Wednesday, December 21, 2005

A while back, I surveyed POSIX.1, Cygwin, MacOS X, and Win32 APIs, with the idea of determining how well the POSIX API was supported by each platform (clearly, POSIX itself supported POSIX very nicely :-). To this survey, I added an enumeration of equivalent NSPR 4.3 functionality. NSPR 4.3, in some cases, added APIs that provided functionality that already existed on all of the above platforms. This was primarily because at the time NSPR came into being, Macintosh was still pre-MacOS X, and if there ever was a platform that was not POSIX, it was MacOS prior to darwin and the release of MacOS X. An example of the utter defiance shown by Apple to the Unix way was its networking API. MacTCP, as it was called, was about as far away as one could get from a BSD sockets-like interface (without leaving the solar system, that is). To cite one example, the typical way to send data over a TCP connection required one to fill out a ParmBlk (a struct, essentially) in order to describe the parameters of the send (including a pointer to the data), and then call a function name PBControlAsync() to make the send happen:

typedef struct TCPSendPB {
byte ulpTimeoutValue; /* upper-layer protocol
timeout */
byte ulpTimeoutAction; /* upper-layer protocol
timeout action */
byte validityFlags; /* validity flags for
options */
Boolean pushFlag; /* true if data should be sent
immediately */
Boolean urgentFlag; /* identifies the data as
important */
Ptr wdsPtr; /* pointer to write data
structure */
unsigned long sendFree;
unsigned short sendLength;
Ptr userDataPtr;

TCPSendPB pb;
struct TCPSendPB *sendpb = &pb.csParam.send;
pb.csCode = TCPSend;/* send TCP data */
sendpb->ulpTimeoutValue = (int) ttmo_write;
sendpb->ulpTimeoutAction = 0;
sendpb->validityFlags = timeoutValue|timeoutAction;
sendpb->pushFlag = T; /* send the data now */
sendpb->urgentFlag = NIL; /* non-urgent data */
sendpb->wdsPtr = (Ptr) &wds;
sendpb->userDataPtr = NIL;
PBControlAsync ((ParmBlkPtr) &pb);

Try porting that to Linux! TCP opens, reads, and writes all followed about the same pattern. As, for that matter, did many of the other APIs implemented throughout MacOS toolbox. To port BSD or POSIX sockets-based code to classic Mac, one had to wrap MacTCP, or just give up. I did exactly that when I worked on a port of Apple's X server application (named MacX, not to be confused with MacOS X). No, I didn't give up, but I did write an abstraction layer. The MIT X11 Server code used BSD sockets; it was much better to adhere to its requirements than it would have been to modify the core X11 sources.

But I am starting to digress. Another good reason for coding to NSPR over any other API was that as NSPR embraces further platforms (which was a distinct possibility since Mozilla was based on it), you pick up support on that platform for free.

The following is a link to the document that I produced which surveys the aforementioned APIs: POSIX.1 API Support. Looking at it, you should come away with an appreciation of just how big POSIX.1 is, and how well it is covered by the platforms we concern ourselves with in this book.