libdombey(8) FreeBSD System Manager's Manual libdombey(8)
NAME
libdombey -- SCGI Application Server Library
SYNOPSIS
#include<dombey.h>
-I/usr/local/include -L/usr/local/lib -ldombey
DESCRIPTION
libdombey implements an SCGI application server which is incapable of
generating responses on its own. The programmer links custom code
against the library to create a complete multi-process server.
The library supplies the server's "main" function, and performs all the
network and process management functions of the server. One master
process forks and kills child processes, as needed, according to demand,
once per second. The child processes accept and service client connec-
tions. The master process does not.
libdombey may be made to listen for connections on TCP or UNIX-domain
sockets.
USAGE
The programmer must define in his or her code three functions which are
prototyped in dombey.h:
void scgi_init_func();
void scgi_child_init_func();
void scgi_request_handler();
In scgi_init_func(), or in functions which it calls, the programmer must
perform the initialization tasks his or her server needs to do, once at
server start-up, before any child processes are forked. scgi_init_func()
is called precisely once by libdombey before the server attempts to
change user and group to "nobody" or to the values specified by the -u
and/or -g command-line options. Therefore, if the server starts as root,
scgi_init_func() will execute as root. scgi_init_func() is executed
before the server becomes a daemon, which means the standard streams will
still be connected to the terminal it was started from, and error and
informative messages may be sent there. scgi_init_func() is called
before any of the command-line options are processed, except for the -f
option. Therefore, if the server has been started with the -r option,
the server will not yet have set the current working directory when
scgi_init_func() is executed.
In scgi_child_init_func(), or in functions which it calls, the programmer
may perform any other initialization tasks each child process needs to
perform independently of its parent before it can begin servicing connec-
tions. For example, one may open unique database connections for each
server child in scgi_child_init_func(). scgi_child_init_func() is called
every time a new server child process is forked().
scgi_child_init_func() is executed after the server has changed user and
group to "nobody" or to the values specified by the -u and/or -g command-
line options. When scgi_child_init_func() is executed the standard
streams will be connected to /dev/null. Therefore errors must be
reported using syslog(3). When scgi_child_init_func() is executed, the
-r command-line option will have been processed to change the current
working directory.
Libdombey recognizes several command-line options to configure itself,
described at the end of this manual, but does not allow user code access
to the command line arguments. Instead, it recognizes an -f option, and
assigns the value of this option to the global character pointer
scgi_config_file. The code in scgi_init_func() and/or
scgi_child_init_func() may then access the specified configuration file.
Libdombey does nothing with the value of scgi_config_file. If the -f
option was not present on the command line, this variable will be NULL.
If the programmer has shut-down tasks to perform when the master or child
processes exit, he or she can register functions via atexit(3) in either
scgi_init_func() or scgi_child_init_func(). Functions registered in
scgi_init_func() will be called by the master and all child processes
when they exit. Functions registered in scgi_child_init_func() will only
be called by the registering process when it exits. If the programmer
needs to perform a shut-down task only in the master process, then he or
she is advised to use a global int to indicate whether a process is the
master or a child.
In scgi_init_func(), the programmer may install a function to be called
periodically by the master process to perform maintenance tasks with:
void scgi_periodic( void (*)(), int );
The function pointed to by first argument will be called periodically by
the master process, the period being specified in seconds by the second
argument. This function may only be called from scgi_init_func() because
only that function is invoked in the master process. Calling it from any
other location in your code will have no effect. Setting the interval to
a value <= 0, or setting the function to NULL, disables the periodic
function. Note that the server will be running as the user and group
defined by the -u and -g options when the periodic function is invoked.
The third programmer-supplied function, scgi_request_handler() is called
once for every request received by the server. The programmer must use
the buffered IO functions to output a complete CGI response to stdout
before scgi_request_handler() returns.
NEVER read from stdin. Your server may block forever, if you do.
The programmer must not define any global symbol beginning with the five
characters "scgi_", other than the names of the three programmer supplied
functions, because the library reserves that namespace for its own use.
There is one libdombey library function which should be called from
inside scgi_init_func():
void scgi_set_name( char * );
If not set, or set to NULL, the server's name defaults to "LibDombey".
The server's name is used in two ways:
o When the server is running, stderr is connected to /dev/null.
Errors, therefore, must be reported using syslog(3). The library
calls openlog() with the server's name as argument, to ensure log
entries are identified by the server's name.
o The server's pidfile will be written to /var/run/, if the server is
started as root. The filename will be the server's name with ".pid"
appended to it. This file can be used by /usr/local/etc/rc.d/
scripts to stop the server. A sample script is included in the lib-
dombey distribution.
Inside scgi_request_handler(), eight library functions may be employed to
access the SCGI environment, the decoded SCGI parameters, uploaded files,
and any cookies defined in HTTP_COOKIE:
char *scgi_get_env( char * );
char **scgi_get_envs();
char *scgi_get_param( char * );
char **scgi_get_params();
char *scgi_get_cookie( char * );
char **scgi_get_cookies();
char **scgi_get_file( char * );
char **scgi_get_files();
scgi_get_env() may be used to retrieve the value of one particular SCGI
environment variable. The name of the variable is passed as argument,
and the function returns the variable's value, or NULL if the variable is
not defined. Note that some variables may be defined with their values
being empty strings. scgi_get_envs() returns an array of character
pointers, listing all the SCGI environment variables and their values,
each variable name followed by its value, with the array terminated with
a NULL pointer.
scgi_get_param() may be used to retrieve the decoded value of one partic-
ular SCGI parameter. The uncoded name of the parameter is passed as
argument, and the function returns the decoded value, or NULL if the
parameter is not defined. Note that some parameters may have values of
empty strings, if a value was not explicitly set by the client.
scgi_get_params() returns an array of character pointers, listing all the
SCGI parameters and their values, each decoded parameter name followed by
its decoded value, with the array terminated by a NULL pointer.
scgi_get_cookie() may be used to retrieve the value of one named cookie
defined in the value of the HTTP_COOKIE environment variable. The name
of the desired cookie is passed as argument, and the function returns the
value, or NULL if the cookie is not set. scgi_get_cookies() returns an
array of character pointers, listing all the cookies defined in
HTTP_COOKIE, each cookie name followed by its value, with the array ter-
minated by a NULL pointer.
When processing a POSTed multipart/form-data document, elements of that
document with a "filename" parameter are stored in files in the directory
specified by the -r option. Other non-file elements of the same document
may be accessed with scgi_get_param() and scgi_get_params(), but the file
elements must be accessed with scgi_get_files() and scgi_get_file().
scgi_get_files() returns a NULL-terminated array of character pointers
listing the parameters of all the files uploaded by the current request.
The array consists of three ajacent entries for each uploaded file. The
first entry of each group of three is the "name" parameter (the name of
the input in the form from which the file was posted). The second entry
is the "filename" parameter (the filename on the client machine). The
third entry is the filename on the local filesystem where the success-
fully uploaded file has been stored. All files are created with
mkstemp() and reside in the directory specified by the -r option. These
filenames will all be unlink()ed by the library when scgi_request_han-
dler() returns. If the programmer wants to the files to persist, he or
she is responsible for hard linking another name to them.
scgi_get_file() may be used to access the files array entries associated
with a particular name. The function accepts the name parameter as argu-
ment and returns a pointer to a character pointer. Indexing the returned
pointer with 0, will give you a character pointer to the "filename"
parameter, and indexing the returned pointer with 1 will give you a char-
acter pointer to the local filename of the uploaded file.
libdombey stores only the first 25 SCGI environment variable/value pairs,
the first 25 SCGI parameter/value pairs, the first 25 uploaded files, and
the first 25 cookie/value pairs. More items provided in a client request
will be ignored. These limits are defined with four macros in the source
code, MAX_ENV, MAX_PARAMS, MAX_FILE, and MAX_COOKIE, respectively. You
may change them and recompile libdombey, if you need more items.
The pointers and strings returned by these functions MUST NOT be modi-
fied. The values returned by scgi_get_env(), scgi_get_param(),
scgi_get_file(), and scgi_get_cookie() do not persist between invocations
of scgi_request_handler(), so do not store them. The locations of the
arrays returned by scgi_get_envs(), scgi_get_params(), scgi_get_files(),
and scgi_get_cookies() never change, so these functions may be called
once and the returned values stored and used thereafter. One may call
these two functions in scgi_init_func() to get their values, but the con-
tent of the arrays will be indeterminate at that time, and should not be
accessed.
There is one last library convenience function available to the program-
mer:
char *scgi_form_encode( char * );
This function encodes a string using x-www-form-urlencoding. The
returned string is dynamically allocated, and must be free(3)d when no
longer needed.
An example server is included in the libdombey distribution, named
test.scgi. Please examine the test.c source for the example server. It
demonstrates the use of libdombey concisely.
CONFIGURATION
A server linked against libdombey writes its pidfile into /var/run/, if
it can (ie., it is started as root), and may be stopped with a SIGTERM.
A sample rc.d script is provided in the libdombey distribution. To use
the script, all occurrences of "dombey" must be replaced with the value
you passed to scgi_set_name(), and the script installed in
/usr/local/etc/rc.d, renamed as the value you passsed to scgi_set_name().
Two variables must be added to /etc/rc.conf. For example (substituting
"dombey" for your server's name):
dombey_enable="YES"
dombey_flags="-u www -g www -r /usr/local/dombey"
If the "enable" variable is set to "YES", the server will be started at
system start. The following rc commands will be available:
/usr/local/etc/rc.d/dombey start
/usr/local/etc/rc.d/dombey stop
/usr/local/etc/rc.d/dombey restart
/usr/local/etc/rc.d/dombey status
If you do not want the server started on system start, then set
dombey_enable="NO"
and use the following commands:
/usr/local/etc/rc.d/dombey forcestart
/usr/local/etc/rc.d/dombey forcestop
/usr/local/etc/rc.d/dombey forcerestart
/usr/local/etc/rc.d/dombey forcestatus
COMMAND-LINE OPTIONS
The following command-line options are recognized by libdombey servers.
The -r option is mandatory. All the rest are optional.
-r The mandatory -r option specifies the server root directory, which
libdombey will make its current working directory. When multi-
part/form-data POST request entities contain "filename" parameters,
files will be created in this directory to hold the data for those
entities.
-l By default, libdombey listens on all TCP interfaces it can find capa-
ble of IPv4 or IPv6. The -l option instructs the library to listen
on a UNIX-domain socket instead. The path to the socket must be
specified as this option's argument. The server will create the
socket when it starts, unlinking it first, if it already exists in
the filesystem. The owner and group of the socket will be changed to
the values of the -u and -g options, or their defaults. The permiss-
sions of the socket will be set to srwxrwx---. If this option is
present on the command-line, then the -p and -i options may not be
present. The server will refuse to run if they are.
-p The -p option specifies the port to listen on. This defaults to 4000
if not specified. Note that to bind to a port lower than 1024, the
server must be started as root.
-i By default, libdombey accepts connections on all interfaces it can
find capable of IPv4 or IPv6. The -i option, when present, overrides
this behavior, by limiting libdombey to accepting connections from a
specified interface only. The option accepts the IP address of the
desired interface as an argument. The address must be expressed in
the presentation format for either IPv4 or IPv6.
-m
-n libdombey uses a multi-process model, with one master process forking
or killing slave processes in response to client activity. Only the
slave processes service client requests. The -n options specifies
the number of idle slaves the master will attempt to keep ready at
all times. The -m option specifies the maximum number of slaves
which may be running at any time. The value specified must be equal
to or greater than the value specified for -n. The default value for
-n is 3 and the default value for -m is 25.
-b The -b option, if present, describes a maximum acceptable data size,
in bytes, which is used differently when processing different types
of requests. Its purpose is to prevent malicious clients from caus-
ing the server to consume arbitrary amounts of memory. If not speci-
fied this value defaults to 10000.
For GET requests this value is ignored.
For POST requests which are encoded with x-www-form-urlencoding, this
size is the maximum size of request bodies. Connections will be
dropped without explanantion when CONTENT_LENGTH exceeds this value.
For POST requests submitted as multipart/form-data documents, this
value specifies the maximum size of each non-file entity in the docu-
ment. The -e option specifies the maximum length of file entities.
-e The -e option specifies the maximum size, in bytes, of files uploaded
in multipart/form-data POSTS. If not specified, it defaults to
2000000. Connections attempting to upload a file greater than this
size will be dropped without explanation.
-u
-g The -u and the -g options may be used to specify the user and group
for the server to change to after it has bound to the listening
socket. If not specified, both values default to "nobody". Note
that in order for a libdombey server to change user the server must
be started as root. If not started as root, two error messages will
be syslog()ed at start-up, complaining about the inability of the
server to change user and group. You can suppress them by providing
values to -u and -g to override the default "nobody" with the actual
user and group under which the server runs.
-x The -x option, if present, prevents libdombey from becoming a daemon.
It will then run in the foreground of the terminal where it was
started, and may be stopped with signals (ie., Control-C). Stderr
will be connected to the terminal, so diagnostic output may be sent
there when this option is present on the command-line. The server
also will not write its pidfile to /var/run/ when the -x option is
used.
-f The -f option requires a filename as argument. Libdombey does noth-
ing with this value, but assigns it to the global character pointer
named scgi_config_file. This allows the code in scgi_init_func()
and/or scgi_child_init_func() to read a configuration file, specified
by the user, upon process start-up.
AUTHORS
James Bailie <jimmy@mammothcheese.ca>
http://www.mammothcheese.ca
Jan 05, 2012