# 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
>     #HTTP socket capable of single-stack IPV6 and IPV6-mapped IPV4
>     tcp-socket-listen --backlog 2 --combine4and6 "::0" http
>     envuidgid publicfile
>     hardlimit -o 20 -d 500000
>     softlimit -o hard -d hard
>     tcp-socket-accept --connection-limit 16
>     ucspi-socket-rules-check
>     ./service

>     #!/bin/nosh
>     #HTTP service over IPv4/IPv6 using Bernstein's publicfile
>     sh -c 'exec httpd ~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:

- `nosh` chain loads tcp-socket-listen.

- `tcp-socket-listen` opens a TCP socket, binds it to a wildcard IP address and the well-known TCP port for HTTP, and then chain loads envuidgid.

- `envuidgid` reads the system's account database for the user "publicfile", sets up some environment variables for later use, and chain loads softlimit.

- `softlimit` adjusts some kernel resource limits for the current process, and chain loads hardlimit.

- `hardlimit` adjusts some kernel resource limits for the current process, and chain loads tcp-socket-accept.

- `tcp-socket-accept` sits waiting for TCP connections on the listening socket that was opened for it, forking a new process for each accepted connection and chain loading to ucspi-socket-rules-check in that process.

- `ucspi-socket-rules-check` checks a local database, in the service directory, for access controls on the connecting client IP address, and if the client is permitted access chains to the `service` program.

In the `service` program:

- nosh chain loads the service program proper, which is Bernstein's publicfile.

- publicfile picks up the environment variables earlier set by envuidgid, changes to the data root directory, drops superuser privileges, and serves HTTP requests over the TCP connection.

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.

Some `run` programs pass tcp-socket-listen the `--systemd-compatibility` option, if the program that accepts the socket connections require systemd's LISTEN_FDS protocol for knowing which open file descriptor is the listening TCP socket. This protocol also permits one to build up a list of listening sockets, for the final accepting service program to use, by simple dint of chaining multiple programs such as tcp-socket-listen, udp-socket-listen, and local-stream-socket-listen one after another.

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.