/* * charybdis: A slightly useful ircd. * ports.c: Solaris ports 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 * Copyright (C) 2002-2004 ircd-ratbox development team * Copyright (C) 2005 Edward Brocklesby. * Copyright (C) 2005 William Pitcock and Jilles Tjoelker * Copyright (C) 2007 River Tarnell * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * $Id: ports.c 3366 2007-04-03 09:57:53Z nenolod $ */ #include "stdinc.h" #include #include #include "stdinc.h" #include "res.h" #include "numeric.h" #include "tools.h" #include "memory.h" #include "balloc.h" #include "linebuf.h" #include "sprintf_irc.h" #include "commio.h" #include "ircevent.h" #include "modules.h" static int comm_init(void); static void comm_deinit(void); static int comm_select_impl(unsigned long delay); static void comm_setselect_impl(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout); static void pe_update_events(fde_t *, short, PF *); static int pe; static struct timespec zero_timespec; static port_event_t *pelst; /* port buffer */ static int pemax; /* max structs to buffer */ static void pe_update_events(fde_t * F, short filter, PF * handler) { PF *cur_handler = NULL; if (filter == POLLRDNORM) cur_handler = F->read_handler; else if (filter == POLLWRNORM) cur_handler = F->write_handler; if (!cur_handler && handler) port_associate(pe, PORT_SOURCE_FD, F->fd, filter, F); else if (cur_handler && !handler) port_dissociate(pe, PORT_SOURCE_FD, F->fd); } /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ /* Public functions */ /* * init_netio * * This is a needed exported function which will be called to initialise * the network loop code. */ static int init_netio(void) { if((pe = port_create()) < 0) { ilog(L_MAIN, "init_netio: Couldn't open port fd!\n"); exit(115); /* Whee! */ } pemax = getdtablesize(); pelst = MyMalloc(sizeof(port_event_t) * pemax); zero_timespec.tv_sec = 0; zero_timespec.tv_nsec = 0; return 0; } /* * ircd_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 comm_setselect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout) { fde_t *F = &fd_table[fd]; s_assert(fd >= 0); s_assert(F->flags.open); if (type & COMM_SELECT_READ) { pe_update_events(F, POLLRDNORM, handler); F->read_handler = handler; F->read_data = client_data; } if (type & COMM_SELECT_WRITE) { pe_update_events(F, POLLWRNORM, handler); F->write_handler = handler; F->write_data = client_data; } } /* * ircd_select * * 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 * ircd_setselect and fd_table[] and calls callbacks for IO ready * events. */ int comm_select(unsigned long delay) { int i, fd; unsigned int nget = 1; struct timespec poll_time; poll_time.tv_sec = delay / 1000; poll_time.tv_nsec = (delay % 1000) * 1000000; i = port_getn(pe, pelst, pemax, &nget, &poll_time); set_time(); if (i == -1) return COMM_ERROR; for (i = 0; i < nget; i++) { PF *hdl = NULL; fde_t *F; switch(pelst[i].portev_source) { case PORT_SOURCE_FD: fd = pelst[i].portev_object; F = &fd_table[fd]; if ((pelst[i].portev_events & POLLRDNORM) && (hdl = F->read_handler)) { F->read_handler = NULL; hdl(fd, F->read_data); } if (F->flags.open == 0) continue; if ((pelst[i].portev_events & POLLWRNORM) && (hdl = F->write_handler)) { F->write_handler = NULL; hdl(fd, F->write_data); } break; default: break; } } return COMM_OK; }