elemental-ircd/libratbox/src/poll.c

248 lines
6.4 KiB
C

/*
* ircd-ratbox: A slightly useful ircd.
* s_bsd_poll.c: POSIX poll() compatible network routines.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
* Copyright (C) 2002-2005 ircd-ratbox development team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*
*/
#include <libratbox_config.h>
#include <ratbox_lib.h>
#include <commio-int.h>
#if defined(HAVE_POLL) && (HAVE_SYS_POLL_H)
#include <sys/poll.h>
/* I hate linux -- adrian */
#ifndef POLLRDNORM
#define POLLRDNORM POLLIN
#endif
#ifndef POLLWRNORM
#define POLLWRNORM POLLOUT
#endif
struct _pollfd_list {
struct pollfd *pollfds;
int maxindex; /* highest FD number */
int allocated; /* number of pollfds allocated */
};
typedef struct _pollfd_list pollfd_list_t;
static pollfd_list_t pollfd_list;
int
rb_setup_fd_poll(rb_fde_t *F)
{
return 0;
}
/*
* rb_init_netio
*
* This is a needed exported function which will be called to initialise
* the network loop code.
*/
int
rb_init_netio_poll(void)
{
int fd;
pollfd_list.pollfds = rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd)));
pollfd_list.allocated = rb_getmaxconnect();
for(fd = 0; fd < rb_getmaxconnect(); fd++) {
pollfd_list.pollfds[fd].fd = -1;
}
pollfd_list.maxindex = 0;
return 0;
}
static void
resize_pollarray(int fd)
{
if(rb_unlikely(fd >= pollfd_list.allocated)) {
int x, old_value = pollfd_list.allocated;
pollfd_list.allocated += 1024;
pollfd_list.pollfds =
rb_realloc(pollfd_list.pollfds,
pollfd_list.allocated * (sizeof(struct pollfd)));
memset(&pollfd_list.pollfds[old_value + 1], 0, sizeof(struct pollfd) * 1024);
for(x = old_value + 1; x < pollfd_list.allocated; x++) {
pollfd_list.pollfds[x].fd = -1;
}
}
}
/*
* rb_setselect
*
* This is a needed exported function which will be called to register
* and deregister interest in a pending IO state for a given FD.
*/
void
rb_setselect_poll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
{
if(F == NULL)
return;
if(type & RB_SELECT_READ) {
F->read_handler = handler;
F->read_data = client_data;
if(handler != NULL)
F->pflags |= POLLRDNORM;
else
F->pflags &= ~POLLRDNORM;
}
if(type & RB_SELECT_WRITE) {
F->write_handler = handler;
F->write_data = client_data;
if(handler != NULL)
F->pflags |= POLLWRNORM;
else
F->pflags &= ~POLLWRNORM;
}
resize_pollarray(F->fd);
if(F->pflags <= 0) {
pollfd_list.pollfds[F->fd].events = 0;
pollfd_list.pollfds[F->fd].fd = -1;
if(F->fd == pollfd_list.maxindex) {
while(pollfd_list.maxindex >= 0
&& pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
pollfd_list.maxindex--;
}
} else {
pollfd_list.pollfds[F->fd].events = F->pflags;
pollfd_list.pollfds[F->fd].fd = F->fd;
if(F->fd > pollfd_list.maxindex)
pollfd_list.maxindex = F->fd;
}
}
/* int rb_select(unsigned long delay)
* Input: The maximum time to delay.
* Output: Returns -1 on error, 0 on success.
* Side-effects: Deregisters future interest in IO and calls the handlers
* if an event occurs for an FD.
* Comments: Check all connections for new connections and input data
* that is to be processed. Also check for connections with data queued
* and whether we can write it out.
* Called to do the new-style IO, courtesy of squid (like most of this
* new IO code). This routine handles the stuff we've hidden in
* rb_setselect and fd_table[] and calls callbacks for IO ready
* events.
*/
int
rb_select_poll(long delay)
{
int num;
int fd;
int ci;
PF *hdl;
void *data;
struct pollfd *pfd;
int revents;
num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay);
rb_set_time();
if(num < 0) {
if(!rb_ignore_errno(errno))
return RB_OK;
else
return RB_ERROR;
}
if(num == 0)
return RB_OK;
/* XXX we *could* optimise by falling out after doing num fds ... */
for(ci = 0; ci < pollfd_list.maxindex + 1; ci++) {
rb_fde_t *F;
pfd = &pollfd_list.pollfds[ci];
revents = pfd->revents;
fd = pfd->fd;
if(revents == 0 || fd == -1)
continue;
F = rb_find_fd(fd);
if(F == NULL)
continue;
if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
hdl = F->read_handler;
data = F->read_data;
F->read_handler = NULL;
F->read_data = NULL;
if(hdl)
hdl(F, data);
}
if(IsFDOpen(F) && (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))) {
hdl = F->write_handler;
data = F->write_data;
F->write_handler = NULL;
F->write_data = NULL;
if(hdl)
hdl(F, data);
}
if(F->read_handler == NULL)
rb_setselect_poll(F, RB_SELECT_READ, NULL, NULL);
if(F->write_handler == NULL)
rb_setselect_poll(F, RB_SELECT_WRITE, NULL, NULL);
}
return 0;
}
#else /* poll not supported */
int
rb_init_netio_poll(void)
{
errno = ENOSYS;
return -1;
}
void
rb_setselect_poll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
{
errno = ENOSYS;
return;
}
int
rb_select_poll(long delay)
{
errno = ENOSYS;
return -1;
}
int
rb_setup_fd_poll(rb_fde_t *F)
{
errno = ENOSYS;
return -1;
}
#endif