libserverevents(8)      FreeBSD System Manager's Manual     libserverevents(8)

NAME
     libserverevents - Generic Event-Driven Server Library

SYNOPSIS
     #include <libserverevents.h>
     -pthread -I/usr/local/include -L/usr/local/lib -lserverevents

DESCRIPTION
     The Libserver package supplies 3 libraries that implement generic
     servers.  The libraries perform network and concurrency tasks.  You
     supply code to service connections.  All 3 libraries service TCP or UNIX-
     domain connections.  Separate libraries implement multi-process, multi-
     threaded, and event-driven servers.  This manual documents the event-
     driven library.  The other two libraries are described in the "libserver"
     manual.

     Example echo servers are included in the libserver 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().

     If you need to invoke worker-specific cleanup code in a multi-process
     server, you can install your cleanup handlers with atexit() inside
     serv_worker_init_func().

     If you need to invoke worker-specific cleanup code in a multi-threaded
     server, you can call your cleanup code from the destructor functions of
     your thread-specific keys.

   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 "server".  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 libserver distribution.

   SERV_SET_CALL_AND_RESPONSE()
     Call-and-response behavior is enabled by default.  If the protocol your
     server implements allows both connection endpoints to write
     simultaneously, call serv_set_call_and_response() in serv_init_func()
     with an argument of zero to turn off call-and-response behavior.

     void serv_set_call_and_response( int on );

     With call-and-response behavior enabled, read events are disabled when
     outgoing data is queued with serv_write_conn().  When the queue is
     exhausted, read events are enabled again.  When call-and-response
     behavior is disabled, read events are enabled at all times.

   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.  If you write a chat server, for example, you use the
     identifiers of other connections to queue outgoing data for them with
     serv_write_conn().

     If the protocol your server implements requires the server to speak
     first, send the initial data with serv_write_conn() in
     serv_open_callback().

   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 data space must be malloc-ed and is freed by the library when the
     connection is closed.  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
     or NULL.  The library frees outgoing queued data and connection-specific
     data when serv_close_callback() returns.

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

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

     The second argument is the length of the data in bytes.  The length is
     never greater than 32768 bytes.  The third argument is a character
     pointer to the data.  The fourth argument is the connection-specific data
     for the socket or NULL.

     The buffer pointed to by the third argument is malloc-ed and must be
     freed before serv_read_callback() returns unless the buffer is passed to
     serv_write_conn().

   SERV_WRITE_CONN()
     To write to the client, passed a malloc-ed 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 space must be malloc-ed and is freed by the library when the
     data has been written.

     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.  Writes are multiplexed with other events.  To ensure
     smooth multiplexing, queue large data in chunks with separate calls to
     serv_write_conn().

     When outgoing data is queued for a connection, read events for that
     connection are disabled until the queue has been exhausted unless
     serv_call_and_response() has been called with a non-zero argument.

     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
     or NULL.

     When writing data from another source to a client, you may not want to
     queue all the outgoing data at once because you do not know the size of
     the data in advance, and you want to limit memory or CPU usage.  Use
     serv_write_callback() to queue new data for a connection after its
     outgoing queue has been consumed.

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

     int serv_close_conn( int fd, int force );

     serv_close_conn() closes a connection immediately if the second "force"
     argument is non-zero.  If "force" is zero, the connection is closed when
     the outgoing queue has been written to the client.  In that situation,
     further incoming data is not read from the client.  The library calls
     serv_close_callback() when the socket is closed.

     If a client closes its connection, the library calls
     serv_close_callback().

   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().

   SERV_INIT_THREAD_POOL()
     Offload tasks that are time-intensive to a pool of threads to avoid
     blocking the main event loop.  The thread pool is established by invoking

     int serv_init_thread_pool( int num_threads, int stack_size, void ( *callback )( int fd, int result ));

     This function returns 0 on success and 1 on failure.
     serv_init_thread_pool() can only be called from inside serv_init_func().
     The first argument is the number of threads to be created.  The second
     argument is the size of the stack for each thread.  The default size is
     used (2M) if this argument is 0.  Set this to a value suitable for your
     server.  The third argument is a callback function to be invoked when
     threads have accomplished their tasks.

   SERV_QUEUE_FOR_THREAD_POOL()
     To queue a task for the thread pool, invoke

     int serv_queue_for_thread_pool( int fd, int ( *func )( int fd, void *data ));

     This function returns 0 success and 1 on failure.  The first argument is
     the file descriptor on which the time-intensive operation is to be
     performed.  The second argument is the function to perform the time-
     intensive operation.  The library sets the descriptor to blocking mode.
     All events for the descriptor are disabled.  The library calls the
     function from a thread in the pool with the descriptor and the
     connection-specific data.  The function must not call any libserver
     functions because they are not reentrant.  The function must return an
     int result.

     When the function returns, the callback registered with
     serv_init_thread_pool() is invoked with the descriptor as the first
     argument and the return value of function as the second argument.  The
     library calls the callback in the main thread.  The callback can invoke
     any libserver function.  When the callback returns, events are re-enabled
     for the descriptor, and the descriptor is set to non-blocking mode.

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

     Upon receipt of SIGBUS or SIGSEGV, libserver 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_interface;
     char *serv_port;
     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_interface    points to the value passed to the -i option.  Defaults
                       to "".

     serv_port         points to the value passed as argument to the -p
                       option.  Defaults to "1966".

     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
     The library writes its pidfile into /var/run/ if is started as root.  The
     library is stopped with SIGTERM.  The library does graceful stops.  The
     library does not exit until all established connections have closed
     naturally.  If you want to kill a server outright, send it a SIGKILL.  A
     sample control script is provided in the server distribution.  To use the
     script, you must replace all occurrences of "server" with the value you
     pass to serv_set_name().  The script must be renamed as the value you
     passed to serv_set_name() and installed in /usr/local/etc/rc.d.

     Two variables must be added to /etc/rc.conf to use the script.
     Substitute your server's name for "server":

     server_enable="YES"
     server_flags="-u www -g www -r /usr/local/server"

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

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

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

     libserver_enable="NO"

     and use the following commands:

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

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

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

     -l  By default, the library listens on all TCP interfaces it can find
         capable of IPv4 or IPv6.  The -l option instructs the library to
         listen on a UNIX-domain socket instead.  Specify the path to the
         socket as argument.  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---.  You
         cannot specify the -l option together with the -p or -i options.

     -p  The -p option specifies the port to listen on.  This defaults to
         1966.  To bind to a port lower than 1024, the server must be started
         as root.

     -i  By default, libserver accepts connections on all interfaces it can
         find capable of IPv4 or IPv6.  The -i option limits libserver to
         accepting connections from a specified interface.  Pass the IP
         address of the desired interface as argument.

     -m  By default, libserver maintains no more than 16384 simultaneous
         connections.  The -m option specifies a different value.

     -q  The -q option specifies the backlog of client connections queued by
         the OS kernel for the server to subsequently service.  This value
         defaults to 1024.  Note that the kernel actually uses a queue of 1.5
         times the size of the specified value.  Connections arriving when the
         queue is full are dropped by the kernel.  Libserver does not let you
         set this value to less than 1024.

     -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 libserver to
         change user, it must be started as root.

         Libserver 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 libserver from becoming a daemon and writing
         its pidfile to /var/run/.  Libserver 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.  Libserver 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

                                 June 29, 2017