Does this site look plain?

This site uses advanced css techniques

A customer in the labor time-keeping business had a series of timeclock products that were installed on factory floors to allow the workers to clock in and out, and to change jobs they were working on.

The Serial-port Server

The first versions of these clocks were connected via serial lines, and in 1992 I was contracted to write the UNIX server software that would communicate with all of them. A configuration file gave the device names of all the remote clocks, plus some key parameters, and it would poll them in turn periodically. When any clock had data, it would be saved into a logfile that was later passed on to other software for processing.

This software was in production for many years, and was eventually ported to several other variants of UNIX. Though my software implemented the serial protocol, I did not design it.

The Network Version

In 1995, my customer migrated to network-based timekeeping, and the clocks they used ran MS-DOS and used a third-party TCP/IP stack. These units had a much richer feature set than the previous RS232-based clocks, and I was contracted to develop the protocol, the libraries that talked to the network, and the server component.

At the time, this third-party stack was expensive - several hundred dollars per copy - and we seriously considered implementing our own stack to save these substantial costs. Doing a full TCP/IP stack from scratch is no small project, but since we designed our protocol to use UDP only, the elimination of TCP would have eliminated an enormous amount of complexity. Ultimately we never did write our own stack, but the UDP-based implementation remained nevertheless.

Packet Structure
The packet layout itself was highly encapsulated reflecting the multiple layers of software that would manipulate them. The "wire header" - the very start of the packet - included the size of the payload and a packet type. The packet type encodes the protocol layer, whether this is a request or a response, and a bit of debugging information. [Packet Structure]
"Application" packets are simply passed up from the library to the client or server for application-specific processing, and the library does nothing with them save for validating the checksum and silently dropping duplicate responses.
"Transport" packets are used for library-to-library communications, and this includes server discovery, file transfer, and other debugging/management commands. The application layer itself won't ever see these packets as they are processed entirely inside the library.
File Transfer
In addition to sending application data back and forth, the protocol permits transferring of files from end to end. These packets have the traditional "wire header", plus a "file request" header. This provides the operation being requested:
  • Open file for reading
  • Open file for writing
  • Read/ACK a block
  • Write/ACK a block
  • Close the file
The library handled the entire transaction asynchronously, and the application could either wait for completion, or continue processing until the transfer-complete callback was invoked.
Server and Client Discovery
The client terminals all used DHCP to acquire their own IP addresses, but they do not know where the protocol servers are found. All participants supported automated client and server discovery, where local broadcasts would announce to the network that a client or server was on the network, and multiple servers of varying ranks (primary, secondary, etc.) were supported.

The Network Servers

I implemented the network-based server on both Windows NT and UNIX, and a great deal of the code was common to both. In particular, the low-level networking libraries were shared by UNIX, NT and by the MS-DOS timeclock terminals.

The servers were ported to multiple UNIX systems, and remained in production for many years. The packet structure I designed initially required no changes over the life of the product.