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