diff options
Diffstat (limited to 'src/socket.c')
-rw-r--r-- | src/socket.c | 147 |
1 files changed, 117 insertions, 30 deletions
diff --git a/src/socket.c b/src/socket.c index 78f79f5..13ee5e0 100644 --- a/src/socket.c +++ b/src/socket.c @@ -15,6 +15,7 @@ along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ #include "pies.h" +#include <assert.h> static void switch_eids (uid_t *puid, gid_t *pgid, mode_t *pumask) @@ -391,19 +392,20 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime) return res; } - -fd_set listenset; +fd_set fdset[3]; int fd_max; struct sockinst { struct sockinst *prev, *next; int fd; - int (*handler) (int, void *); + int dead; + socket_handler_t handler[3]; void *data; }; struct sockinst *si_head, *si_tail; +static int si_iterating; static struct sockinst * find_socket (int fd) @@ -416,17 +418,6 @@ find_socket (int fd) return sp; } -struct sockinst * -find_socket_handler (int (*handler) (int, void *)) -{ - struct sockinst *sp; - - for (sp = si_head; sp; sp = sp->next) - if (sp->handler == handler) - break; - return sp; -} - static void calc_fd_max () { @@ -439,20 +430,38 @@ calc_fd_max () } void * -register_socket (int fd, int (*handler) (int, void *), void *data) +register_socket (int fd, + socket_handler_t rd, + socket_handler_t wr, + socket_handler_t ex, + void *data) { struct sockinst *sip = xmalloc (sizeof *sip); sip->fd = fd; - sip->handler = handler; + sip->dead = 0; + sip->handler[PIES_EVT_RD] = rd; + sip->handler[PIES_EVT_WR] = wr; + sip->handler[PIES_EVT_EX] = ex; sip->data = data; sip->next = NULL; sip->prev = si_tail; if (si_tail) si_tail->next = sip; else + { + FD_ZERO (&fdset[PIES_EVT_RD]); + FD_ZERO (&fdset[PIES_EVT_WR]); + FD_ZERO (&fdset[PIES_EVT_EX]); si_head = sip; + } + si_tail = sip; - FD_SET (fd, &listenset); + if (rd) + FD_SET (fd, &fdset[PIES_EVT_RD]); + if (wr) + FD_SET (fd, &fdset[PIES_EVT_WR]); + if (ex) + FD_SET (fd, &fdset[PIES_EVT_EX]); if (fd_max == -1) calc_fd_max (); else if (fd > fd_max) @@ -460,13 +469,30 @@ register_socket (int fd, int (*handler) (int, void *), void *data) return sip; } +/* FIXME: Don't use with disable_socket/enable_socket */ void -deregister_socket (int fd) +update_socket (int fd, int evt, socket_handler_t f) { struct sockinst *sp = find_socket (fd); + assert (sp != NULL); + sp->handler[evt] = f; + if (f) + FD_SET (fd, &fdset[evt]); + else + FD_CLR (fd, &fdset[evt]); +} + +static void +delete_sockinst (struct sockinst *sp) +{ + if (sp->handler[PIES_EVT_RD]) + FD_CLR (sp->fd, &fdset[PIES_EVT_RD]); + if (sp->handler[PIES_EVT_WR]) + FD_CLR (sp->fd, &fdset[PIES_EVT_WR]); + if (sp->handler[PIES_EVT_EX]) + FD_CLR (sp->fd, &fdset[PIES_EVT_EX]); + fd_max = -1; - if (!sp) - return; if (sp->prev) sp->prev->next = sp->next; else @@ -475,9 +501,20 @@ deregister_socket (int fd) sp->next->prev = sp->prev; else si_tail = sp->prev; + free (sp); - FD_CLR (fd, &listenset); - fd_max = -1; +} + +void +deregister_socket (int fd) +{ + struct sockinst *sp = find_socket (fd); + if (!sp) + return; + if (si_iterating) + sp->dead = 1; + else + delete_sockinst (sp); } @@ -489,7 +526,7 @@ register_program_socket (int socktype, int fd, void *data) logmsg (LOG_ERR, "listen: %s", strerror (errno)); return 1; } - register_socket (fd, progman_accept, data); + register_socket (fd, progman_accept, NULL, NULL, data); return 0; } @@ -499,16 +536,26 @@ disable_socket (int fd) if (fd < 0) return; debug (2, (_("disabling fd %d"), fd)); - FD_CLR (fd, &listenset); + FD_CLR (fd, &fdset[PIES_EVT_RD]); + FD_CLR (fd, &fdset[PIES_EVT_WR]); + FD_CLR (fd, &fdset[PIES_EVT_EX]); } void enable_socket (int fd) { + struct sockinst *sp; if (fd < 0) return; debug (2, (_("enabling fd %d"), fd)); - FD_SET (fd, &listenset); + sp = find_socket (fd); + assert (sp != NULL); + if (sp->handler[PIES_EVT_RD]) + FD_SET (fd, &fdset[PIES_EVT_RD]); + if (sp->handler[PIES_EVT_WR]) + FD_SET (fd, &fdset[PIES_EVT_WR]); + if (sp->handler[PIES_EVT_EX]) + FD_SET (fd, &fdset[PIES_EVT_EX]); } void @@ -519,15 +566,55 @@ pies_pause () while (1) { - fd_set rdset = listenset; - int rc = select (fd_max + 1, &rdset, NULL, NULL, NULL); + fd_set rdset = fdset[PIES_EVT_RD]; + fd_set wrset = fdset[PIES_EVT_WR]; + fd_set exset = fdset[PIES_EVT_EX]; + + int rc = select (fd_max + 1, &rdset, &wrset, &exset, NULL); if (rc > 0) { struct sockinst *sp; - + int delete = 0; + ++si_iterating; for (sp = si_head; sp; sp = sp->next) - if (FD_ISSET (sp->fd, &rdset)) - sp->handler (sp->fd, sp->data); + { + if (sp->dead) + { + delete = 1; + continue; + } + if (sp->handler[PIES_EVT_RD] && FD_ISSET (sp->fd, &rdset)) + sp->handler[PIES_EVT_RD] (sp->fd, sp->data); + + if (sp->dead) + { + delete = 1; + continue; + } + if (sp->handler[PIES_EVT_WR] && FD_ISSET (sp->fd, &wrset)) + sp->handler[PIES_EVT_WR] (sp->fd, sp->data); + + if (sp->dead) + { + delete = 1; + continue; + } + if (sp->handler[PIES_EVT_EX] && FD_ISSET (sp->fd, &exset)) + sp->handler[PIES_EVT_EX] (sp->fd, sp->data); + } + --si_iterating; + + if (delete) + { + for (sp = si_head; sp; ) + { + struct sockinst *next = sp->next; + if (sp->dead) + delete_sockinst (sp); + sp = next; + } + calc_fd_max (); + } break; } else if (rc < 0) |