Shared connection state
-----------------------
Richard Jones, 27th December 2001.

1. Problem
----------

Up until now (version 1.103) the architecture of the FTP server has
been very simple: there is a parent process listening for connections.
When a connection comes in, a process is forked off to handle the
connection. Between connections there is no shared state: each
connection knows nothing of any other connections in progress.

Advanced features in the FTP server require some state to be shared
between connections. Examples are:

1.1 The proposed SITE WHO command
---------------------------------

This proposed command would allow an administrator to list out
all users currently using the FTP server. Clearly the child process
handling the administrator's connection must therefore know something
about all of the other child processes.

1.2 The proposed `max clients' directive
----------------------------------------

To specify the maximum number of clients in a class or for a
particular user, it is suggested that we extend `max clients'
like so:

max clients: 10 class anonymous	  # only 10 anonymous clients allowed
max clients: 1 each class users   # each person in "users" can log in
				  # only once (no limit on max users, however)
max clients: 2 user pete,rich     # pete and rich can only log in twice

Notice that you don't know what class a user is (or what their
username is) until well into the connection.

Thus to implement this, each child process must again know a lot of
information about the state of each other child process. This again
implies shared state.

1.3 Upload and download quotas and credits
------------------------------------------

At this point in time, it is not clear exactly what the best way to
implement quotas and credits will be. However, it is clear that a
user must not be able to bypass a quota by opening more than one
connection to the server at the same time. In order to achieve this,
each child process must know what each other child process is doing.

2. Solution
-----------

There are several possible ways to share information between the
child processes. They include:

. shared file(s)
. shared memory (SysV SHM)
. shared anonymous memory-mapped files (mmap)

Of these, the most robust method and the one which is available on
all platforms, seems to be shared files using POSIX fcntl-style locking.

For the different types of shared state, different approaches
are suitable. All will use shared file(s) of some sort, but not
all will require explicit locking.

All shared files should be stored on local disk to avoid problems
with consistency, speed and locking over NFS. A suitable place to
store files would be in /var/lock/ftpd/

2.1 Connection state
--------------------

Each child process should create a file called /var/lock/ftpd/conns/$$
(where $$ is the process ID). This text file will contain information
about the connection (and may be rewritten several times over the
course of a single connection). When the connection is dropped, this
file *must* be deleted.

Other child processes may immediately find out the global connection
state by opening and examining each file in the /var/lock/ftpd/conns/
directory.

To ensure (a) that files cannot be read partially by other children
and (b) that files may still be written to even after a child
process has dropped privileges and chrooted, each child will keep
a file descriptor open on the file and only append to it using
atomic write(2).

The contents of this file is a list of zero or more of the following
`key: value's:

peeraddrstring: 1.2.3.4			# Client's IP address.
peerhostname: foo.bar.example.com	# Client's hostname, if resolved.
user: rich				# Username, if authenticated.
class: users				# User's class.
uploaded: 50000				# Number of bytes (???) uploaded.
downloaded: 2000000			# Number of bytes (???) downloaded.

If the same key occurs twice, then the latter key is taken (allowing
the append-only semantics to work).

Other keys will be added here as they are required.

2.2 Upload and download credits and quotas
------------------------------------------
