Anatomy of a typical TCP service

The http6d service in the regular services collection is an example of a typical and commonly used TCP service. Its start, stop, and restart programs are fairly trivial and straightforward. The meat of the service is its run and service programs.

The service could be arranged as a single run program. However, that does not permit adjustment of the service program, including its command-line arguments, whilst the service is up. Having a separate service program, that is chained to for each new TCP connection, permits an administrator to adjust the main service program without taking the service down. Of course, this has to be done carefully, because a live service could run the service program at any time, including halfway through when a text editor is updating the script. So always edit a "service.new" script and then, after setting execute permission, atomically rename it to service.

The run and service programs are as follows:

#!/bin/nosh
#Run file generated from build/http6d.socket
tcp-socket-listen --systemd-compatibility --backlog 2 0 80
softlimit -o 20 -d 50000
envuidgid publicfile
tcp-socket-accept --connection-limit 16 --no-delay 
ucspi-socket-rules-check
./service
#!/bin/nosh
#Service file generated from build/http6d@.service
#HTTP service over IP4/IP6 using Bernstein's publicfile
httpd /home/publicfile/public

Like many of the pre-packaged services, these scripts are in fact automatically generated from a description file that is in the source package. (In fact, that description is a slight variant on a systemd unit file.) Both invoke nosh as their script interpreter, and comprise a series of utility commands, each chain-loading to the next, passing along what program arguments it has not itself absorbed.

In the run program:

In the service program:

The amount of setup in the run and service scripts depends from what the service program itself does, of course. If publicfile did not change working directory and root directory, for example, one could do so with the chain-loading chdir and chroot commands.

Because the service's run program was generated from a systemd unit file, the run program passes tcp-socket-listen the --systemd-compatibility option. This isn't strictly necessary here, since the program that accepts the socket connections doesn't require systemd's LISTEN_FDS protocol for knowing which open file descriptor is the listening TCP socket. Were it a systemd-specific program, however, it would need this; and the option does no harm to non-systemd-specific server programs.

Looking at the rest of the service bundle, one finds the standard things for a "server" service. The service is auto-started (when enabled) by the "server" system target. It is stopped by the "shutdown" system target. It requires for correct operation that all services in the "basic" system target be started, before it itself is started. Its output is sent to a logger service.