libmessage(3)          FreeBSD Library Functions Manual          libmessage(3)

NAME
     libmessage - Message Server Library

SYNOPSIS
     #include <message.h>
     -I/usr/local/include -L/usr/local/lib -lmessage -lcrypto -lssl

DESCRIPTION
     LibMessage implements a generic, event-driven, message-based server with
     Transport Layer Security.  The library performs network and concurrency
     tasks.  You supply code to service connections.

     An example echo server and client are included in the source
     distribution.  An example chat server and client are also included.  See
     AVALON.README.

     An included companion library, libmessageclient(3), provides client
     functions.

   RATIONALE
     All TCP servers must concurrently accept, read from, and write to
     multiple connections.  Server developers should not have to repetitively
     re-implement this infrastructure.  It should be abstracted into a
     library.  LibMessage provides that infrastructure.

     All TCP servers and clients must descriminate messages in the their data
     streams.  If a single message is delivered per connection, EOF is a
     sufficient means of discrimination.  To discriminate multiple messages in
     their data streams, endpoints must exchange messages that are terminated
     with sentinals or preceded with length headers.  Service developers
     should not have to repeatedly incorporate a discrimination mechanism into
     their application-level protocols.  Message discrimination should be
     abstracted into a lower layer.  LibMessage provides this layer.

   FRAMES
     Server and client communicate in messages from 1 to 262144 (or the value
     of the -s option) bytes in length.  Messages are delivered in frames
     containing up to 32767 bytes of payload.  The first 2 bytes of frames
     comprise the frame header.  The high-order bit in the frame header
     indicates whether or not a frame is the last frame in a message.  The
     succeeding 15 bits specify the length of the frame's payload in bytes.
     Messages and frames of 0 length are valid.

     There are 2 Bytes of metadata for every 32767 bytes of payload.  A
     message of 262144 bytes is fragmented into 9 frames.  Therefore, with the
     default maximum message size, the protocol overhead is 9 x 2 = 18 bytes.

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

     void ms_init_func();
     void ms_exit_func();

     int ms_open_callback( void *, char * );
     int ms_read_callback( void *, int, int, unsigned char * );

     void ms_write_callback( void * );
     void ms_close_callback( void * );

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

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

     LibMessage calls ms_init_func():

     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
         ms_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.

   MS_EXIT_FUNC()
     If you have exit handlers you would like to register to run before the
     server exits, do not invoke atexit() from ms_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
     ms_exit_func().

   MS_SET_NAME()
     Call ms_set_name() inside ms_init_func() to set the server's name.

     void ms_set_name( char * );

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

     o   When the server is running, stderr is connected to /dev/null.  Errors
         must are reported with syslog(3).  LibMessage 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 LibMessage distribution.

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

     void ms_set_periodic( void (*)(), int );

     LibMessage 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.

   MS_OPEN_CALLBACK()
     LibMessage calls ms_open_callback() when a new connection is received.

     int ms_open_callback( void * );

     The argument is an opaque pointer that uniquely identifies the
     connection.  You pass the pointer to other library functions as
     necessary.

     Return 0 from ms_open_callback() to indicate that the connection should
     be accepted.  Return a non-zero value to indicate that the connection
     should be dropped.

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

   MS_SET_DATA()

   MS_GET_DATA()
     Use ms_set_data() to associate a void pointer with a connection.

     void ms_set_data( void *conn, void *data );

     The data argument is a pointer of any kind that you want to associate
     with the connection referenced by the conn argument.

     Use ms_get_data() to retrieve the stored pointer.

     void *ms_get_data( void *conn );

   MS_GET_QLEN
     Use ms_get_qlen() to know the number of outgoing frames currently queued
     for delivery to a client.

     unsigned int ms_get_qlen( void *conn );

     To control memory exhaustion, use this function to detect connections
     that have gone idle and are not consuming their queues.  Close the
     connections, or stop queueing data for them.

   MS_CLOSE_CALLBACK()
     LibMessage calls ms_close_callback() when a connection is closed.

     void ms_close_callback( void *data );

     LibMessage frees any outgoing queued data when ms_close_callback()
     returns.

     You must be prepared for connections to be closed unexpectedly due to
     internal errors.

   MS_READ_CALLBACK()
     LibMessage calls ms_read_callback() when a complete message has been read
     from the client.

     int ms_read_callback( void *, int len, unsigned char *buffer );

     The second argument is the length of the payload data in bytes.

     The third argument is a character pointer to the payload data.  The third
     argument points into a buffer that is freed on return.

     LibMessage accepts messages of 0 length.  In that case, the buffer
     argument is NULL.

     return 1 if you called ms_close_conn() to close the connection.
     Otherwise, return 0.  If you want to discard a message, return 0.

   MS_WRITE_CALLBACK()
     LibMessage calls ms_write_callback() when the outgoing frame queue for a
     client has been exhausted.

     void ms_write_callback( void * );

   MS_QUEUE_MESSAGE()
     Queue an outgoing message for clients with ms_queue_message().

     int ms_queue_message( void **, int conns, unsigned int len, unsigned char *data );

     The first argument is a pointer to an array of opaque pointers
     representing the connections to which the data is to be written.

     The second argument is the number of elements in the first argument.

     The third argument is the length of the payload data in bytes.

     The fourth argument is a character pointer to the payload data.

     ms_queue_message() frames the data and queues the frames for delivery.
     Each time a write event for a connection is generated, the library sends
     no more than one frame to the client.

     The library calls ms_write_callback() when a connection's queue has been
     exhausted.

     ms_queue_message() returns 0 on success and 1 on error.  If conns is
     zero, ms_queue_message() does nothing and returns 0.  An error return
     means that the system is low on memory and the function could not
     allocate memory to enlarge an outgoing message queue.  Some connections
     may have had the message queued for them.  Some will definitely not have
     had the message queued for them.  Note that if you pass a length argument
     outside the range 1-262144 (or -s), ms_queue_message() also returns 1.

   MS_QUEUE_FRAME()
     Queue an individual outgoing frame for clients with ms_queue_frame().

     This function is useful when you do not know the length of a message in
     advance.  You can queue fragment frames containing the data followed by a
     final terminator frame of 0 length.

     int ms_queue_frame( void **, int conns, int final, unsigned int len, unsigned char *data );

     The third argument indicates whether or not the frame header should have
     its high-order bit set.

     ms_queue_frame() frames the data in one frame and queues the frame for
     delivery.  If the len argument is outside the range 0-32767,
     ms_queue_frame() returns 1.

     Otherwise, The function behaves similarly to ms_queue_message().

   MS_CLOSE_CONN()
     To close a connection, invoke ms_close_conn().

     void ms_close_conn( void *conn, int now );

     If "now" is non-zero, ms_close_conn() closes the connection immediately.

     Otherwise, the connection is closed when its queue of outgoing frames has
     been exhausted.  When the queue is empty, ms_write_callback() is NOT be
     called, but ms_close_callback() is called.  Do not call other library
     functions for a connection that you have closed.  The connection
     identifier pointer is no longer valid.

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

     Upon receipt of SIGBUS or SIGSEGV, LibMessage restarts servers 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.

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

   CONFIGURATION
     LibMessage writes its pidfile into /var/run/ if is started as root.  The
     library is stopped with SIGTERM.  A sample control script is provided in
     the LibMessage distribution.  To use the script, you must replace all
     occurrences of "message" with the value you pass to ms_set_name().  The
     script must be renamed as the value you passed to ms_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 "message":

     message_enable="YES"
     message_flags="-u www -g www

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

     service message start
     service message stop
     service message restart
     service message status

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

     message_enable="NO"

     and use the following commands:

     service message onestart
     service message onestop
     service message onerestart
     service message onestatus

   COMMAND-LINE OPTIONS
     The following command line options are recognized by LibMessage servers.
     The -t and -r options must be defined.  The rest are optional.

     -r  The -r option specifies the root directory of your server. The server
         invokes chdir(2) on the value of this option before changing to the
         user and group specified by the -u and -g options.

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

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

     -m  By default, LibMessage maintains no more than 16384 simultaneous
         connections.  The -m option changes this value.

     -u

     -g  The -u and the -g options are used to specify the user and group for
         the server.  If the server starts as an unprivileged user and group,
         then these options must be set to the user and group.  For LibMessage
         to change to a different user and group, it must be started as root.
         Both values default to "nobody".

         LibMessage 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.

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

     -x  The -x option prevents LibMessage from becoming a daemon.  LibMessage
         runs in the foreground of its launching terminal.  Use this option in
         conjunction with the compiler options -O0 -g to run your servers
         under the debugger.

     -f  The -f option takes a filename as argument.  LibMessage assigns the
         filename to the global character pointer ms_config_file.  This
         enables code in ms_init_func() and to access a configuration file.

     -s  The -s option changes the maximum message size from the default of
         262144 bytes to a user-specified value.  The value cannot be set
         lower than the frame size of 32767 bytes.

     -t  The -t option specifies the fully qualified path to the TLS
         configuration file.  The file must contain 3 lines of text.  The
         first line is the fully qualified path to the file holding the server
         key in PEM format. The second line is the password for the key.  This
         line can be blank if there is no password.  The third line is the
         fully qualified path to the file containing the certificate chain in
         PEM format.

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

                               Tue Apr 21, 2020