multiserve(3)          FreeBSD Library Functions Manual          multiserve(3)

NAME
     multiserve - Local socket server library for use with multifile(1)

SYNOPSIS
     #include <multiserve.h>
     -I/usr/local/include -L/usr/local/lib -lmultiserve

DESCRIPTION
     Multiserve implements a skeletal local socket server for use with
     multifile(1).  The library performs network and concurrency tasks.  You
     supply code to service connections.

     An example echo server is included in the source distribution.

   USAGE
     The library provides your server's "main" function.  You define 6
     functions to match the following prototypes.

     void serv_init_func();
     void serv_exit_func();

     void serv_open_callback( int fd );
     void serv_close_callback( int fd, void *data );

     void serv_read_callback( int fd, int len, char *buffer, void *data );
     void serv_write_callback( int fd, void *data );

     Do not define any other global symbol beginning with the five characters
     'serv_' because the library reserves that namespace.

   SERV_INIT_FUNC()
     In serv_init_func() perform the initialization tasks your server needs to
     do once at server start-up.

     void serv_init_func();

     The library calls serv_init_func():

     o   after changing to the directory specified by the -r command line
         option.

     o   before attempting to change the server's user and group to the values
         specified by the command line options.  If the server starts as root
         serv_init_func() executes as root.

     o   before the server becomes a daemon and starts listening for
         connections.  The standard streams are connected to the terminal from
         which the server was started.  Error and informative messages should
         be sent to the terminal.

   SERV_EXIT_FUNC()
     If you have exit handlers you would like to register to run before the
     server exits, do not invoke atexit() from serv_init_func().  If you do
     so, your handlers are run when the server becomes a daemon.  The server
     forks to create a new session.  The dying parent process will call your
     handlers when it exits.  Instead, call your cleanup code from
     serv_exit_func().

   SERV_SET_NAME()
     Call serv_set_name() inside serv_init_func() to set the server's name.

     void serv_set_name( char *name );

     If not set the server's name defaults to "multiserve".  The server's name
     is used in two ways:

     o   When the server is running, stderr is connected to /dev/null.  Errors
         must be reported with syslog(3).  The library calls openlog() with
         the server's name as argument to ensure that log entries are
         identified by the server's name.

     o   The server's pidfile is written to /var/run/ if the server is started
         as root.  The filename is the server's name with ".pid" appended to
         it.  This file is used by rc.d scripts to stop the server.  A sample
         script is included in the multiserve distribution.

   SERV_OPEN_CALLBACK()
     The library calls serv_open_callback() when a new connection is received.

     void serv_open_callback( int fd );

     The function receives the file descriptor of the socket as argument.  Do
     not read or write the file descriptor directly.  It is meant to be used
     as a unique identifier for active connections if your code needs to store
     such an identifier.

   SERV_SET_DATA()
     Associate connection-specific data with connections with serv_set_data().

     int serv_set_data( int fd, void *data );

     Connection-specific data pointers are passed as the last argument to
     serv_read_callback(), serv_write_callback(), and serv_close_callback().

     The function returns -1 if the file descriptor does not reference a
     connection and 0 otherwise.

   SERV_CLOSE_CALLBACK()
     The library calls serv_close_callback() when a connection is closed.

     void serv_close_callback( int fd, void *data );

     The function's second argument is the socket's connection-specific data.

   SERV_READ_CALLBACK()
     The library calls serv_read_callback() when the parameter string has been
     read from the client.

     void serv_read_callback( int fd, int len, char *buffer, void *data );

     The second argument is the length in bytes of the parameter data supplied
     by the client.  The length is always less than 65535 bytes.  The third
     argument is a character pointer to the data.  The fourth argument is the
     connection-specific data for the connection.

     If the client does not submit a parameter string, the function is invoked
     with len set to 0.  The contents of buffer are undetermined in this case
     and should not be accessed.

     The space pointed to by buffer is freed when the function returns.

     If, when serv_read_callback() returns, no data has been queued for the
     client with serv_write_conn(), the library closes the connection.

   SERV_WRITE_CONN()
     To write to the client, pass a character buffer to serv_write_conn().

     int serv_write_conn( int fd, int len, char *data );

     The function's second argument is the length of the outgoing data in
     bytes.  The third argument is a character pointer to the outgoing data.
     The data is copied into an internal structure by the library.

     serv_write_conn() does not write the data but queues it for delivery.
     When the socket is writeable, the library sends up to one complete queued
     buffer of data to the client, in discrete writes, until the outgoing
     queue is consumed.

     serv_write_conn() returns:

     o   -1 if the file descriptor does not reference a connection.

     o   -2 if the queue could not be enlarged.

     o   0 on success.

     If the function returns -2, the server cannot allocate memory.  There is
     no point continuing to service this connection.  Perform any clean up
     operations necessary, and call serv_close_conn() to drop the connection.

   SERV_WRITE_CALLBACK()
     The library calls serv_write_callback() when a connection's outgoing data
     queue is exhausted.

     void serv_write_callback( int fd, void *data );

     The function's second argument is the socket's connection-specific data.

     If, when serv_write_callback() returns, no new data has been queued for
     the client with serv_write_conn(), the library closes the connection.

   SERV_CLOSE_CONN()
     To close a connection prematurely, invoke serv_close_conn().

     void serv_close_conn( int fd );

   SERV_SET_PERIODIC()
     Install a function to be invoked periodically with:

     void serv_set_periodic( void (*)(), int );

     The library calls the function pointed to by first argument when the
     number of seconds specified by the second argument have elapsed and then
     again repeatedly when that number of seconds has elapsed since the last
     call.

     To timeout idle connections, maintain a timestamp for each connection
     that you update when the client is active and install a periodic function
     to close expired connections with serv_close_conn().

   SIGNALS
     The library needs to catch SIGTERM, so do not change the disposition of
     that signal.

     Upon receipt of SIGBUS or SIGSEGV, multiserve restarts the server with a
     call to execv(3).  If you want to do something else, install your own
     handler.

     If your server starts as root and changes user and group, the library
     will be unable to restart if your server is not executable by the user or
     group.

     The library will be unable to perform the operations that require root
     privileges after restart unless you manually turn on the setuid bit of
     the server (chmod u=+s).

   ACCESS TO CONFIGURATION VARIABLES
     You can examine the following configuration variables from your code, but
     you must not modify them.   See the CONFIGURATION section for more
     information.

     char *serv_config_file;
     char *serv_root_dir;
     char *serv_user;
     char *serv_group;

     serv_config_file  points to the value passed to the -f option.  Defaults
                       to NULL.

     serv_root_dir     points to the value passed to the -r option.  Defaults
                       to NULL.

     serv_user         points to the value passed as argument to the -u
                       option.  Defaults to "nobody".

     serv_group        points to the value passed as argument to the -g
                       option.  Defaults to "nobody".

   CONFIGURATION
     If is started as root, multiserve writes its pidfile into /var/run/.
     Stop multiserve with a SIGTERM.

     A sample control script, multiserve.rcfile, is provided in the multiserve
     distribution.  To use the script, replace all occurrences of "multiserve"
     with the value you pass to serv_set_name().  Rename the script to the
     same value.  Install the script in /usr/local/etc/rc.d.

     Add the following 2 variables to /etc/rc.conf.  Substitute your server's
     name for "multiserve":

     multiserve_enable="YES"
     multiserve_flags="-u www -g www -r /usr/local/multiserve"

     If "enable" is set to "YES", the server is started at system start.  Use
     the following control commands.

     /usr/local/etc/rc.d/multiserve start
     /usr/local/etc/rc.d/multiserve stop
     /usr/local/etc/rc.d/multiserve restart
     /usr/local/etc/rc.d/multiserve status

     If you do not want the server started on system start, then set

     multiserve_enable="NO"

     Use the following control commands.

     /usr/local/etc/rc.d/multiserve forcestart
     /usr/local/etc/rc.d/multiserve forcestop
     /usr/local/etc/rc.d/multiserve forcerestart
     /usr/local/etc/rc.d/multiserve forcestatus

   COMMAND-LINE OPTIONS
     The following command line options are recognized by multiserve servers.
     All of these are optional.

     -r  User the -r option to specify the server root directory.  Multiserve
         chdir(2)s there.

     -l  By default, the library listens on /var/run/multiserve.socket.  The
         -l option instructs the library to listen on a different path
         instead.  To be accessed by mulitfile, this path must lie within the
         hierarchy rooted at multifiles's root directory.

         The server creates the socket when it starts, unlinking it first if
         it already exists in the filesystem.  The owner and group of the
         socket are changed to the values of the -u and -g options.  The
         permisssions of the socket are set to srwxrwx---.  To be accessed by
         multifile, the socket's -u or -g must match that of multifile.

     -m  By default, multiserve maintains no more than 1024 simultaneous
         connections.  The -m option specifies a different amount.

     -u

     -g  The -u and the -g options are used to specify the user and group for
         the server.  Both values default to "nobody".  For multiserve to
         change user, it must be started as root.  For use with multifile, the
         -u and -g options should be identical to multifile's.

         Multiserve restarts servers on receipt of SIGSEGV or SIGBUS.

         If your server starts as root and changes user and group, the library
         will be unable to restart if your server is not executable by the
         user or group.

         The library will be unable to perform the operations that require
         root privileges after restart unless you manually turn on the setuid
         bit of the server (chmod +s).

     -x  The -x option prevents multiserve from becoming a daemon and writing
         its pidfile to /var/run/.  Multiserve runs in the foreground.  Stderr
         is connected to the terminal so that diagnostic output can be sent
         there.

     -f  The -f option takes a filename as argument.  Multiserve assigns the
         filename to the global character pointer serv_config_file.  This
         enables code in serv_init_func() to access a configuration file.

AUTHORS
     James Bailie <jimmy@mammothcheese.ca>
     http://www.mammothcheese.ca

                               Sat Jul 06, 2019