/* * poll.C: poll(2) socket engine. * Rights to this code are documented in doc/pod/license.pod. * * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) */ static char const rcsid[] = "$Id: poll.C,v 1.5 2007/08/30 19:56:26 pippijn Exp $"; #include #include "atheme.h" #include "internal.h" #include "datastream.h" #include "connection.h" /* * linux does not provide POLLWRNORM by default, and we're not _XOPEN_SOURCE. * so.... we have to do this crap below. */ #ifndef POLLRDNORM #define POLLRDNORM POLLIN #endif #ifndef POLLWRNORM #define POLLWRNORM POLLOUT #endif pollfd pollfds[FD_SETSIZE]; /* XXX We need a define indicating MAXCONN. */ /* * init_socket_queues() * * inputs: * none * * outputs: * none * * side effects: * when using select, we don't need to do anything here. */ void init_socket_queues (void) { memset (&pollfds, 0, sizeof (pollfd) * FD_SETSIZE); } /* * update_poll_fds() * * inputs: * none * * outputs: * none * * side effects: * registered sockets are prepared for the poll() loop. */ static void update_poll_fds (void) { connection_vector::iterator it = connlist.begin (); connection_vector::iterator et = connlist.end (); int slot = 0; while (it != et) { connection_t *cptr = *it; cptr->pollslot = slot; if (cptr->is_connecting () || sendq_nonempty (cptr)) { pollfds[slot].fd = cptr->fd; pollfds[slot].events |= POLLWRNORM; pollfds[slot].revents = 0; } else { pollfds[slot].fd = cptr->fd; pollfds[slot].events |= POLLRDNORM; pollfds[slot].revents = 0; } slot++; ++it; } } /* * connection_t::select() * * inputs: * delay in microseconds * * outputs: * none * * side effects: * registered sockets and their associated handlers are acted on. */ void connection_t::select (time_t delay) { int sr; connection_vector::iterator it = connlist.begin (); connection_vector::iterator et = connlist.end (); int slot; update_poll_fds (); if ((sr = poll (pollfds, connlist.size (), delay / 100)) > 0) { /* Iterate twice, so we don't touch freed memory if * a connection is closed. * -- jilles */ while (it != et) { connection_t *cptr = *it; ++it; // increment here or continue will cause an endless loop slot = cptr->pollslot; if (pollfds[slot].revents == 0) continue; if (pollfds[slot].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { pollfds[slot].events &= ~(POLLRDNORM | POLLIN | POLLHUP | POLLERR); cptr->read_handler (cptr); } } for (it = connlist.begin (), et = connlist.end (); it != et; ++it) { connection_t *cptr = *it; slot = cptr->pollslot; if (pollfds[slot].revents == 0) continue; if (pollfds[slot].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { pollfds[slot].events &= ~(POLLWRNORM | POLLOUT | POLLHUP | POLLERR); if (cptr->is_connecting ()) cptr->callback.connected (cptr); else cptr->write_handler (cptr); } } for (it = connlist.begin (), et = connlist.end (); it != et; ++it) { connection_t *cptr = *it; if (cptr->flags & CF_DEAD) cptr->close (); } } }