pip(3) FreeBSD Library Functions Manual pip(3) NAME pip – Minimal Event-Driven SCGI Application Server Library SYNOPSIS #include -I/usr/local/include -L/usr/local/lib -lpip DESCRIPTION LibPip provides a limited event-driven SCGI application server for use with the prospero web server. The library handles network and concurrency tasks. You supply code to service connections. The library services TCP or UNIX-domain connections. The library only accepts GET and POST requests that use x-form- urlencoding. This means that you cannot service POSTs that upload files. You cannot set events on descriptors. USAGE Pip provides your server's "main" function. You define 3 functions to match the following prototypes. void pip_init_func(); void pip_exit_func(); int pip_request_handler( void * ); Do not define any other global symbol beginning with the five characters ´pip_' because pip reserves that namespace. PIP_INIT_FUNC() In pip_init_func(), perform the initialization tasks your server needs to do once at server start-up. Pip calls pip_init_func(): • after changing to the directory specified by the -r command line option. • 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, pip_init_func() executes as root. • 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. PIP_EXIT_FUNC() If you have exit handlers you would like to register to run before the server exits, do not invoke atexit() from pip_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 pip_exit_func(). PIP_SET_NAME() To set the server's name, call pip_set_name() inside pip_init_func(). void pip_set_name( char * ); If not set, the server's name defaults to "pip". The server's name is used in two ways. • When a server is running, stderr is connected to /dev/null. Errors are reported with syslog(3). Pip calls openlog() with the server's name to ensure log entries are identified by the server's name. • 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 pip distribution. PIP_SET_PERIODIC() Install a function for pip to invoke periodically with: void pip_set_periodic( void (*)(), int ); Pip 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. PIP_REQUEST_HANDLER() Pip calls pip_request_handler() once to service each connection. int pip_request_handler( void * ); The opaque pointer argument identifies the current connection. You pass the pointer to other library functions as necessary. Queue response data for the client with pip_write_conn(). • To abandon a connection, return a non-zero value. Queued data is discarded, and the connection is closed. • To indicate that the complete response has been queued for the client, return 0. If no data is queued, pip drops the connection. Otherwise, the connection is closed after all the data is sent to the client. PIP_GET_USER_DATA() The library provides space where you can store a generic pointer or a float for every connection. A pointer to the storage space is returned by pip_get_user_data(). union pip_user_data { void *ptr; float num; }; union pip_user_data *pip_get_user_data( void * ); The function accepts the opaque pointer that identifies a connection. PIP_WRITE_CONN() To queue response data for the client, pass a character pointer to pip_write_conn(). int pip_write_conn( void *conn, void *data, int len ); The function's first argument is the opaque pointer passed to pip_request_handler(). The function's second argument is an opaque pointer to the data. The third argument specifies the length of the data pointed to by the second argument. Pip copies the data to an internal buffer. pip_write_conn() does not write the data but queues it for delivery. When the socket is writeable, pip sends up to one buffer of queued data to the client until the outgoing queue is consumed. pip_write_conn() returns: • -1 if the opaque pointer does not reference a connection. • -2 If the server cannot enlarge the queue. • 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 then return -1 from pip_request_handler() to drop the connection. ACCESS TO REQUEST DATA Inside pip_request_handler(), use the following library functions to access the environment, the parameters, and cookies. The first argument to all of these functions is the opaque pointer passed to pip_request_handler(). char *pip_get_env( void *conn, char * ); char **pip_get_envs( void *conn ); char *pip_get_param( void *conn, char * ); char **pip_get_params( void *conn ); char *pip_get_cookie( void *conn, char * ); char **pip_get_cookies( void *conn ); pip_get_env() retrieves the value of one particular environment variable. Pass the name of the variable as argument, and the function returns that variable's value or NULL if the variable is not defined. pip_get_envs() returns an array of character pointers listing all the environment variables and their values with each variable name followed by its value. The array is always terminated with a NULL pointer. pip_get_param() retrieves the decoded value of one particular parameter. Pass the name of the parameter as argument, and the function returns that parameter's value or NULL if the parameter is not defined. pip_get_params() returns an array of character pointers listing all the parameters and their values with each parameter name followed by its value. The array is always terminated by a NULL pointer. pip_get_cookie() retrieves the value of one named cookie defined in the the HTTP_COOKIE environment variable. Pass the name of the desired cookie as argument, and the function returns that cookie's value or NULL if the cookie is not set. pip_get_cookies() returns an array of character pointers listing all the cookies defined in HTTP_COOKIE with each cookie name followed by its value. The array is always terminated by a NULL pointer. CONVENIENCE FUNCTIONS Use these convenience functions to encode a string in x-www-form- urlencoding and to escape <, >, and & with their HTML entities. char *pip_form_encode( char * ); char *pip_html_escape( char * ); Both functions return dynamically allocated strings that must be freed by the caller. These functions return NULL if memory cannot be allocated. 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 *pip_config_file; char *pip_root_dir; char *pip_interface; char *pip_port; char *pip_user; char *pip_group; pip_config_file points to the value passed to the -f option. Defaults to NULL. pip_root_dir points to the value passed to the -r option. Must be explicitly set. pip_interface points to the value passed to the -i option. Defaults to "". pip_port points to the value passed as argument to the -p option. Defaults to "4000". pip_user points to the value passed as argument to the -u option. Defaults to "nobody". pip_group points to the value passed as argument to the -g option. Defaults to "nobody". LIMITS Pip stores the information for 25 environment variables, 50 parameters, and 25 cookies. More items provided in a client request are ignored. See the COMMAND-LINE OPTIONS for how to use the -b option to limit the amount of data clients can submit. CONFIGURATION If it is started as root, pip writes its pidfile into /var/run/. Stop pip with SIGTERM. Pip stops gracefully. Idle workers exit immediately. Workers with established connections exit after established connections close. A sample control script, pip.rcfile, is provided in the pip distribution. To use the script, replace all occurrences of "pip" with the value that you pass to pip_set_name(). Rename the script to the same value. Install the script in /usr/local/etc/rc.d. Add the following variables to /etc/rc.conf. Substitute your server's name for "pip". pip_enable="YES" pip_flags="-u www -g www -r /usr/local/pip" If the "enable" variable is set to "YES", the server is started at system start. Use the following control commands. service pip start service pip stop service pip restart service pip status If you do not want the server started on system start, then set pip_enable="NO" Use the following control commands. service pip onestart service pip onestop service pip onerestart service pip onestatus DEBUGGING To debug a server, compile it with the -g and -O0 compiler options. With the debugger, invoke the server with pip's -x option. This forces the server to run as a single-thread foreground process. If you suspect a library bug exists, compile the pip source to object files with symbol information with "make debug". The object files can be included in your projects to allow you to trace the pip function calls. COMMAND-LINE OPTIONS The following command-line options are recognized by pip servers. The -r option is mandatory. -r Use the -r option to specify the absolute path to the server root directory. Pip chdir(2)s here. -l By default, pip listens on all interfaces it can find capable of IPv4 or IPv6. The -l option instructs pip 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---. -p The -p option specifies the port to listen on. This defaults to 4000. To bind to a port lower than 1024, the server must be started as root. -i By default, pip accepts connections on all interfaces it can find capable of IPv4 or IPv6. The -i option limits pip to accepting connections from a specified interface. Pass the IP address of the desired interface as argument. -m By default, pip maintains no more than 16384 simultaneous connections. The -m option changes this value. -u -g The -u and the -g options specify the user and group of the server. Both values default to "nobody". To change user, the server must be started as root. -b The -b option specifies a maximum acceptable data size in bytes. This value defaults to 4096. • For GET requests this value is ignored. We rely on the web server to limit the length of request lines. • For POST requests that are encoded with x-www-form-urlencoding, this value is the maximum size of request bodies. Connections are dropped without explanation when CONTENT_LENGTH exceeds this value. • Pip drops connections that make multipart/form-data requests. -x This option is useful when debugging servers. The -x option prevents pip from becoming a daemon. -f The -f option specifies a filename as argument. Pip assigns it to the global character pointer named pip_config_file. This enables the code in pip_init_func() and pip_worker_init_func() to read a configuration file. AUTHORS James Bailie ⟨jimmy@mammothcheese.ca⟩ http://www.mammothcheese.ca Sun Nov 20, 2022