261 lines
5.7 KiB
C
261 lines
5.7 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 <librb_config.h>
|
|
#include <rb_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
|