Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Network socket programming using the NetLib library

0.00/5 (No votes)
28 Aug 2013 1  
The Palm OS operating system provides a library called the NetLib, allowing easy access to netowrk sockets. The library makes developing network-enabled applications for Palm OS very similar to writing such programs for Unix based systems (and equally easy).

This article is written by Dariusz Paduch, and was originally published in the June 2005 issue of the Software Developer's Journal magazine. You can find more articles at the SDJ website.

Figure 1. Progress Manager at work

Introduction

In the following article, I will demonstrate how to write an application for Palm OS, which makes use of network sockets provided by the system library NetLib. Using the methods described here, one can create an application functionally similar to Linux wget, downloading a file of choice from the internet using the HTTP protocol. I will assume that the reader is familiar with the basics of programming for the Palm OS platform.

Socket programming under Palm OS hardly differs from programming it under Unix-like systems. Therefore, everyone who has done this before under Unix should have no problems whatsoever applying their solution in the Palm OS case.

Initializing NetLib

In order to avail oneself of the benefits provided by a system library, one has to first determine its reference number. It is required in order to use any function belonging to that particular library. One should be careful here not to lose the reference number going from function to function, as that would make it impossible for the program to use any function belonging to that library. We obtain the reference number by calling SysLibFind(), providing a pointer to our variable (AppNetRefnum) as its parameter. Of course, the library we are looking for must be present in the system, and has to have already been loaded; while there should be no problems with this in the case of NetLib, it is wise to protect oneself against the errors returned by SysLibFind().

Having already obtained the reference number of our library, we can open and initialize it with the NetLibOpen() function; of course, we have to pass the reference number as one of its arguments. The function will try to bring up all network interfaces that have already been configured, so if there are none available, it will return an error. If NetLib has already been opened, the error returned by the function will be netErrAlreadyOpen – which can be safely ignored, as it merely informs us that opening the library was not necessary. This is worth remembering in order not to abort the whole operation due to this error.

One other thing one should do before beginning to play with sockets is testing the network connections. For this, one should use the NetLibConnectionRefresh() function, which checks and optionally opens (if we pass true as its second argument) all connections.

Once we are done with all the required operations on the socket, we should clean the system up by closing NetLib with the NetLibClose() function; this will protect the program from errors like netErrAlreadyOpen, later on.

Addressing

The addresses of a socket under Palm OS is stored in an appropriate structure, just like under Unix. Since in our case we use the addresses of Internet sockets, we can use the NetSocketAddrINType structure, in which we store three values. The address family determines the syntax of an address. We will be connecting to the Internet, so will be using IP addresses (we write netSocketAddrINET as this value). What remains are the number of the port and the IP address of the remote host. If the user provides a host name instead of an IP address, it will have to be resolved; fortunately the NetLibGetHostByName() can help us with this. In order to use it, we will need another structure that will store the host information – NetHostInfoBufType. The NetLibGetHostByName() function's arguments will then be the string containing the name of the host and a pointer to the output structure. After the function has been executed, NetHostInfoBufType contains an array called address, in which all IP addresses of the host in question are stored. The size of the address array depends on the netDNSMaxAddresses constant, so it can contain more than one IP address. We, on the other hand, are only interested in one, so we will just refer to the value stored under address[0]. Having thus obtained the host's IP address, we can write it into the aforementioned NetSocketAddrINType address structure.

We will then make use of this structure in order to attach our socket to a remote host.

Listing 1. Initialization of the NetLib library

Err err, errcode;
UInt8 allup;
UInt16 AppNetRefnum = 0;

// Look for a system library
err = SysLibFind("Net.lib", &AppNetRefnum);
if (err || !AppNetRefnum) return err;

// Open NetLib
NetLibOpen(AppNetRefnum, &errcode);
if (errcode && errcode != netErrAlreadyOpen)
return errcode;

// Refresh network connections
NetLibConnectionRefresh(AppNetRefnum,
true, &allup, &errcode);
if (errcode) {
 NetLibClose(AppNetRefnum, true);
 return errcode;
}
(...)
NetLibClose(AppNetRefnum, true);

Sockets

The time has come to actually open a network socket. In order to do this, we will need some information. To begin with, we need the domain – the value that we passed to the NetSocketAddrINType as the address family (netSocketAddrINET). Next, we will define the type of the socket, i.e., whether the connection is to use datagrams or streams; in our case, we have to specify netSocketTypeStream. We shall also have to choose an appropriate protocol, depending on the type of the socket; for a streaming socket, the right protocol will be TCP (netSocketProtoIPTCP). We are going to pass all this information as arguments to the NetLibSocketOpen() function, which in turn returns a socket descriptor that we are going to store in a NetSocketRef-type variable. We will be using this descriptor of an open socket in all the operations on this socket.

We have already got an open network socket and an address structure, so it is high time to establish a connection to the remote host (unless one uses datagram sockets, in which case, no connections have to be established, and we just provide the address data of an appropriate host in all send or receive operations on the socket). To connect a socket to the remote host, we use the NetLibSocketConnect() function, taking as parameters the socket descriptor and a pointer to the address structure. Now we can finally communicate with the remote host using the socket descriptor.

Having finished our communication, we close the network socket by calling the NetLibSocketClose() function.

Communicating with the remote host

After the connection has been established, the actual conversation with the server is just a question of sending queries and receiving replies. There are two functions we use in sending and receiving data – NetLibSend() and NetLibReceive(). The arguments they both take are the socket descriptor we have obtained earlier, a character string as a buffer of data to be sent or for data to be received, and a value defining the length of the buffer. Both functions return the number of bytes which have been transmitted – a very useful feature for verifying the accuracy of the communication. When a function returns zero, it implies that the server has closed the socket, meaning that all the data has been sent.

In the case of datagram sockets, we also have to provide a pointer to the address structure, along with its size.

At this point of our application, it is time to start considering the way, i.e., the protocol, of communication with the server. We have to know what to send to the server and what answers are to be expected. In the case of wget, the protocol used is HTTP, hence we too will be sending and receiving HTTP headers. The responses of an HTTP server consist of the header and the data. The header can tell us what the name and the size of the transmitted file is, giving us information about how many bytes we should write to a file and under what name. The headers can also contain appropriate error messages, which should be taken into account in the error-handling function of our application.

Listing 2. Addressing and communication with a remote host

char host[] = "www.palmtop.pl";
char buffer[40]; // A buffer for sent/received data
int bytes = 1;
NetSocketRef sock;
NetSocketAddrINType addr;
NetHostInfoBufType hostinfo;

NetLibGetHostByName(
AppNetRefnum, host, &hostinfo, -1, &errcode);

if (errcode) return errcode;
addr.family = netSocketAddrINET;
addr.port = 80;
addr.addr = hostinfo.address[0];

// Open a network socket
sock = NetLibSocketOpen(
AppNetRefnum, netSocketAddrINET, netSocketTypeStream,
netSocketProtoIPTCP, -1, &errcode);

// Connect the socket to the specifi ed host and port
NetLibSocketConnect(AppNetRefnum, sock, &addr,
sizeof(addr), -1, &errcode);
if (errcode) {
  NetLibSocketClose (AppNetRefnum, sock, -1, &err);
  return errcode;
}

// Transmit the contents of the buffer through
// the socket to the host
NetLibSend(AppNetRefnum, sock, buffer,
StrLen(buffer), 0, 0, 0, -1, &errcode);

// Retrieve data from the socket to the buffer
while(bytes > 0)
bytes = NetLibReceive(AppNetRefnum, sock,
buffer, 40, 0, 0, 0, -1, &errcode);

// Close the network socket
NetLibSocketClose(AppNetRefnum, sock, -1, &errcode)

Communication with the user

While the data transmission is taking place, it would not hurt to keep the user informed about the progress of the data flow. For this purpose, the creators of Palm OS have created a special interface called Progress Manager.

Using Progress Manager, we can display and control the contents of a progress window. What is to be displayed in this window is controlled by a programmer-defined function called PrgCallbackFunc. A number of different progress states can be declared, e.g., Connecting, Retrieving, or Disconnecting. Just before connecting to the remote host, we open the progress window, calling the PrgStartDialog function, and giving it the title of the window and a pointer to the callback function; all further operations on the window's contents are to be performed with the PrgUpdateDialog function. This function makes it possible to switch between different progress states, provide the callback function with additional text output, or display an error message. Another thing worth mentioning here is the PrgUserCancel macro, which checks whether the user has not cancelled the operation while it was in progress.

What next?

Much remains to be improved in our program, providing great opportunities to a programmer. First of all, one should remember to enhance error checking. Each of the functions possesses a plethora of errors that they can return, some of which should be taken into account when displaying messages. A detailed description of all of them can be found in the Palm OS API documentation. Furthermore, most functions operating on sockets possess the time-out attribute, which is worth having a look at and adjusting appropriately to our needs in order to save the user from having to wait for the server's response forever.

On the 'Net

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here