http://www.developer.com/ws/palm/article.php/3393391/Palm-OS-Communications-Primer-Net-Library.htm
The previous article told about Serial Manager. Now, we'll discuss how to develop network applications in a Palm OS environment. Obviously, we won't cover all available API calls, but will try to highlight the most common flow. The Network Library can be naturally divided into two parts: the API itself and the protocol stack. This is a standard division for such kind of arcitectures. Your application as a client invokes API methods to get desired functionality. API translates all this calls into correspondend requests. These requests are then placed into some intermediate part—mailbox queue—and protocol stack layer reads requests from this queue and interacts with network. All responses are put back to mailbox queue, and finally and API returns answers back to client applications. Thats's the principal working flow of Palm OS Network Library. If you want to map this schema against the OSI network model, we may state that the protocol stack provides transport, network, and data link services. TCP and UDP are transport-layer protocols, IP is a network-layer protocol, and PPP and SLIP are data link-layer protocols. Your program is responsible for providing the application, presentation, and session services of the OSI model. Thus the Net Library API plays a similar role as Berkeley sockets or the Winsock API. If you have some experience in Unix network programming, here is the good news. As a matter of fact, you may develop your network application under a Unix environment and then (with a bit of glue here and there, of course) compile it for Palm OS. Changes will be really minor. Net Lib is a system library, so it's usually preloaded at your application's runtime. Nevetheless, the standard and correct manner is first to find "Net.lib" and to load this library if necessary:
During above calls you're getting libRefnum—the reference number of the library. You will use it for all future calls to the rest of the network API. Please notice that when you receive netErrAlreadyOpen as an error, it means just that Net Lib is open. In this case, libRefnum is simply incremented. Default values of interfaces to attach, IP addresses, and so forth are taken from the preference panel settings unless you want to open specific configuration by calling the following: When Net Library is no longer needed, you should release it: The last parameter of this function (UInt16 immediate) controls the shutdown algorithm. If libRefnum is greater than 1, the function decreases the reference counter and returns netErrStillOpen. Otherwise, it behaves as follows: This brilliant solution significally increases performance because it allows you to launch another network application within a short period of time without any reinitialization. Before all the story, let's just declare that basically all network applications may be classified either as servers or clients. You certainly may develop some program that will combine both of them simultaniously. But, in most cases, with a Palm device you will need to create clients rather than servers. There are well-known schemas for each type of application. You can find then in any book. Here we place them for reference only: Below we will consider some aspects of each application type. In the case of Palm OS, you must call the NetLibSocketOpen function to create the socket: Because it's written in SDK's help, Net Library supports INET or Raw address domains. You may specify either TCP/IP, UDP, or Raw socket types. For simplicity, we will not discuss Raw sockets, just couple of comments; this is long story by itself. Well, here are a few words about raw sockets anyway. Since Palm OS 3.0, the following types are supported: Thus, the main headaches are on you. If we've succeeded to open a socket of the desired type, we have several opportunities. Your can get or set a lot of socket options by calling NetLibSocketOptionSet; for example, linger behavior, OOB data processing, blocking mode, and so forth. The next snippet demonstrates how to cancel the blocking mode:
As you can see, in the meantime all the stuff is pretty similar to UNIX or Windows. Once a socket is opened and configured, you either can establish a connection to the remote host and/or send/receive data or setup the socket to listen to incoming connections. First, let's take a look at the client code. Depending on the socket type, the work flow will be a bit different. Stream sockets in fact require establishing a connection before any transmission operations. In case of UDP, you can provide the host address as one of parameters. If the UDP socket was previously connected, you'll get an error if you specify a host address. Hence, you may change the next code snippet according to your needs or skip it in case of UDP or Raw sockets: If you develop a server application, a set of calls will be like the following sample: To retrieve the host address, you may use NetLibGetHostByName and analogous functions. Let's say several words about sending/receiving. There is a rich family of such functions: As noted above, for each socket type you will or will not specify a host IP address, timeout period, and data buffer. Please pay attention that the stream socket allows sending a single buffer that the caller provides. For UDP sockets, you have to send a single packet at a time (1536 bytes). Otherwise, no data is sent at all. Raw sockets (supported in Palm OS version 3.0 and higher) must construct the entire IP header, including the destination address, before data can be sent; thus, the address is taken from the data to be sent. In the sample project, you will find some simple examples of different calls. NetLibDmReceive is a Palm OS-specific function that has no equivalent in a standard network API. It receives data from a socket directly into a database record. You only provide the record's start address and offset. In all other aspects, it behaves similarly to a NetLibReceive call. Net Library contains a NetLibMaster function, which provides the network statistics, interface statistics, and the contents of the trace buffer. The last feature is quite useful for debugging purposes. NetLibMaster, together with NetLibTracePrintF and NetLibTracePutS, gives you a powerful mechanism to debug either your application or network configuration issues. To get an access to the tracing capability, you can call either NetLibSettingSet for the Net Library in general or NetLibIFSettingSet for specific a network interface, passing netSettingTraceBits as target setting. The netTracingAppMsgs bit should be raised to get the above functions doing something. The default value is (netTracingErrors | netTracingAppMsgs), but if you don't see any output, take care about setting everything properly. The next code snippet illustrates all this dry theory: You may download the sample project here. Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.
Palm OS Communications Primer: Net Library
August 11, 2004
Net Library Architecture: Distant Glance
Stepping Into the Library
// Find the network library
UInt16 libRefnum = 0;
Err error = errNone;
error = SysLibFind("Net.lib", &libRefnum);
if (error)
{
// Handle it
return;
}
// Open the network library
UInt16 netIFErrs = 0;
error = NetLibOpen(libRefnum, &netIFErrs);
if (netIFErrs || (error && error != netErrAlreadyOpen))
{
// Errors during opening Net Lib or bringing up the
// network interface
// Handle it somehow
}
Err NetLibOpenConfig (UInt16 refNum,UInt16 configIndex,
UInt32 openFlags, UInt16 *netIFErrP);
error = NetLibClose(libRefnum, false);
Typical Scenarios
Client:
Server:
The accept function creates a new socket. The original socket opened by the server continues to listen and can be used to accept more connections until closed. Server applications must close the listening socket, in addition to any sockets created, by accepting a client connection
An application should call NetLibSocketShutdown before calling NetLibSocketCloseCreation and Setup
// Open a socket
UInt16 libRefnum = 0;
Err error = errNone;
...
NetSocketRef socket =
NetLibSocketOpen(libRefnum, // Network library
netSocketAddrINET, // Address domain
netSocketTypeStream, // Socket type
netSocketProtoIPTCP, // Protocol
-1, // Timeout
&error // Error result
);
if (error)
{
// Handle it somehow
}
For applications that use raw sockets in the INET domain, the net library checks the destination IP address of all incoming packets to see if it matches any of those raw sockets. If it does, the packet is enqueued directly into the matching socket and is not passed to the protocol stack.
When an application sends data through raw sockets in the IP domain, the net library packages the data into a packet and passes it directly to the interface's send routine. You are responsible for forming the entire IP header, including any necessary checksums, source and destination IP address, and so on.
When an interface is bound to a raw socket with no protocol, the net library places that interface into raw mode. In raw mode, the interface passes all incoming packets, no matter what the link layer protocol, to its raw receive function.
When an application sends data through a raw socket with no protocol, the net library packages the data into a packet and passes it directly to the interface's send routine.
The interface remains in raw mode until the raw socket is closed
UInt8 bNonBlocking = 1;
Int16 nRes =
NetLibSocketOptionSet(libRefnum, socket,
netSocketOptLevelSocket,
netSocketOptSockNonBlocking,
&bNonBlocking,sizeof(bNonBlocking),
-1, &err);
Establishing a Connection
NetIPAddr addr = NetLibAddrAToIN(libRefnum, textIP);
// Connect the socket to its destination
NetSocketAddrINType destAddr;
MemSet(&destAddr, sizeof(destAddr), 0);
destAddr.family = netSocketAddrINET; // This should match the
// second argument to
// NetLibSocketOpen
destAddr.port = 8080;
destAddr.addr = addr;
Err error = 0;
result =
NetLibSocketConnect(libRefnum, // Network
// library
socket, // Socket
// reference
(NetSocketAddrType*)&destAddr, // Destination
// address
sizeof(destAddr), // Length of
// destAddr
-1, // Timeout
&error // Error result
);
if (result == -1)
{
// handle error
goto CloseSocket;
}
Err SetupServerSocket(NetSocketRef socket)
{
Err error;
NetSocketAddrINType addr;
addr.family = netSocketAddrINET;
addr.port = NetHToNS(8080);
addr.addr = NetHToNL(0);
if (NetLibSocketBind(libRefnum, socket, &addr, sizeof(addr), -1,
&error) != -1)
error = errNone;
if (NetLibSocketListen(libRefnum, socket, 5, -1, &error) != -1)
error = errNone;
return error;
}
Transmitting the Data
Int16 NetLibSendPB(UInt16 libRefNum, NetSocketRef socket,
NetIOParamType *pbP, UInt16 flags,
Int32 timeout, Err *errP);
Int16 NetLibSend(UInt16 libRefNum, NetSocketRef socket,
void *bufP, UInt16 bufLen, UInt16 flags,
void *toAddrP, UInt16 toLen,
Int32 timeout, Err *errP);
Int16 NetLibReceivePB(UInt16 libRefNum, NetSocketRef socket,
NetIOParamType *pbP, UInt16 flags,
Int32 timeout, Err *errP);
Int16 NetLibReceive(UInt16 libRefNum, NetSocketRef socket,
void *bufP, UInt16 bufLen, UInt16 flags,
void *fromAddrP, UInt16 *fromLenP,
Int32 timeout, Err *errP);
Int16 NetLibDmReceive(UInt16 libRefNum, NetSocketRef socket,
void *recordP, UInt32 recordOffset,
UInt16 rcvLen, UInt16 flags,
void *fromAddrP, UInt16 *fromLenP,
Int32 timeout, Err *errP);
Debugging Network Applications
///////////////////////////////////////////////////////////////////
// Enable tracing
///////////////////////////////////////////////////////////////////
void SetupTracing()
{
Err err;
DWord value;
Word settingSize;
Word index;
Byte traceRoll;
value = 0x0800;
settingSize = sizeof(value);
err = NetLibSettingSet(libRefnum, netSettingTraceSize, &value,
settingSize);
if (err)
{
// Handle error
return;
}
// Set tracing bits
value = netTracingErrors | netTracingMsgs | netTracingAppMsgs;
// Set trace level for stack
NetLibSettingSet(libRefnum, netSettingTraceBits, &value,
settingSize);
// Set rollover to none
traceRoll = false;
NetLibSettingSet(libRefnum, netSettingTraceRoll, &traceRoll,
sizeof(traceRoll));
// Set trace bits also for all attached interfaces
for (index = 0; 1; index++)
{
DWord ifCreator;
Word ifInstance;
err = NetLibIFGet(libRefnum, index, &ifCreator, &ifInstance);
if (err)
{
err = 0;
break;
}
NetLibIFSettingSet(libRefnum, ifCreator, ifInstance,
netIFSettingTraceBits, &value, settingSize);
}
}
...
///////////////////////////////////////////////////////////////////
// Do actual traces
///////////////////////////////////////////////////////////////////
NetLibTracePrintF(libRefNum, "Error occured is %x\n", error);
...
///////////////////////////////////////////////////////////////////
// Extract tracing data
///////////////////////////////////////////////////////////////////
void ShowTracing()
{
NetMasterPBType pb;
Err err;
Char text[100];
DWord oldTrace;
Int i;
DWord value;
Word settingSize;
Boolean setTraceBits = false;
Word index;
Byte traceRoll;
CharPtr cmdP;
// Temporarily disable tracing
settingSize = sizeof(oldTrace);
NetLibSettingGet(libRefnum, netSettingTraceBits, &oldTrace,
&settingSize);
value = 0;
err = NetLibSettingSet(libRefnum, netSettingTraceBits, &value,
settingSize);
if (oldTrace == 0)
StdPutS("Tracing not on\n");
else {
StdPutS("From oldest to newest...");
StdPutS("\nTICKS EVENT ROUTINE\n");
}
// See what the oldest entry is
for (i=0; 1; i++) {
pb.param.traceEventGet.index = i;
pb.param.traceEventGet.textP = text;
err = NetLibMaster(libRefnum, netMasterTraceEventGet, &pb,
AppNetTimeout);
if (err) {
printf("Error: %s\n", appErrString(err));
break;
}
}
// Print them in oldest to newest order
for (i=i-1; i>=0 ; i--)
{
pb.param.traceEventGet.index = i;
pb.param.traceEventGet.textP = text;
err = NetLibMaster(libRefnum, netMasterTraceEventGet, &pb,
AppNetTimeout);
if (err) break;
// User 'text' buffer as you want to
...
}
// Restore tracing level
err = NetLibSettingSet(libRefnum, netSettingTraceBits, &oldTrace,
settingSize);
}
Download
About the Author