libixp

git clone git://oldgit.suckless.org/libixp/
Log | Files | Refs | LICENSE

server.c (3432B)


      1 /* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
      2 /* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
      3  * See LICENSE file for license details.
      4  */
      5 #include <assert.h>
      6 #include <errno.h>
      7 #include <stdlib.h>
      8 #include <sys/types.h>
      9 #include <sys/socket.h>
     10 #include <unistd.h>
     11 #include "ixp_local.h"
     12 
     13 /**
     14  * Function: ixp_listen
     15  * Type: IxpConn
     16  *
     17  * Params:
     18  *	fs:    The file descriptor on which to listen.
     19  *	aux:   A piece of data to store in the connection's
     20  *	       P<aux> member of the IxpConn data structure.
     21  *	read:  The function called when the connection has
     22  *	       data available to read.
     23  *	close: A cleanup function called when the
     24  *	       connection is closed.
     25  *
     26  * Starts the server P<srv> listening on P<fd>. The optional
     27  * P<read> and P<close> callbacks are called with the IxpConn
     28  * structure for the connection as their sole argument.
     29  *
     30  * Returns:
     31  *	Returns the connection's new IxpConn data structure.
     32  *
     33  * See also:
     34  *	F<ixp_serverloop>, F<ixp_serve9conn>, F<ixp_hangup>
     35  */
     36 IxpConn*
     37 ixp_listen(IxpServer *srv, int fd, void *aux,
     38 		void (*read)(IxpConn*),
     39 		void (*close)(IxpConn*)
     40 		) {
     41 	IxpConn *c;
     42 
     43 	c = emallocz(sizeof *c);
     44 	c->fd = fd;
     45 	c->aux = aux;
     46 	c->srv = srv;
     47 	c->read = read;
     48 	c->close = close;
     49 	c->next = srv->conn;
     50 	srv->conn = c;
     51 	return c;
     52 }
     53 
     54 /**
     55  * Function: ixp_hangup
     56  * Function: ixp_server_close
     57  *
     58  * ixp_hangup closes a connection, and stops the server
     59  * listening on it. It calls the connection's close
     60  * function, if it exists. ixp_server_close calls ixp_hangup
     61  * on all of the connections on which the server is
     62  * listening.
     63  *
     64  * See also:
     65  *	F<ixp_listen>, S<IxpServer>, S<IxpConn>
     66  */
     67 
     68 void
     69 ixp_hangup(IxpConn *c) {
     70 	IxpServer *s;
     71 	IxpConn **tc;
     72 
     73 	s = c->srv;
     74 	for(tc=&s->conn; *tc; tc=&(*tc)->next)
     75 		if(*tc == c) break;
     76 	assert(*tc == c);
     77 
     78 	*tc = c->next;
     79 	c->closed = 1;
     80 	if(c->close)
     81 		c->close(c);
     82 	else
     83 		shutdown(c->fd, SHUT_RDWR);
     84 
     85 	close(c->fd);
     86 	free(c);
     87 }
     88 
     89 void
     90 ixp_server_close(IxpServer *s) {
     91 	IxpConn *c, *next;
     92 
     93 	for(c = s->conn; c; c = next) {
     94 		next = c->next;
     95 		ixp_hangup(c);
     96 	}
     97 }
     98 
     99 static void
    100 prepare_select(IxpServer *s) {
    101 	IxpConn *c;
    102 
    103 	FD_ZERO(&s->rd);
    104 	for(c = s->conn; c; c = c->next)
    105 		if(c->read) {
    106 			if(s->maxfd < c->fd)
    107 				s->maxfd = c->fd;
    108 			FD_SET(c->fd, &s->rd);
    109 		}
    110 }
    111 
    112 static void
    113 handle_conns(IxpServer *s) {
    114 	IxpConn *c, *n;
    115 	for(c = s->conn; c; c = n) {
    116 		n = c->next;
    117 		if(FD_ISSET(c->fd, &s->rd))
    118 			c->read(c);
    119 	}
    120 }
    121 
    122 /**
    123  * Function: ixp_serverloop
    124  * Type: IxpServer
    125  *
    126  * Enters the main loop of the server. Exits when
    127  * P<srv>->running becomes false, or when select(2) returns an
    128  * error other than EINTR.
    129  *
    130  * Returns:
    131  *	Returns 0 when the loop exits normally, and 1 when
    132  *	it exits on error. V<errno> or the return value of
    133  *	F<ixp_errbuf> may be inspected.
    134  * See also:
    135  *	F<ixp_listen>, F<ixp_settimer>
    136  */
    137 
    138 int
    139 ixp_serverloop(IxpServer *srv) {
    140 	timeval *tvp;
    141 	timeval tv;
    142 	long timeout;
    143 	int r;
    144 
    145 	srv->running = 1;
    146 	thread->initmutex(&srv->lk);
    147 	while(srv->running) {
    148 		tvp = nil;
    149 		timeout = ixp_nexttimer(srv);
    150 		if(timeout > 0) {
    151 			tv.tv_sec = timeout/1000;
    152 			tv.tv_usec = timeout%1000 * 1000;
    153 			tvp = &tv;
    154 		}
    155 
    156 		if(srv->preselect)
    157 			srv->preselect(srv);
    158 
    159 		if(!srv->running)
    160 			break;
    161 
    162 		prepare_select(srv);
    163 		r = thread->select(srv->maxfd + 1, &srv->rd, 0, 0, tvp);
    164 		if(r < 0) {
    165 			if(errno == EINTR)
    166 				continue;
    167 			return 1;
    168 		}
    169 		handle_conns(srv);
    170 	}
    171 	return 0;
    172 }
    173