#include <mailutils/server.h> typedef void (*mu_conn_free_fp)(void *conn_data,void *server_data); typedef int (*mu_conn_loop_fp)(int fd,void *conn_data,void *server_data); typedef void (*mu_server_free_fp)(void *server_data); typedef int (*mu_server_idle_fp)(void *server_data); int mu_server_add_connection(mu_server_t t, int fd, void *data, mu_conn_loop_fp loop, mu_conn_free_fp free); int mu_server_count(mu_server_t t, size_t *pcount); int mu_server_create(mu_server_t *t); int mu_server_destroy(mu_server_t *t); int mu_server_run(mu_server_t t); int mu_server_set_data(mu_server_t t,void *data,mu_server_free_fp fp); int mu_server_set_idle(mu_server_t t, mu_server_idle_fp fp); int mu_server_set_timeout(mu_server_t t,struct timeval *to); typedef int (*mu_ip_server_conn_fp)(int fd,struct sockaddr *s,int len, void *server_data, void *call_data, mu_ip_server_t srv); typedef int (*mu_ip_server_intr_fp)(void *data, void *call_data); typedef void (*mu_ip_server_free_fp)(void *data); int mu_ip_server_accept(mu_ip_server_t *srv, void *call_data); int mu_ip_server_create(mu_ip_server_t *srv,struct sockaddr *addr, int addrlen, int type); int mu_ip_server_destroy(mu_ip_server_t *srv); int mu_ip_server_get_debug(mu_ip_server_t srv, mu_debug_t *debug); int mu_ip_server_get_fd(mu_ip_server_t srv); int mu_ip_server_get_sockaddr(mu_ip_server_t srv, struct sockaddr *s, int *size); int mu_ip_server_get_type(mu_ip_server_t srv, int *ptype); int mu_ip_server_loop(mu_ip_server_t srv, void *call_data); int mu_ip_server_open(mu_ip_server_t srv); int mu_ip_server_set_acl(mu_ip_server_t srv, mu_acl_t acl); int mu_ip_server_set_conn(mu_ip_server_t srv, mu_ip_server_conn_fp conn); int mu_ip_server_set_data(mu_ip_server_t srv, void *data, mu_ip_server_free_fp free); int mu_ip_server_set_debug(mu_ip_server_t srv, mu_debug_t debug); int mu_ip_server_set_ident(mu_ip_server_t srv, const char *ident); int mu_ip_server_set_intr(mu_ip_server_t srv, mu_ip_server_intr_fp intr); int mu_ip_server_shutdown(mu_ip_server_t srv); int mu_tcp_server_set_backlog(mu_ip_server_t srv, int backlog); int mu_udp_server_get_bufsize(mu_ip_server_t srv, size_t *size); int mu_udp_server_get_rdata(mu_ip_server_t srv, char **pbuf, size_t *pbufsize); int mu_udp_server_set_bufsize(mu_ip_server_t srv, size_t size); typedef int (*mu_m_server_conn_fp)(int fd, struct sockaddr *sa, int salen, void *data, mu_ip_server_t srv, time_t timeout, int transcript); typedef int (*mu_m_server_prefork_fp)(int fd, void *data, struct sockaddr *s, int size); void mu_m_server_begin(mu_m_server_t srv); void mu_m_server_cfg_init(void); void mu_m_server_create(mu_m_server_t *srv,char *ident); void mu_m_server_destroy(mu_m_server_t *srv); void mu_m_server_end(mu_m_server_t srv); int mu_m_server_foreground(mu_m_server_t srv); int mu_m_server_get_default_address(mu_m_server_t srv,struct sockaddr *sa, int *salen); void mu_m_server_get_sigset(mu_m_server_t srv, sigset_t *sigset); void mu_m_server_get_type(mu_m_server_t srv,int *type); int mu_m_server_run(mu_m_server_t srv); const char *mu_m_server_pidfile(mu_m_server_t srv); void mu_m_server_set_conn(mu_m_server_t srv, mu_m_server_conn_fp f); void mu_m_server_set_data(mu_m_server_t srv, void *data); void mu_m_server_set_default_address(mu_m_server_t srv, struct sockaddr *sa, int salen); void mu_m_server_set_default_port(mu_m_server_t srv, int port); int mu_m_server_set_foreground(mu_m_server_t srv, int enable); void mu_m_server_set_max_children(mu_m_server_t srv, size_t num); int mu_m_server_set_pidfile(mu_m_server_t srv, const char *pidfile); void mu_m_server_set_prefork(mu_m_server_t srv, mu_m_server_prefork_fp f); void mu_m_server_set_sigset(mu_m_server_t srv, sigset_t *sigset); void mu_m_server_set_strexit(mu_m_server_t srv,const char* (*fun)(int)); void mu_m_server_set_timeout(mu_m_server_t srv, time_t timeout); void mu_m_server_set_type(mu_m_server_t srv,int type); void mu_m_server_stop(int code); time_t mu_m_server_timeout(mu_m_server_t srv);
The core of the server system is the mu_server_t object. This object can monitor any number of file descriptors for activity calling user-defined routines to process the incoming data.
Servers based on socket communications can be created and managed using the mu_ip_server_t. These can be used either as standalone servers or as a connection to a mu_server_t object, in which case the mu_ip_server_t object is passed as the data argument of the mu_server_add_connection.
Severs based on the mu_server_t and mu_ip_server_t objects can only process one client session at a time. The mu_m_server object can process multiple sessions by fork'ing sub-processes to handle each connection.
To access the configuration file options for configuring an mu_m_server object, the following code is needed:
#include <mailutils/acl.h>
#include <mailutils/server.h>
struct mu_cfg_param param[]={
.....
{".server",mu_cfg_section,NULL,0,NULL,"Server Configuration"},
.....
NULL};
struct argp argp={ ..... };
static const char *capa[]={.....};
int main(int argc, char *argv[])
{
mu_m_server_t srv=NULL;
mu_acl_cfg_init();
mu_m_server_cfg_init();
mu_argp_init(NULL,NULL);
mu_m_server_create(&srv,"ident");
if(mu_app_init(&app,capa,param,argc,argv,0,NULL,srv))
exit(1);
........
}
typedef struct _mu_ip_server *mu_ip_server_t
This is an opaque data structure used to control IP servers. None of the fields in the structure should be accessed by a user program.
typedef struct _mu_m_server *mu_m_server_t
This is an opaque data structure used to control multi-servers. None of the fields in the structure should be accessed by a user program.
typedef struct _mu_server *mu_server_t;
This is an opaque data structure used to control the server. None of the fields in the structure should be accessed by a user program.
int mu_ip_server_accept(mu_ip_server_t *srv, void *call_data);
Once called this function waits for an incoming connection from a client. When a connection is made, any acl(s) are checked and the connection function is called to handle the session. The function will return 0 if successful or an error code. In the event of an error, the listening socket will also be closed terminating the server.
int mu_ip_server_create(mu_ip_server_t *srv,struct sockaddr *addr, int addrlen, int type);
This create a new instance of an IP server. The IP address and port for the server to listen on are passed in the addr argument, the size of which is passed in addrlen. The type argument is either MU_IP_TCP or MU_IP_UDP. The function returns 0 if successful or an error code.
int mu_ip_server_destroy(mu_ip_server_t *srv);
Releases all the resources allocated to the IP server. The function returns 0 if successful or an error code.
int mu_ip_server_get_debug(mu_ip_server_t srv, mu_debug_t *debug);
The IP server maintains in internal debug object. This function returns this object. Returns 0 if successful or an error code.
int mu_ip_server_get_fd(mu_ip_server_t srv);
This function returns the file descriptor associated with the listening socket.
int mu_ip_server_get_sockaddr(mu_ip_server_t srv, struct sockaddr *s, int *size);
This function returns in s a copy of the listening socket descriptor. The argument size holds the size of s and is updated on exit to reflect the actual size of the listening socket descriptor. The function returns 0 if successful or an error code.
int mu_ip_server_get_type(mu_ip_server_t srv, int *ptype);
This function returns the type (TCP or UDP) of the server in ptype. Returns 0 if successful or an error code.
int mu_ip_server_loop(mu_ip_server_t srv, void *call_data);
This function enters a loop which calls mu_ip_server_accept to accept and process client sessions. The loop remains active for as long as the socket is open and the mu_ip_server_accept function returns 0. The function returns 0 if the loop is properly exited or the error code.
int mu_ip_server_open(mu_ip_server_t srv);
This function opens the socket associated with the server. It returns 0 if successful or an error code.
int mu_ip_server_set_acl(mu_ip_server_t srv, mu_acl_t acl);
This function sets the access control list which controls access to the server to the acl argument. Returns 0 if successful or an error code.
int mu_ip_server_set_conn(mu_ip_server_t srv, mu_ip_server_conn_fp conn);
This function sets the function called by the mu_ip_server_accept function when a connection from a client is made. The function return 0 if successful or an error code.
The parameters passed to the connection function is the file descriptor associated with the connection, a socket structure identifying the source of the incoming connection, the size of this structure, the call_data and srv arguments of the calling mu_ip_tcp_accept function. The function should return a non-zero value in the event of an error which will terminate the server.
int mu_ip_server_set_data(mu_ip_server_t srv, void *data, mu_ip_server_free_fp free);
This function sets a pointer to a block of memory that is passed to the function set by a call to mu_ip_server_set_intr. The free argument is a function that releases this block of data when the server object is destroyed.
int mu_ip_server_set_debug(mu_ip_server_t srv, mu_debug_t debug);
This function replaces the internal debug object with the one passed in debug. Returns 0 if successful or an error code.
int mu_ip_server_set_ident(mu_ip_server_t srv, const char *ident);
This set an identity string for the server object. Returns 0 if successful or an error code.
int mu_ip_server_set_intr(mu_ip_server_t srv, mu_ip_server_intr_fp intr);
This function is used to define the function called from mu_ip_server_tcp_accept if a signal is caught while it is waiting for a connection. Returns 0 if successful or an error code.
The arguments for the interrupt function are the pointer set by the most recent call to mu_ip_server_set_data and the call_data argument passed to the mu_ip_server_tcp_accept function. If this function returns a non-zero value then the connection is terminated.
int mu_ip_server_shutdown(mu_ip_server_t srv);
This function closes the listening socket so terminating the server. The function returns 0 if successful or an error code.
void mu_m_server_begin(mu_m_server_t srv);
This routine is called to start the server process. If necessary, the process is daemonised, the pidfile is created, any existing signal handlers are stored and signal handlers for the signals being trapped by the server are defined.
void mu_m_server_cfg_init(void);
This routine is called to enable the server options in the configuration file.
void mu_m_server_create(mu_m_server_t *srv,char *ident);
This function creates a new mu_m_server_t object. The ident argument is used to prefix messages.
void mu_m_server_destroy(mu_m_server_t *srv);
Releases the resources allocated to the object.
void mu_m_server_end(mu_m_server_t srv);
This routine is called when the main server control loop is completed to restore the old signal handlers.
int mu_m_server_foreground(mu_m_server_t srv);
Returns 0 if the server is configured to run as a daemon process or a non-zero value if it is configured to run in the foreground.
int mu_m_server_get_default_address(mu_m_server_t srv,struct sockaddr *sa, int *salen);
This function returns in sa a copy of the default address' socket descriptor. The argument salen holds the size of sa and is updated on exit to reflect the actual size of the socket descriptor. The function returns 0 if successful or an error code.
void mu_m_server_get_sigset(mu_m_server_t srv, sigset_t *sigset);
This function returns the current signal mask in sigset.
void mu_m_server_get_type(mu_m_server_t srv,int *type);
Returns the connection mode of the server in type.
const char *mu_m_server_pidfile(mu_m_server_t srv);
Returns the filename of the pidfile.
int mu_m_server_run(mu_m_server_t srv);
This is the main control loop of the server. The function returns 0 if the main loop is terminated correctly or an error code.
void mu_m_server_set_conn(mu_m_server_t srv, mu_m_server_conn_fp f);
Sets the connection function for the server.
The connection function is called by the sub-process after it has been created. The arguments to this routine are the file descriptor associated with the connection, the socket describing the incoming connection and its size, a pointer to the block of memory set by the last call to mu_m_server_set_data, the mu_ip_server_t object associated with the server, the timeout value and the transcript flag.
void mu_m_server_set_data(mu_m_server_t srv, void *data);
Sets a pointer to a memory block which is passed to the connection and prefork functions. The resources allocated to this block are NOT released when the object is destroyed.
void mu_m_server_set_default_address(mu_m_server_t srv, struct sockaddr *sa, int salen);
This function sets the default address the server listens on.
void mu_m_server_set_default_port(mu_m_server_t srv, int port);
This sets the default port that the server listens on. The server will listen on all interfaces.
int mu_m_server_set_foreground(mu_m_server_t srv, int enable);
This function controls whether or not the server is to run daemonised or not. If enable is 1 then the server runs in the foreground.
void mu_m_server_set_max_children(mu_m_server_t srv, size_t num);
This sets the maximum number of sub-processes created by the server to num.
int mu_m_server_set_pidfile(mu_m_server_t srv, const char *pidfile);
This sets name of the pidfile. This function returns 0 if it is successful or an error code.
void mu_m_server_set_prefork(mu_m_server_t srv, mu_m_server_prefork_fp f);
Sets the prefork function for the server.
The prefork function is called when a valid session has been established but before the sub-process which handles the session is created. The arguments to this routine are: the file descriptor associated with the session, a pointer to the memory block set by the last call to mu_m_server_set_data, a socket describing the incoming connection and the size of the socket. If this function returns a non-zero value then the session is abandoned.
void mu_m_server_set_strexit(mu_m_server_t srv,const char* (*fun)(int));
This function sets the function called to convert the exit code of a sub-process to human readable text.
void mu_m_server_set_sigset(mu_m_server_t srv, sigset_t *sigset);
By default, the server traps and handles the SIGCHLD, SIGINT, SIGTERM, SIGQUIT and SIGHUP signals. This function can be used to modify the signals that are handled by the server.
void mu_m_server_set_timeout(mu_m_server_t srv, time_t timeout);
This function sets the value which is passed to the connection function as a timeout value.
void mu_m_server_set_type(mu_m_server_t srv,int type);
Sets the connection mode of the server, either MU_IP_TCP or MU_IP_UDP.
void mu_m_server_stop(int code);
If this function is called with a non-zero value for code the control loop will be terminated.
time_t mu_m_server_timeout(mu_m_server_t srv);
Returns the currently set timeout value.
int mu_server_add_connection(mu_server_t t, int fd, void *data, mu_conn_loop_fp loop, mu_conn_free_fp free);
This function adds the file descriptor fd to the list of those being monitored by the server. The data argument is a pointer to a structure which is used to manage the underlying connection, e.g. in the case of an IP server, it will be the address of the mu_ip_server_t structure. This function will return 0 if successful or an error code.
The loop function is called from the main control loop when activity is detected on the file descriptor. The three arguments passed to this function are the fd and data arguments and the current pointer set by the mu_server_set_data function. This function should return MU_SERVER_SUCCESS if there is no error, MU_SERVER_CLOSE_CONN to stop the server monitoring that connection or MU_SERVER_SHUTDOWN to terminate the control loop altogether.
The free function is called from mu_server_destroy to release all resources associated with the connection. The two arguments pass to this function are the data argument and the current pointer set by the mu_server_set_data function.
int mu_server_count(mu_server_t t, size_t *pcount);
This function returns in pcount the number of connections currently being monitored. This function will return 0 if successful or an error code.
int mu_server_create(mu_server_t *t);
This function creates a new server. Returns 0 if successful or an error code.
int mu_server_destroy(mu_server_t *t);
Releases all the resources allocated to the server. Returns 0 if successful or an error code.
int mu_server_run(mu_server_t t);
This enters the main control loop of the server. Once in this loop, the server waits for some activity on any of the connections it is monitoring. If there is activity on the connection then that connection's loop function is called. If the monitoring is interrupted by a signal then the idle function is called. Any error in either the monitoring or processing of the data results in the control loop being terminated and the error code being returned to the caller.
int mu_server_set_data(mu_server_t t,void *data,mu_server_free_fp fp);
This function stores the pointer to a user provided block of data which is passed as an additional argument to various functions called during the operation of the server. The function fp, if it is provided, is used to release this data block during the call to mu_server_destroy.
int mu_server_set_idle(mu_server_t t, mu_server_idle_fp fp);
This function sets the function called when the main control loop is interrupted by a signal.
When the fp function is called, the argument passed to it is the pointer set by the most recent call to mu_server_set_data. If this function returns a non-zero value then the main control loop will be terminated.
int mu_server_set_timeout(mu_server_t t,struct timeval *to);
This function sets the timeout value used by the main control loop when monitoring for activity. If no timeout is specified then the server will block indefinitly. The function returns 0 if successful or an error code.
int mu_tcp_server_set_backlog(mu_ip_server_t srv, int backlog);
This function is used to set the size of the incoming connection queue for TCP sockets. The function returns 0 if successful or an error code.
The default value is 4.
int mu_udp_server_get_bufsize(mu_ip_server_t srv, size_t *size);
This function returns in size the size of the data buffer used for UDP communications. The function returns 0 if successful or an error code.
int mu_udp_server_get_rdata(mu_ip_server_t srv, char **pbuf, size_t *pbufsize);
This function returns a pointer to the UDP data buffer in pbuf and its size in pbufsize. It returns 0 if successful or an error code.
int mu_udp_server_set_bufsize(mu_ip_server_t srv, size_t size);
This function is used to set the size of the buffer used to hold incoming UDP messages. The function returns 0 if successful or an error code.
The default is 4096 bytes.