Author: Kev <klmitch@mit.edu>
authorKevin L. Mitchell <klmitch@mit.edu>
Thu, 7 Jun 2001 00:29:48 +0000 (00:29 +0000)
committerKevin L. Mitchell <klmitch@mit.edu>
Thu, 7 Jun 2001 00:29:48 +0000 (00:29 +0000)
Log message:

This is the long awaited merge of the events branch with the main-line.
The events branch is now defunct.  Enjoy...

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@487 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

49 files changed:
ChangeLog
INSTALL_FR
RELEASE.NOTES
acconfig.h
config.h.in
configure
configure.in
include/IPcheck.h
include/client.h
include/ircd.h
include/ircd_events.h [new file with mode: 0644]
include/ircd_osdep.h
include/ircd_policy.h
include/list.h
include/listener.h
include/numeric.h
include/s_auth.h
include/s_bsd.h
include/s_debug.h
include/uping.h
ircd/IPcheck.c
ircd/Makefile.in
ircd/channel.c
ircd/engine_devpoll.c [new file with mode: 0644]
ircd/engine_kqueue.c [new file with mode: 0644]
ircd/engine_poll.c [new file with mode: 0644]
ircd/engine_select.c [new file with mode: 0644]
ircd/ircd.c
ircd/ircd_events.c [new file with mode: 0644]
ircd/ircd_signal.c
ircd/list.c
ircd/listener.c
ircd/m_list.c
ircd/m_stats.c
ircd/os_bsd.c
ircd/os_generic.c
ircd/os_linux.c
ircd/os_openbsd.c
ircd/os_solaris.c
ircd/res.c
ircd/s_auth.c
ircd/s_bsd.c
ircd/s_conf.c
ircd/s_err.c
ircd/s_serv.c
ircd/s_stats.c
ircd/s_user.c
ircd/send.c
ircd/uping.c

index 294e412f6030ec56d439929d3f1c2f59d81feb89..4936069e7e8144bfa5199fc6a5aeaa2d87f130f3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,273 @@
+2001-06-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/res.c (init_resolver): don't start DNS expires with a 0
+       relative timeout--if the server starts slow, timeouts could be
+       messy...there's probably a better solution, but this'll do for now
+
+       * ircd/os_solaris.c: _XOPEN_SOURCE doesn't get along with Solaris
+       headers very well; include stropts.h; define an os_set_tos()
+
+       * ircd/os_generic.c (os_set_tos): added an os_set_tos() for
+       os_generic.c
+
+       * ircd/ircd.c: if there are no C-lines, we don't want to have a
+       timer that expires at the absolute time of 0--it kinda blocks all
+       the other timers!
+
+       * ircd/engine_devpoll.c: some includes for open(); declare errcode
+       and codesize in engine_loop()
+
+       * ircd/list.c (free_client): remove bogus check on timer active
+       flag
+
+       * ircd/s_auth.c: pull out destruction code in
+       auth_timeout_request() into an externally-visible
+       destroy_auth_request(); manage cli_auth pointer in client
+       structure; use it for an extra assertion check
+
+       * ircd/list.c: include s_auth.h for destroy_auth_request(); add
+       debugging notices to show flow when deallocating
+       connections/clients; call destroy_auth_request() when free'ing a
+       client that has an auth outstanding; don't free the connection if
+       the process timer is unmarked but still active
+
+       * ircd/ircd_events.c: set GEN_ACTIVE when initializing a generator
+       and reset it before calling the event handler for an ET_DESTROY
+       event
+
+       * include/s_auth.h (destroy_auth_request): declare
+       destroy_auth_request(), which can be used to destroy an
+       outstanding auth request if a client socket goes away before the
+       auth exchange is completed
+
+       * include/ircd_events.h: add an active flag to keep track of
+       whether or not particular generators are active, for the
+       convenience of functions using the API
+
+       * include/client.h: add a pointer for auth requests to struct
+       Connection so we can kill outstanding auth requests if a client
+       socket closes unexpectedly
+
+       * ircd/s_bsd.c: cli_connect() could become 0 during the course of
+       the sock or timer callback; take that into account in the assert
+
+       * ircd/list.c: add magic number checking and setting--magic
+       numbers are zero'd on frees to detect double-frees; add back
+       setting of cli_from() to 0 to break the back-link from the struct
+       Connection (duh)
+
+       * ircd/ircd.c: set me's magic number correctly
+
+       * include/client.h: define magic numbers and accessor/verifier
+       macros
+
+       * ircd/list.c: assert that dealloc_client() is called with
+       cli_connect(cptr) == 0; set cli_connect(cptr) to 0 before calling
+       dealloc_client(); don't mess with cli_from(cptr)
+
+       * ircd/s_bsd.c: only attempt to dealloc a connection if the
+       associated client has already been destroyed, or at least delinked
+
+2001-06-05  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/list.c (free_client): only try to delete the socket when
+       the fd hasn't already been closed, avoiding a double-free
+
+       * ircd/list.c (free_connection): make sure the client is really
+       gone before doing away with the connection
+
+       * ircd/s_bsd.c: record that socket has been added in con_freeflag
+       field; queue a socket_del() as soon as the socket is close()'d;
+       use con_freeflag & FREEFLAG_TIMER instead of con_timer; clear
+       FREEFLAG_SOCKET on ET_DESTROY event in client_sock_callback(),
+       then dealloc the connection if safe; mark socket as dead when
+       there's a read error or EOF; clear FREEFLAG_TIMER flag upon entry
+       to client_timer_callback(); dealloc connection if safe upon
+       ET_DESTROY event in client_timer_callback()
+
+       * ircd/list.c: use con_freeflag instead of con_timer; only dealloc
+       the connection if both socket and timer have been destroyed;
+       destroy both socket and timer explicitly and carefully
+
+       * include/client.h: replace the con_timer field with a
+       con_freeflag field, to indicate what still needs freeing; define
+       the freeflags
+
+       * ircd/engine_select.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/engine_devpoll.c (engine_loop): duh...sockList[i] could
+       become 0
+
+       * ircd/s_bsd.c: add some extra assertions to try to track down a
+       corruption problem
+
+       * ircd/engine_select.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_poll.c (engine_loop): add an extra assert to try to
+       track down a corruption problem
+
+       * ircd/engine_kqueue.c (engine_loop): add an extra assert to try
+       to track down a corruption problem
+
+       * ircd/engine_devpoll.c (engine_loop): skip slots that have become
+       empty during processing; add an extra assert to try to track down
+       a corruption problem
+
+       * ircd/engine_kqueue.c (engine_delete): make sure to zero deleted
+       entries
+
+2001-06-04  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): client is no longer
+       blocked, so we must mark it as unblocked
+
+       * ircd/engine_select.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK; use a dummy sock variable to keep things from
+       disappearing on us; correct timeout calculation; update nfds for
+       efficiency
+
+       * ircd/engine_poll.c: use new debugging level (DEBUG_ENGINE);
+       remove a spurious "if (sock)" which will always be true; update
+       nfds for efficiency
+
+       * ircd/engine_kqueue.c: add Debug() calls galore; add handling for
+       SS_NOTSOCK (just in case); correct timeout calculation
+
+       * ircd/engine_devpoll.c: add Debug() calls galore; add handling
+       for SS_NOTSOCK; correct timeout calculation; add EAGAIN handling
+
+       * include/s_debug.h (DEBUG_ENGINE): add new debugging level;
+       pretty-indent numbers
+
+       * ircd/engine_poll.c (engine_loop): break out SS_NOTSOCK
+       case--it's not a socket; the check for writability is most likely
+       not needed, but present for completeness
+
+2001-05-24  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c: add Debug messages; call read_packet() even if the
+       no newline flag is set; call read_packet() when the timer expires,
+       regardless of what's in the buffer--read_packet() should be able
+       to deal properly
+
+       * ircd/IPcheck.c (ip_registry_connect_succeeded): correct a NOTICE
+       sent to clients to include the client nickname (duh)
+
+       * ircd/ircd_events.c: don't destroy a timer if it's already marked
+       for destruction; replace a missing ! in socket_del()
+
+       * ircd/engine_poll.c (engine_loop): reference a temporary variable
+       so we don't have to worry about sockList[i] going away
+
+       * ircd/s_bsd.c (client_sock_callback): add Debug messages
+
+       * ircd/s_auth.c: add Debug messages all over the place
+
+       * ircd/ircd_events.c: add and edit some Debug messages; add a list
+       of routines to convert some of the enums and flags from numbers
+       into human-readable strings for the Debug messages
+
+       * ircd/engine_poll.c: hack some Debug messages to use the new name
+       conversion routines in ircd_events.c; add an extra assert for a
+       condition that shouldn't ever happen; apparently recv() can return
+       EAGAIN when poll() returns readable--I wonder why...
+
+       * include/ircd_events.h: declare some helper routines under
+       DEBUGMODE
+
+2001-05-23  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_bsd.c (client_sock_callback): add an extra assertion
+       check
+
+       * ircd/s_auth.c: add more Debug messages
+
+       * ircd/list.c (make_client): add an extra assertion check
+
+       * ircd/ircd_events.c (socket_events): don't call the engine events
+       changer if we haven't actually made any changes to the event mask
+
+       * ircd/uping.c: add some Debug messages
+
+       * ircd/s_stats.c: document new /STATS e
+
+       * ircd/s_err.c: add RPL_STATSENGINE to report the engine name
+
+       * ircd/s_bsd.c: remove static client_timer variable; in
+       read_packet(), if there's still data in the client's recvQ after
+       parsing, add a 2 second timer (con_proc); fix the ET_DESTROY case
+       of client_sock_callback to handle destroying the timer properly;
+       rewrote client_timer_callback from scratch to be called on an
+       individual client
+
+       * ircd/m_stats.c: add /STATS e to report the engine name
+
+       * ircd/list.c: deal with con_timer field in struct Connection
+       properly; correct a core-level bug in remove_client_from_list--if
+       the client is the only one in the list, we try to update
+       GlobalClientList's cli_prev pointer--not good
+
+       * ircd/ircd.c: remove call to init_client_timer()
+
+       * ircd/engine_poll.c: made Debug messages more uniform by
+       prepending "poll:" to them all; corrected an off-by-one error that
+       caused poll_count to be 1 less than the actual count and removed
+       my work-around; added Debug messages to indicate which socket is
+       being checked and what the results are
+
+       * ircd/Makefile.in: ran a make depend
+
+       * include/s_bsd.h: remove init_client_timer(), since we're doing
+       it differently now
+
+       * include/numeric.h (RPL_STATSENGINE): a stats reply to report the
+       engine name
+
+       * include/ircd_policy.h (HEAD_IN_SAND_STATS_E): turn off /stats e
+       reports for non-opers
+
+       * include/client.h: add con_timer and con_proc fields to struct
+       Connection and define accessor macros--con_timer marks that
+       con_proc contains a valid timer, and con_proc is used to pace user
+       data
+
+       * ircd/s_bsd.c (close_connection): let free_client() destroy the
+       socket
+
+       * ircd/s_auth.c (start_auth): add a Debug call to indicate when
+       auth has begun on a client
+
+       * ircd/ircd_events.c: ensure that event_execute() is called with a
+       non-NULL event; modify event_add() macro to properly zero list
+       bits; modify gen_dequeue() to not try to clip it out of a list
+       it's already been clipped out of; change signal socket
+       initialization to use state SS_NOTSOCK; permit timeout values of
+       0 in add_timer(); add many Debug calls; change socket_del() and
+       timer_del() to always set the GEN_DESTROY flag; use GEN_MARKED in
+       timer_run() instead of GEN_DESTROY so that event_generate() will
+       pass on the events; remove the switch and replace with a simpler
+       if-then-else tree in timer_run(); don't allow destroyed sockets to
+       be destroyed again, nor their states or event masks to be changed
+
+       * ircd/ircd.c: initialize "running" to 1
+
+       * ircd/engine_poll.c: deal with SS_NOTSOCK "sockets"; add Debug
+       messages all over the place; fix a counting problem in
+       engine_add(); turn wait into a signed integer and set it to -1
+       only if timer_next() returns 0; adjust wait time to be relative;
+       don't call gen_ref_dec() if socket disappeared while we were
+       processing it
+
+       * include/ircd_events.h: the pipe for signals is not a socket, so
+       we must mark it as such--added SS_NOTSOCK for that special socket;
+       events won't be generated if GEN_DESTROY is on, so add GEN_MARKED
+       for the benefit of timer_run()
+
+       * configure.in: add --enable-pedantic and --enable-warnings to
+       turn on (and off) -Wall -pedantic in CFLAGS
+
 2001-05-21  Kevin L. Mitchell  <klmitch@mit.edu>
 
        * ircd/s_conf.c: change "s_addr" element accesses to "address"
        * include/s_conf.h: on some systems, "s_addr" is a macro; use
        "address" instead
 
+2001-05-18  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/engine_kqueue.c: include ircd_alloc.h; set_or_clear returns
+       void in this file; add a missing semi-colon; declare errcode,
+       codesize
+
+       * ircd/uping.c (uping_sender_callback): it's pptr, not uping
+
+       * ircd/s_user.c (register_user): comment out spurious reference to
+       nextping
+
+       * ircd/s_serv.c (server_estab): comment out spurious reference to
+       nextping
+
+       * ircd/s_conf.c (read_configuration_file): comment out spurious
+       reference to nextping and nextconnect
+
+       * ircd/s_bsd.c: comment out some spurious references to formerly
+       global (now non-existant) variables; correct a couple of typos
+
+       * ircd/s_auth.c: pre-declare some functions referenced in the
+       callback; correct a typo
+
+       * ircd/res.c (start_resolver): pass errno value of ENFILE
+
+       * ircd/listener.c (accept_connection): you know your API is messed
+       up when...variables that shouldn't have been global crop up in
+       other files
+
+       * ircd/list.c (free_client): substitution of == for =
+
+       * ircd/ircd_signal.c: include assert.h for assertion checking;
+       check ev_data() to find out what signal generated event
+
+       * ircd/ircd_events.c: some references to the variable "timer"
+       should have been references to the variable "ptr"
+
+       * ircd/engine_select.c: it's struct fd_set, not struct fdset;
+       ev_timer(ev) is already a timer pointer; declare codesize as a
+       size_t to correct signedness issue; use timer_next(), not
+       time_next()
+
+       * ircd/engine_poll.c: ev_timer(ev) is already a timer pointer;
+       select fd out of struct pollfd in assertion checking; declare
+       errcode and codesize; use timer_next(), not time_next()
+
+       * ircd/engine_kqueue.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/engine_devpoll.c: ev_timer(ev) is already a timer pointer;
+       use function timer_next(), not time_next()
+
+       * ircd/Makefile.in (IRCD_SRC): add ircd_events.c to the list of
+       compiled sources; do make depend
+
+       * include/list.h: pre-declare struct Connection
+
+       * include/ircd_events.h (gen_ref_inc): cast to the right structure
+       name
+
+       * include/s_auth.h: duh; missing */
+
+2001-05-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/send.c: update write events status after sending data or
+       accumulating data to be sent
+
+       * ircd/m_list.c (m_list): update write events status after
+       canceling a running /list
+
+       * ircd/channel.c (list_next_channels): update write events status
+       after listing a few channels
+
+       * ircd/s_bsd.c: extensive changes to update to new events model;
+       remove on_write_unblocked() and the two implementations of
+       read_message(), which have been deprecated by this change
+
+       * ircd/s_auth.c: set the socket events we're interested in for
+       clients; simplify some logic that does the connect_nonb followed
+       by the socket_add
+
+       * ircd/list.c: define free_connection() to free a connection
+       that's become freeable once the struct Socket has been
+       deallocated; fix up free_client() to take this new behavior into
+       account
+
+       * ircd/ircd.c: call init_client_timer()
+
+       * include/s_bsd.h: declare new REGISTER_ERROR_MESSAGE when unable
+       to register connect-in-progress with events system; declare
+       init_client_timer() (HACK!) to preserve rate-limiting behavior
+
+       * include/list.h: declare new free_connection()
+
+       * include/client.h: add a struct Socket to struct Connection
+
+2001-05-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_signal.c: massage the handlers for SIGHUP, SIGINT, and
+       SIGTERM into event callbacks; perform the actions in the
+       callbacks, since they're not called in the context of the signal;
+       set up the signal callbacks in the event engine
+
+       * ircd/ircd_events.c (signal_callback): we're supposed to look for
+       a specific signal; don't generate an event if there is no signal
+       structure for it
+
+       * ircd/ircd.c: nuke nextconnect and nextping and replace them with
+       connect_timer and ping_timer; massage try_connections() and
+       check_pings() into timer callbacks that re-add themselves at the
+       right time; remove ircd.c's "event_loop()"; initialize the event
+       system and the connect_timer and ping_timer
+
+       * ircd/uping.c: correct a couple more typos
+
+       * ircd/s_auth.c: rework to use new events system
+
+       * ircd/os_solaris.c (os_connect_nonb): update to new interface
+
+       * ircd/os_openbsd.c (os_connect_nonb): update to new interface
+
+       * ircd/os_linux.c (os_connect_nonb): update to new interface
+
+       * ircd/os_generic.c (os_connect_nonb): update to new interface
+
+       * ircd/os_bsd.c (os_connect_nonb): update to new interface
+
+       * include/s_auth.h: remove deprecated members of struct
+       AuthRequest, replacing them with struct Socket and struct Timer
+       structures; add flags to indicate when these structures have been
+       released by the event system; remove the deprecated
+       timeout_auth_queries()
+
+       * include/ircd_osdep.h (os_connect_nonb): connect could complete
+       immediately, so change the interface to handle that possibility
+
+       * ircd/uping.c (uping_server): noticed and corrected a typo
+
+       * ircd/listener.c: set up to use ircd_event's struct Socket by
+       adding an socket_add() call to inetport(), replacing
+       free_listener() with socket_del() in close_listener(), and
+       reworking accept_connection to be called as the callback
+
+       * ircd/ircd.c: add a call to IPcheck_init()
+
+       * ircd/IPcheck.c: remove IPcheck_expire(); rework
+       ip_registry_expire() to be called from a timer; write
+       IPcheck_init() to set up the expiration timer (hard-coded for a
+       60-second expiration time)
+
+       * include/listener.h: add a struct Socket to the struct Listener;
+       remove accept_connection()
+
+       * include/IPcheck.h: add IPcheck_init(), remove IPcheck_expire()
+
+2001-05-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include config.h; use USE_KQUEUE and
+       USE_DEVPOLL instead of HAVE_KQUEUE and HAVE_DEVPOLL_H
+
+       * ircd/engine_select.c: include config.h; set FD_SETSIZE to
+       MAXCONNECTIONS, not IRCD_FD_SETSIZE...
+
+       * ircd/engine_poll.c: include config.h
+
+       * ircd/engine_kqueue.c: include config.h
+
+       * ircd/engine_devpoll.c: include config.h
+
+       * ircd/Makefile.in: include engine sources in compilation and make
+       depend steps
+
+       * configure.in: add checks for enabling the /dev/poll- and
+       kqueue-based engines
+
+       * acconfig.h: add lines for USE_DEVPOLL and USE_KQUEUE
+
+       * ircd/Makefile.in: work in the engine sources
+
 2001-05-07  Kevin L. Mitchell  <klmitch@mit.edu>
 
        * ircd/m_settime.c: include ircd_snprintf.h
        * ircd/send.c (sendcmdto_flag_butone): if FLAGS_OPER is or'd with
        flag, send only to appropriate opers
 
+2001-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/uping.c: refit to use the new events interface
+
+       * ircd/res.c: refit to use the new events interface
+
+       * ircd/ircd_events.c: create timer_chg(), which permits a
+       (non-periodic) timer's expire time to be modified; change the
+       logic in timer_run() so that timers that were re-added while the
+       event was being processed will not be destroyed prematurely
+
+       * include/uping.h: include the events header, declare some extra
+       fields in struct UPing, remove timeout value, and define some
+       flags for marking which cleanup items have yet to be done
+
+       * include/ircd_events.h: add a prototype for timer_chg() to change
+       the expire time of a running timer
+
 2001-03-13 Joseph Bongaarts <foxxe@wtfs.net>
        * ircd/os_openbsd.c: Tweaked the openbsd hack a bit.
        
 
        * ircd/ircd_features.c: default LOCOP_KILL to TRUE--oops...
 
+2001-01-16  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c (timer_run): it's possible that the timer got
+       deleted during the callback processing, so don't go to the bother
+       of requeuing it if the destroy flag is set
+
+       * ircd/engine_select.c: define FD_SETSIZE to be IRCD_FD_SETSIZE
+       out of config.h if this is a *BSD; include errno.h (oops);
+       decrement error count after an hour using a timer; use FD_SETSIZE
+       constant instead of IRCD_FD_SETSIZE constant; fill in event
+       processing code
+
+       * ircd/engine_poll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
+       * ircd/engine_kqueue.c: include errno.h (oops); decrement error
+       count after an hour using a timer; assert events filter is either
+       EVFILT_READ or EVFILT_WRITE; fill in event processing code
+
+       * ircd/engine_devpoll.c: include errno.h (oops); decrement error
+       count after an hour using a timer; fill in event processing code
+
 2001-01-15  Kevin L. Mitchell  <klmitch@mit.edu>
 
        * ircd/client.c: fixed feattab; basically, when I changed features
        privileges together; also fixed a bug in the antiprivs masking
        loop in client_set_privs()--last index wouldn't get parsed
 
+2001-01-11  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: call event_generate() with new data
+       argument; make it set that field in struct Event; make
+       socket_add() return the value of the eng_add callback
+
+       * ircd/engine_select.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_poll.c: make engine_add() return a
+       successful/unsuccessful status; add bounds-checking outside of an
+       assert; use accessor macros; use log_write(), not the deprecated
+       ircd_log(); add an assert to engine_loop() to double-check for
+       data structure corruption
+
+       * ircd/engine_kqueue.c: implementation of an engine for kqueue()
+
+       * ircd/engine_devpoll.c: implementation of an engine for /dev/poll
+
+       * include/ircd_events.h: define some accessor macros; add ev_data
+       to struct Event for certain important data--errno values, for
+       instance; make EngineAdd callback tell us if it was successful or
+       not; add extra argument to event_generate(); make socket_add()
+       return the status from EngineAdd
+
+2001-01-10  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: pass initializer information about how many
+       total _filedescriptors_ may be opened at once
+
+       * ircd/ircd.c: use exported "running" instead of unexported
+       thisServer.running
+
+       * ircd/engine_select.c: implementation of an event engine based on
+       select()
+
+       * ircd/engine_poll.c: implementation of an event engine based on
+       poll()
+
+       * include/ircd_events.h: pass the engine initializer an integer
+       specifing how many _filedescriptors_ may be opened at once
+
+       * include/ircd.h: running has to be exported for the engine_*
+       event loops
+
+2001-01-09  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_events.c: include some needed headers; add some
+       comments; make evEngines[] const; bundle sig_sock and sig_fd into
+       a struct named sigInfo; rework struct evInfo to have a queue of
+       _generators_, and only when threaded; added a gen_init() function
+       to centralize generator initialization; fix various compile-time
+       errors; rework event_add() for new queueing scheme and checked for
+       compile-time errors; add casts where needed; spell evEngines[]
+       correctly; make engine_name() return const char*
+
+       * include/ircd_events.h: type EventCallBack depends on struct
+       Event, so pre-declare it; put _event_ queue into generators, and
+       only when threaded; give engine data a union to store both ints
+       and pointers; make engine name a const; fix gen_ref_dec() macro;
+       make engine_name() return a const char*
+
+       * ircd/ircd_events.c: gen_dequeue() is now exported, so move it
+       down with the non-static functions; modify event_execute() to use
+       the new gen_ref_dec() to simplify code; make sure event_generate()
+       does not generate new events for generators marked for destruction
+
+       * include/ircd_events.h: the engines, at least, may need to modify
+       reference counts to keep generators from going away while
+       something still points at them, so add reference counter
+       manipulators and export gen_dequeue() for them
+
+       * ircd/ircd_events.c: set up the list of engines to try; set up
+       the signal struct Socket; rename netInfo to evInfo; move static
+       functions near the beginning of the file; do away with
+       signal_signal() (since we no longer keep a signal count ourselves)
+       and call event_generate() directly from signal_callback--also
+       renamed some functions; allow signal_callback() to read up to
+       SIGS_PER_SOCK at once from the signal pipe; add event_init() to
+       initialize the entire event system; add event_loop() to call the
+       engine's event loop; initialize new struct GenHeader member,
+       gh_engdata; remove timer_next(); add socket_add() function to add
+       a socket; add socket_del() to mark a socket for deletion; add
+       socket_state() to transition a socket between states; add
+       socket_events() to set what events we're interested in on the
+       socket; add engine_name() to retrieve event engine's name
+
+       * include/ircd_events.h: add engine data field to struct
+       GenHeader; rename SOCK_ACTION_REMOVE to SOCK_ACTION_DEL; add a
+       note about states vs s_events; remove signal count; fold union
+       Generator back into struct Event; remove count members from struct
+       Generators; redefine engine callbacks to not take a struct
+       Engine*; add explanatory comments to callback definitions; add
+       some engine callbacks to handle operations; remove struct Engine
+       flag member--can detect single flag from eng_signal member; add
+       event_init(), event_loop(), engine_name(), and the socket_*()
+       functions; make timer_next() a macro to avoid a function call
+
+2001-01-08  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * include/ircd_events.h: rename to ircd_events.h, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+       * ircd/ircd_events.c: rename to ircd_events.c, since it handles
+       events, not just networking stuff; add signal support; more
+       structural rearrangement
+
+2001-01-07  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: implement timer API; add reference counts
+       appropriately
+
+       * include/ircd_network.h: firm up some pieces of the interface;
+       split out members everything has into a separate structure; add
+       reference counts; add timer API
+
+2001-01-06  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/ircd_network.c: static data and event manipulation
+       functions for new event processing system
+
+       * include/ircd_network.h: data structures for new event processing
+       system
+
 2001-01-03  Kevin L. Mitchell  <klmitch@mit.edu>
 
        * ircd/whowas.c: Completely re-did the old allocation scheme by
index 6242806cf121dcda46c49482ac9449f191dc9a6a..de339b4e23c134818503febb68c79702ed55126d 100644 (file)
@@ -155,4 +155,3 @@ vous avez des probl
 définissent DEBUGMODE. Recompiler l'ircd, et metez-le Ã  la main comme: ircd
 - t - x9. Ceci Ã©crira un point la sortie Ã  votre Ã©cran, montrant
 probablement pourquoi il ne commence pas.
-
index 4e17c49fff2688221f40d8f7bf6575b0c1f0f177..1c5df59f31c59cd69f077cff0d80fbb8f668008e 100644 (file)
@@ -140,4 +140,4 @@ more than 4096 IP's in 60s it warns 'dst cache overflow'.  This limit can be
 changed by modifying /proc/sys/net/ipv4/route/max_size.
 
 A patch to select is also recommended if you have regular poll/select
-errors.
\ No newline at end of file
+errors.
index 2d0fcf40492dc58c9b9d159c8f9c22ad5c908d63..5b6d248e36d5bb0a96e2cc61330fada62fc00016 100644 (file)
 
 /* Define to force the poll() function to be used */
 #undef USE_POLL
+/* Define to enable the /dev/poll engine */
+#undef USE_DEVPOLL
+/* Define to enable the kqueue engine */
+#undef USE_KQUEUE
 
 /* Define to enable various debugging code in the server; DO NOT USE
  * THIS ON PRODUCTION SERVERS ON PAIN OF DELINKING!
index 3b2499c0ff3f710b6af38e468141e14f90babb5a..3880424c0f62bfc178dda0a985fee3f79695060b 100644 (file)
@@ -19,7 +19,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: config.h.in,v 1.1 2001-05-07 21:21:17 kev Exp $
+ * $Id: config.h.in,v 1.2 2001-06-07 00:29:46 kev Exp $
  */
 
 /* Define to `int' if <sys/types.h> doesn't define.  */
 /* Define if you have the <poll.h> header file.  */
 #undef HAVE_POLL_H
 
+/* Define if you have the <sys/devpoll.h> header file.  */
+#undef HAVE_SYS_DEVPOLL_H
+
+/* Define if you have the <sys/event.h> header file.  */
+#undef HAVE_SYS_EVENT_H
+
 /* Define if you have the nsl library (-lnsl).  */
 #undef HAVE_LIBNSL
 
 /* Force inlining for a few critical functions */
 #undef FORCEINLINE
 
+/* Define to enable the /dev/poll engine */
+#undef USE_DEVPOLL
+
+/* Define to enable the kqueue engine */
+#undef USE_KQUEUE
+
 /* Domain name to be used for some statistics gathering */
 #undef DOMAINNAME
 
index 0ad2cdf9198f586fc02f658c89911ac381358c5e..8b84aa8d61eb8f3909079b033b35bdcec62c0fa2 100755 (executable)
--- a/configure
+++ b/configure
@@ -23,8 +23,16 @@ ac_help="$ac_help
   --disable-symbols       Disable debugging symbols (remove -g from CFLAGS)"
 ac_help="$ac_help
   --enable-profile        Enable profiling support (add -pg to CFLAGS)"
+ac_help="$ac_help
+  --enable-pedantic       Enable pedantic warnings (add -pedantic to CFLAGS)"
+ac_help="$ac_help
+  --enable-warnings       Enable warnings (add -Wall to CFLAGS)"
 ac_help="$ac_help
   --disable-inlines       Disable inlining for a few critical functions"
+ac_help="$ac_help
+  --enable-devpoll        Enable the experimental /dev/poll-based engine"
+ac_help="$ac_help
+  --enable-kqueue         Enable the experimental kqueue-based engine"
 ac_help="$ac_help
   --with-symlink=name     Name to give the symlink; if name is "no," no
                           symlink will be created."
@@ -601,7 +609,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 fi
 
 echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:605: checking host system type" >&5
+echo "configure:613: checking host system type" >&5
 
 host_alias=$host
 case "$host_alias" in
@@ -625,7 +633,7 @@ echo "$ac_t""$host" 1>&6
 # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:629: checking for $ac_word" >&5
+echo "configure:637: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -655,7 +663,7 @@ if test -z "$CC"; then
   # Extract the first word of "cc", so it can be a program name with args.
 set dummy cc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:659: checking for $ac_word" >&5
+echo "configure:667: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -706,7 +714,7 @@ fi
       # Extract the first word of "cl", so it can be a program name with args.
 set dummy cl; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:710: checking for $ac_word" >&5
+echo "configure:718: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -738,7 +746,7 @@ fi
 fi
 
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:742: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 
 ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -749,12 +757,12 @@ cross_compiling=$ac_cv_prog_cc_cross
 
 cat > conftest.$ac_ext << EOF
 
-#line 753 "configure"
+#line 761 "configure"
 #include "confdefs.h"
 
 main(){return(0);}
 EOF
-if { (eval echo configure:758: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:766: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   ac_cv_prog_cc_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
@@ -780,12 +788,12 @@ if test $ac_cv_prog_cc_works = no; then
   { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
 fi
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:784: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:792: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:789: checking whether we are using GNU C" >&5
+echo "configure:797: checking whether we are using GNU C" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -794,7 +802,7 @@ else
   yes;
 #endif
 EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:798: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:806: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gcc=yes
 else
   ac_cv_prog_gcc=no
@@ -813,7 +821,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
 ac_save_CFLAGS="$CFLAGS"
 CFLAGS=
 echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:817: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:825: checking whether ${CC-cc} accepts -g" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -849,7 +857,7 @@ fi
 
 
 echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
-echo "configure:853: checking for ${CC-cc} option to accept ANSI C" >&5
+echo "configure:861: checking for ${CC-cc} option to accept ANSI C" >&5
 if eval "test \"`echo '$''{'am_cv_prog_cc_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -865,7 +873,7 @@ for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__
 do
   CC="$ac_save_CC $ac_arg"
   cat > conftest.$ac_ext <<EOF
-#line 869 "configure"
+#line 877 "configure"
 #include "confdefs.h"
 #include <stdarg.h>
 #include <stdio.h>
@@ -902,7 +910,7 @@ return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
 
 ; return 0; }
 EOF
-if { (eval echo configure:906: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:914: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   am_cv_prog_cc_stdc="$ac_arg"; break
 else
@@ -947,18 +955,34 @@ if test x"$CFLAGS" != x"$unet_old_cflags"; then
     # If -pg was already there, force profiling to be enabled
     unet_cv_enable_profile=yes
 fi
+if test x"$CFLAGS" != x; then
+    unet_old_cflags=$CFLAGS
+    CFLAGS=`echo "$CFLAGS" | sed -e 's/-Wall//g'`
+fi
+if test x"$CFLAGS" != x"$unet_old_cflags"; then
+    # If -Wall was already there, force warnings to be enabled
+    unet_cv_enable_warnings=yes
+fi
+if test x"$CFLAGS" != x; then
+    unet_old_cflags=$CFLAGS
+    CFLAGS=`echo "$CFLAGS" | sed -e 's/-pedantic//g'`
+fi
+if test x"$CFLAGS" != x"$unet_old_cflags"; then
+    # If -pedantic was already there, force pedatic to be enabled
+    unet_cv_enable_pedantic=yes
+fi
 
 
 
 echo $ac_n "checking for library containing crypt""... $ac_c" 1>&6
-echo "configure:955: checking for library containing crypt" >&5
+echo "configure:979: checking for library containing crypt" >&5
 if eval "test \"`echo '$''{'ac_cv_search_crypt'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_func_search_save_LIBS="$LIBS"
 ac_cv_search_crypt="no"
 cat > conftest.$ac_ext <<EOF
-#line 962 "configure"
+#line 986 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -969,7 +993,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:973: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:997: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_search_crypt="none required"
 else
@@ -980,7 +1004,7 @@ rm -f conftest*
 test "$ac_cv_search_crypt" = "no" && for i in descrypt crypt; do
 LIBS="-l$i  $ac_func_search_save_LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 984 "configure"
+#line 1008 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -991,7 +1015,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:995: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_search_crypt="-l$i"
 break
@@ -1016,12 +1040,12 @@ fi
    # Most operating systems have gethostbyname() in the default searched
    # libraries (i.e. libc):
    echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
-echo "configure:1020: checking for gethostbyname" >&5
+echo "configure:1044: checking for gethostbyname" >&5
 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1025 "configure"
+#line 1049 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char gethostbyname(); below.  */
@@ -1044,7 +1068,7 @@ gethostbyname();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1048: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_gethostbyname=yes"
 else
@@ -1063,7 +1087,7 @@ else
   echo "$ac_t""no" 1>&6
 # Some OSes (eg. Solaris) place it in libnsl:
      echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
-echo "configure:1067: checking for gethostbyname in -lnsl" >&5
+echo "configure:1091: checking for gethostbyname in -lnsl" >&5
 ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1071,7 +1095,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lnsl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1075 "configure"
+#line 1099 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1082,7 +1106,7 @@ int main() {
 gethostbyname()
 ; return 0; }
 EOF
-if { (eval echo configure:1086: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1110: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1109,7 +1133,7 @@ else
   echo "$ac_t""no" 1>&6
 # Some strange OSes (SINIX) have it in libsocket:
        echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
-echo "configure:1113: checking for gethostbyname in -lsocket" >&5
+echo "configure:1137: checking for gethostbyname in -lsocket" >&5
 ac_lib_var=`echo socket'_'gethostbyname | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1117,7 +1141,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1121 "configure"
+#line 1145 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1128,7 +1152,7 @@ int main() {
 gethostbyname()
 ; return 0; }
 EOF
-if { (eval echo configure:1132: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1156: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1157,7 +1181,7 @@ else
           # AC_CHECK_LIB's API is essentially broken so the following
           # ugliness is necessary:
           echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
-echo "configure:1161: checking for gethostbyname in -lsocket" >&5
+echo "configure:1185: checking for gethostbyname in -lsocket" >&5
 ac_lib_var=`echo socket'_'gethostbyname | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1165,7 +1189,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket -lnsl $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1169 "configure"
+#line 1193 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1176,7 +1200,7 @@ int main() {
 gethostbyname()
 ; return 0; }
 EOF
-if { (eval echo configure:1180: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1204: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1195,7 +1219,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6
-echo "configure:1199: checking for gethostbyname in -lresolv" >&5
+echo "configure:1223: checking for gethostbyname in -lresolv" >&5
 ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1203,7 +1227,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lresolv  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1207 "configure"
+#line 1231 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1214,7 +1238,7 @@ int main() {
 gethostbyname()
 ; return 0; }
 EOF
-if { (eval echo configure:1218: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1242: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1253,12 +1277,12 @@ fi
 fi
 
   echo $ac_n "checking for socket""... $ac_c" 1>&6
-echo "configure:1257: checking for socket" >&5
+echo "configure:1281: checking for socket" >&5
 if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1262 "configure"
+#line 1286 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char socket(); below.  */
@@ -1281,7 +1305,7 @@ socket();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1285: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1309: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_socket=yes"
 else
@@ -1299,7 +1323,7 @@ if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
-echo "configure:1303: checking for socket in -lsocket" >&5
+echo "configure:1327: checking for socket in -lsocket" >&5
 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1307,7 +1331,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1311 "configure"
+#line 1335 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1318,7 +1342,7 @@ int main() {
 socket()
 ; return 0; }
 EOF
-if { (eval echo configure:1322: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1346: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1344,7 +1368,7 @@ EOF
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
-echo "configure:1348: checking for socket in -lsocket" >&5
+echo "configure:1372: checking for socket in -lsocket" >&5
 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1352,7 +1376,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket -lnsl $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1356 "configure"
+#line 1380 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1363,7 +1387,7 @@ int main() {
 socket()
 ; return 0; }
 EOF
-if { (eval echo configure:1367: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1391: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1391,14 +1415,14 @@ fi
 
 
 echo $ac_n "checking for library containing res_mkquery""... $ac_c" 1>&6
-echo "configure:1395: checking for library containing res_mkquery" >&5
+echo "configure:1419: checking for library containing res_mkquery" >&5
 if eval "test \"`echo '$''{'ac_cv_search_res_mkquery'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_func_search_save_LIBS="$LIBS"
 ac_cv_search_res_mkquery="no"
 cat > conftest.$ac_ext <<EOF
-#line 1402 "configure"
+#line 1426 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1409,7 +1433,7 @@ int main() {
 res_mkquery()
 ; return 0; }
 EOF
-if { (eval echo configure:1413: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1437: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_search_res_mkquery="none required"
 else
@@ -1420,7 +1444,7 @@ rm -f conftest*
 test "$ac_cv_search_res_mkquery" = "no" && for i in resolv; do
 LIBS="-l$i  $ac_func_search_save_LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1424 "configure"
+#line 1448 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1431,7 +1455,7 @@ int main() {
 res_mkquery()
 ; return 0; }
 EOF
-if { (eval echo configure:1435: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_search_res_mkquery="-l$i"
 break
@@ -1453,7 +1477,7 @@ else :
 fi
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1457: checking how to run the C preprocessor" >&5
+echo "configure:1481: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -1468,13 +1492,13 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 1472 "configure"
+#line 1496 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1478: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1502: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1485,13 +1509,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 1489 "configure"
+#line 1513 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1495: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1519: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1502,13 +1526,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -nologo -E"
   cat > conftest.$ac_ext <<EOF
-#line 1506 "configure"
+#line 1530 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1512: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1536: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1533,12 +1557,12 @@ fi
 echo "$ac_t""$CPP" 1>&6
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1537: checking for ANSI C header files" >&5
+echo "configure:1561: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1542 "configure"
+#line 1566 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1546,7 +1570,7 @@ else
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1550: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1574: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1563,7 +1587,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1567 "configure"
+#line 1591 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1581,7 +1605,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1585 "configure"
+#line 1609 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1602,7 +1626,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1606 "configure"
+#line 1630 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1613,7 +1637,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 exit (0); }
 
 EOF
-if { (eval echo configure:1617: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1641: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -1636,21 +1660,21 @@ EOF
 
 fi
 
-for ac_hdr in poll.h
+for ac_hdr in poll.h sys/devpoll.h sys/event.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1644: checking for $ac_hdr" >&5
+echo "configure:1668: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1649 "configure"
+#line 1673 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1654: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1678: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1678,14 +1702,14 @@ done
 
 
 echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1682: checking whether byte ordering is bigendian" >&5
+echo "configure:1706: checking whether byte ordering is bigendian" >&5
 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_cv_c_bigendian=unknown
 # See if sys/param.h defines the BYTE_ORDER macro.
 cat > conftest.$ac_ext <<EOF
-#line 1689 "configure"
+#line 1713 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1696,11 +1720,11 @@ int main() {
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:1700: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1724: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   # It does; now see whether it defined to BIG_ENDIAN or not.
 cat > conftest.$ac_ext <<EOF
-#line 1704 "configure"
+#line 1728 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1711,7 +1735,7 @@ int main() {
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:1715: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1739: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_bigendian=yes
 else
@@ -1731,7 +1755,7 @@ if test "$cross_compiling" = yes; then
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1735 "configure"
+#line 1759 "configure"
 #include "confdefs.h"
 main () {
   /* Are we little or big endian?  From Harbison&Steele.  */
@@ -1744,7 +1768,7 @@ main () {
   exit (u.c[sizeof (long) - 1] == 1);
 }
 EOF
-if { (eval echo configure:1748: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_bigendian=no
 else
@@ -1768,12 +1792,12 @@ EOF
 fi
 
 echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1772: checking for size_t" >&5
+echo "configure:1796: checking for size_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1777 "configure"
+#line 1801 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1801,12 +1825,12 @@ EOF
 fi
 
 echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:1805: checking whether time.h and sys/time.h may both be included" >&5
+echo "configure:1829: checking whether time.h and sys/time.h may both be included" >&5
 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1810 "configure"
+#line 1834 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/time.h>
@@ -1815,7 +1839,7 @@ int main() {
 struct tm *tp;
 ; return 0; }
 EOF
-if { (eval echo configure:1819: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1843: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_header_time=yes
 else
@@ -1836,12 +1860,12 @@ EOF
 fi
 
 echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
-echo "configure:1840: checking whether struct tm is in sys/time.h or time.h" >&5
+echo "configure:1864: checking whether struct tm is in sys/time.h or time.h" >&5
 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1845 "configure"
+#line 1869 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <time.h>
@@ -1849,7 +1873,7 @@ int main() {
 struct tm *tp; tp->tm_sec;
 ; return 0; }
 EOF
-if { (eval echo configure:1853: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1877: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_struct_tm=time.h
 else
@@ -1870,12 +1894,12 @@ EOF
 fi
 
 echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
-echo "configure:1874: checking for uid_t in sys/types.h" >&5
+echo "configure:1898: checking for uid_t in sys/types.h" >&5
 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1879 "configure"
+#line 1903 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 EOF
@@ -1904,7 +1928,7 @@ EOF
 fi
 
 echo $ac_n "checking size of short""... $ac_c" 1>&6
-echo "configure:1908: checking size of short" >&5
+echo "configure:1932: checking size of short" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1912,7 +1936,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1916 "configure"
+#line 1940 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1923,7 +1947,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1927: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1951: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_short=`cat conftestval`
 else
@@ -1943,7 +1967,7 @@ EOF
 
 
 echo $ac_n "checking size of int""... $ac_c" 1>&6
-echo "configure:1947: checking size of int" >&5
+echo "configure:1971: checking size of int" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1951,7 +1975,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1955 "configure"
+#line 1979 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1962,7 +1986,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1966: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_int=`cat conftestval`
 else
@@ -1982,7 +2006,7 @@ EOF
 
 
 echo $ac_n "checking size of long""... $ac_c" 1>&6
-echo "configure:1986: checking size of long" >&5
+echo "configure:2010: checking size of long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1990,7 +2014,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1994 "configure"
+#line 2018 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -2001,7 +2025,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:2005: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2029: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_long=`cat conftestval`
 else
@@ -2021,7 +2045,7 @@ EOF
 
 
 echo $ac_n "checking size of void *""... $ac_c" 1>&6
-echo "configure:2025: checking size of void *" >&5
+echo "configure:2049: checking size of void *" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_void_p'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2029,7 +2053,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2033 "configure"
+#line 2057 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -2040,7 +2064,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:2044: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2068: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_void_p=`cat conftestval`
 else
@@ -2061,12 +2085,12 @@ EOF
 
 if test "$ac_cv_sizeof_int" = 2 ; then
   echo $ac_n "checking for int16_t""... $ac_c" 1>&6
-echo "configure:2065: checking for int16_t" >&5
+echo "configure:2089: checking for int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2070 "configure"
+#line 2094 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2094,12 +2118,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6
-echo "configure:2098: checking for u_int16_t" >&5
+echo "configure:2122: checking for u_int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2103 "configure"
+#line 2127 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2128,12 +2152,12 @@ fi
 
 elif test "$ac_cv_sizeof_short" = 2 ; then
   echo $ac_n "checking for int16_t""... $ac_c" 1>&6
-echo "configure:2132: checking for int16_t" >&5
+echo "configure:2156: checking for int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2137 "configure"
+#line 2161 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2161,12 +2185,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6
-echo "configure:2165: checking for u_int16_t" >&5
+echo "configure:2189: checking for u_int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2170 "configure"
+#line 2194 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2198,12 +2222,12 @@ else
 fi
 if test "$ac_cv_sizeof_int" = 4 ; then
   echo $ac_n "checking for int32_t""... $ac_c" 1>&6
-echo "configure:2202: checking for int32_t" >&5
+echo "configure:2226: checking for int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2207 "configure"
+#line 2231 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2231,12 +2255,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
-echo "configure:2235: checking for u_int32_t" >&5
+echo "configure:2259: checking for u_int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2240 "configure"
+#line 2264 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2265,12 +2289,12 @@ fi
 
 elif test "$ac_cv_sizeof_short" = 4 ; then
   echo $ac_n "checking for int32_t""... $ac_c" 1>&6
-echo "configure:2269: checking for int32_t" >&5
+echo "configure:2293: checking for int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2274 "configure"
+#line 2298 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2298,12 +2322,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
-echo "configure:2302: checking for u_int32_t" >&5
+echo "configure:2326: checking for u_int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2307 "configure"
+#line 2331 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2332,12 +2356,12 @@ fi
 
 elif test "$ac_cv_sizeof_long" = 4 ; then
   echo $ac_n "checking for int32_t""... $ac_c" 1>&6
-echo "configure:2336: checking for int32_t" >&5
+echo "configure:2360: checking for int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2341 "configure"
+#line 2365 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2365,12 +2389,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
-echo "configure:2369: checking for u_int32_t" >&5
+echo "configure:2393: checking for u_int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2374 "configure"
+#line 2398 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2401,9 +2425,57 @@ else
   { echo "configure: error: Cannot find a type with size of 32 bits" 1>&2; exit 1; }
 fi
 
+echo $ac_n "checking for kqueue""... $ac_c" 1>&6
+echo "configure:2430: checking for kqueue" >&5
+if eval "test \"`echo '$''{'ac_cv_func_kqueue'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2435 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char kqueue(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char kqueue();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_kqueue) || defined (__stub___kqueue)
+choke me
+#else
+kqueue();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2458: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_kqueue=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_kqueue=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'kqueue`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
 
 echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6
-echo "configure:2407: checking for restartable system calls" >&5
+echo "configure:2479: checking for restartable system calls" >&5
 if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2411,7 +2483,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2415 "configure"
+#line 2487 "configure"
 #include "confdefs.h"
 /* Exit 0 (true) if wait returns something other than -1,
    i.e. the pid of the child, which means that wait was restarted
@@ -2429,7 +2501,7 @@ main () {
 }
 
 EOF
-if { (eval echo configure:2433: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2505: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sys_restartable_syscalls=yes
 else
@@ -2453,7 +2525,7 @@ fi
 
 
 echo $ac_n "checking for donuts""... $ac_c" 1>&6
-echo "configure:2457: checking for donuts" >&5
+echo "configure:2529: checking for donuts" >&5
 echo "$ac_t""yes" 1>&6
 
 for ac_prog in gawk mawk nawk awk
@@ -2461,7 +2533,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2465: checking for $ac_word" >&5
+echo "configure:2537: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2491,7 +2563,7 @@ test -n "$AWK" && break
 done
 
 echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:2495: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:2567: checking whether ${MAKE-make} sets \${MAKE}" >&5
 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -2529,7 +2601,7 @@ fi
 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 # ./install, which can be erroneously created by make from ./install.sh.
 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:2533: checking for a BSD compatible install" >&5
+echo "configure:2605: checking for a BSD compatible install" >&5
 if test -z "$INSTALL"; then
 if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -2582,7 +2654,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
 test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:2586: checking whether ln -s works" >&5
+echo "configure:2658: checking whether ln -s works" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2607,7 +2679,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2611: checking for $ac_word" >&5
+echo "configure:2683: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_RMPROG'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2648,7 +2720,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2652: checking for $ac_word" >&5
+echo "configure:2724: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_SHPROG'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2686,7 +2758,7 @@ test -n "$SHPROG" || SHPROG="/bin/sh"
 
 
 echo $ac_n "checking for posix non-blocking""... $ac_c" 1>&6
-echo "configure:2690: checking for posix non-blocking" >&5
+echo "configure:2762: checking for posix non-blocking" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_nonblocking_posix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2694,7 +2766,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2698 "configure"
+#line 2770 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -2720,7 +2792,7 @@ int main(void)
   exit(1);
 }
 EOF
-if { (eval echo configure:2724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2796: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_nonblocking_posix=yes
 else
@@ -2742,7 +2814,7 @@ EOF
 
 else
 echo $ac_n "checking for bsd non-blocking""... $ac_c" 1>&6
-echo "configure:2746: checking for bsd non-blocking" >&5
+echo "configure:2818: checking for bsd non-blocking" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_nonblocking_bsd'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2750,7 +2822,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2754 "configure"
+#line 2826 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -2776,7 +2848,7 @@ int main(void)
   exit(1);
 }
 EOF
-if { (eval echo configure:2780: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_nonblocking_bsd=yes
 else
@@ -2804,19 +2876,19 @@ EOF
 fi
 fi
 echo $ac_n "checking for posix signals""... $ac_c" 1>&6
-echo "configure:2808: checking for posix signals" >&5
+echo "configure:2880: checking for posix signals" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_signal_posix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2813 "configure"
+#line 2885 "configure"
 #include "confdefs.h"
 #include <signal.h>
 int main() {
 sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)
 ; return 0; }
 EOF
-if { (eval echo configure:2820: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2892: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   unet_cv_sys_signal_posix=yes
 else
@@ -2836,7 +2908,7 @@ EOF
 
 else
 echo $ac_n "checking for bsd reliable signals""... $ac_c" 1>&6
-echo "configure:2840: checking for bsd reliable signals" >&5
+echo "configure:2912: checking for bsd reliable signals" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_signal_bsd'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2844,7 +2916,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2848 "configure"
+#line 2920 "configure"
 #include "confdefs.h"
 #include <signal.h>
 int calls = 0;
@@ -2862,7 +2934,7 @@ int main(void)
   exit (0);
 }
 EOF
-if { (eval echo configure:2866: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2938: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_signal_bsd=yes
 else
@@ -2891,20 +2963,20 @@ fi
 fi
 
 echo $ac_n "checking if the compiler understands -pipe""... $ac_c" 1>&6
-echo "configure:2895: checking if the compiler understands -pipe" >&5
+echo "configure:2967: checking if the compiler understands -pipe" >&5
 unet_cv_pipe_flags="$ac_cv_prog_gcc"
 if test "$ac_cv_prog_gcc" = no; then
   OLDCFLAGS="$CFLAGS"
   CFLAGS="$CFLAGS -pipe"
   cat > conftest.$ac_ext <<EOF
-#line 2901 "configure"
+#line 2973 "configure"
 #include "confdefs.h"
 
 int main() {
 
 ; return 0; }
 EOF
-if { (eval echo configure:2908: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2980: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   unet_cv_pipe_flags=yes
 else
@@ -2924,7 +2996,7 @@ fi
 
 
 echo $ac_n "checking for OS-dependent information""... $ac_c" 1>&6
-echo "configure:2928: checking for OS-dependent information" >&5
+echo "configure:3000: checking for OS-dependent information" >&5
 case "$host" in
     *-linux*)
        echo "$ac_t""Linux ($host) found." 1>&6
@@ -2978,7 +3050,7 @@ esac
 
 
 echo $ac_n "checking whether to enable use of poll()""... $ac_c" 1>&6
-echo "configure:2982: checking whether to enable use of poll()" >&5
+echo "configure:3054: checking whether to enable use of poll()" >&5
 # Check whether --enable-poll or --disable-poll was given.
 if test "${enable_poll+set}" = set; then
   enableval="$enable_poll"
@@ -3005,10 +3077,14 @@ if test x"$unet_cv_enable_poll" = xyes; then
 #define USE_POLL 
 EOF
 
+    ENGINE_C=engine_poll.c
+else
+    ENGINE_C=engine_select.c
 fi
 
+
 echo $ac_n "checking whether to enable debug mode""... $ac_c" 1>&6
-echo "configure:3012: checking whether to enable debug mode" >&5
+echo "configure:3088: checking whether to enable debug mode" >&5
 # Check whether --enable-debug or --disable-debug was given.
 if test "${enable_debug+set}" = set; then
   enableval="$enable_debug"
@@ -3032,7 +3108,7 @@ EOF
 fi
 
 echo $ac_n "checking whether to enable asserts""... $ac_c" 1>&6
-echo "configure:3036: checking whether to enable asserts" >&5
+echo "configure:3112: checking whether to enable asserts" >&5
 # Check whether --enable-asserts or --disable-asserts was given.
 if test "${enable_asserts+set}" = set; then
   enableval="$enable_asserts"
@@ -3056,7 +3132,7 @@ EOF
 fi
 
 echo $ac_n "checking whether to enable debugging symbols""... $ac_c" 1>&6
-echo "configure:3060: checking whether to enable debugging symbols" >&5
+echo "configure:3136: checking whether to enable debugging symbols" >&5
 # Check whether --enable-symbols or --disable-symbols was given.
 if test "${enable_symbols+set}" = set; then
   enableval="$enable_symbols"
@@ -3077,7 +3153,7 @@ if test x"$unet_cv_enable_symbols" = xyes; then
 fi
 
 echo $ac_n "checking whether to enable profiling support (gprof)""... $ac_c" 1>&6
-echo "configure:3081: checking whether to enable profiling support (gprof)" >&5
+echo "configure:3157: checking whether to enable profiling support (gprof)" >&5
 # Check whether --enable-profile or --disable-profile was given.
 if test "${enable_profile+set}" = set; then
   enableval="$enable_profile"
@@ -3097,8 +3173,50 @@ if test x"$unet_cv_enable_profile" = xyes; then
     CFLAGS="-pg $CFLAGS"
 fi
 
+echo $ac_n "checking whether to enable pedantic compiler warnings""... $ac_c" 1>&6
+echo "configure:3178: checking whether to enable pedantic compiler warnings" >&5
+# Check whether --enable-pedantic or --disable-pedantic was given.
+if test "${enable_pedantic+set}" = set; then
+  enableval="$enable_pedantic"
+  unet_cv_enable_pedantic=$enable_pedantic
+else
+  if eval "test \"`echo '$''{'unet_cv_enable_pedantic'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  unet_cv_enable_pedantic=no
+fi
+
+fi
+
+echo "$ac_t""$unet_cv_enable_pedantic" 1>&6
+
+if test x"$unet_cv_enable_pedantic" = xyes; then
+    CFLAGS="-pedantic $CFLAGS"
+fi
+
+echo $ac_n "checking whether to enable compiler warnings""... $ac_c" 1>&6
+echo "configure:3199: checking whether to enable compiler warnings" >&5
+# Check whether --enable-warnings or --disable-warnings was given.
+if test "${enable_warnings+set}" = set; then
+  enableval="$enable_warnings"
+  unet_cv_enable_warnings=$enable_warnings
+else
+  if eval "test \"`echo '$''{'unet_cv_enable_warnings'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  unet_cv_enable_warnings=no
+fi
+
+fi
+
+echo "$ac_t""$unet_cv_enable_warnings" 1>&6
+
+if test x"$unet_cv_enable_warnings" = xyes; then
+    CFLAGS="-Wall $CFLAGS"
+fi
+
 echo $ac_n "checking whether to enable inlining for a few critical functions""... $ac_c" 1>&6
-echo "configure:3102: checking whether to enable inlining for a few critical functions" >&5
+echo "configure:3220: checking whether to enable inlining for a few critical functions" >&5
 # Check whether --enable-inlines or --disable-inlines was given.
 if test "${enable_inlines+set}" = set; then
   enableval="$enable_inlines"
@@ -3121,8 +3239,68 @@ EOF
 
 fi
 
+echo $ac_n "checking whether to enable the /dev/poll event engine""... $ac_c" 1>&6
+echo "configure:3244: checking whether to enable the /dev/poll event engine" >&5
+# Check whether --enable-devpoll or --disable-devpoll was given.
+if test "${enable_devpoll+set}" = set; then
+  enableval="$enable_devpoll"
+  unet_cv_enable_devpoll=$enable_devpoll
+else
+  if eval "test \"`echo '$''{'unet_cv_enable_devpoll'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  unet_cv_enable_devpoll=no
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_devpoll_h" = xno; then
+    unet_cv_enable_devpoll=no
+fi
+
+echo "$ac_t""$unet_cv_enable_devpoll" 1>&6
+
+if test x"$unet_cv_enable_devpoll" != xno; then
+    cat >> confdefs.h <<\EOF
+#define USE_DEVPOLL 
+EOF
+
+    ENGINE_C="engine_devpoll.c $ENGINE_C"
+fi
+
+echo $ac_n "checking whether to enable the kqueue event engine""... $ac_c" 1>&6
+echo "configure:3274: checking whether to enable the kqueue event engine" >&5
+# Check whether --enable-kqueue or --disable-kqueue was given.
+if test "${enable_kqueue+set}" = set; then
+  enableval="$enable_kqueue"
+  unet_cv_enable_kqueue=$enable_kqueue
+else
+  if eval "test \"`echo '$''{'unet_cv_enable_kqueue'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  unet_cv_enable_kqueue=no
+fi
+
+fi
+
+
+if test x"$ac_cv_header_sys_event_h" = xno -o x"$ac_cv_func_kqueue" = xno; then
+    unet_cv_enable_kqueue=no
+fi
+
+echo "$ac_t""$unet_cv_enable_kqueue" 1>&6
+
+if test x"$unet_cv_enable_kqueue" != xno; then
+    cat >> confdefs.h <<\EOF
+#define USE_KQUEUE 
+EOF
+
+    ENGINE_C="engine_kqueue.c $ENGINE_C"
+fi
+
 echo $ac_n "checking what name to give the symlink""... $ac_c" 1>&6
-echo "configure:3126: checking what name to give the symlink" >&5
+echo "configure:3304: checking what name to give the symlink" >&5
 # Check whether --with-symlink or --without-symlink was given.
 if test "${with_symlink+set}" = set; then
   withval="$with_symlink"
@@ -3154,7 +3332,7 @@ fi
 
 
 echo $ac_n "checking what permissions to set on the installed binary""... $ac_c" 1>&6
-echo "configure:3158: checking what permissions to set on the installed binary" >&5
+echo "configure:3336: checking what permissions to set on the installed binary" >&5
 # Check whether --with-mode or --without-mode was given.
 if test "${with_mode+set}" = set; then
   withval="$with_mode"
@@ -3180,7 +3358,7 @@ IRCDMODE=$unet_cv_with_mode
 
 unet_uid=`id | sed -e 's/.*uid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
 echo $ac_n "checking which user should own the installed binary""... $ac_c" 1>&6
-echo "configure:3184: checking which user should own the installed binary" >&5
+echo "configure:3362: checking which user should own the installed binary" >&5
 # Check whether --with-owner or --without-owner was given.
 if test "${with_owner+set}" = set; then
   withval="$with_owner"
@@ -3206,7 +3384,7 @@ IRCDOWN=$unet_cv_with_owner
 
 unet_gid=`id | sed -e 's/.*gid=[0-9]*(//' -e 's/).*//' 2> /dev/null`
 echo $ac_n "checking which group should own the installed binary""... $ac_c" 1>&6
-echo "configure:3210: checking which group should own the installed binary" >&5
+echo "configure:3388: checking which group should own the installed binary" >&5
 # Check whether --with-group or --without-group was given.
 if test "${with_group+set}" = set; then
   withval="$with_group"
@@ -3238,7 +3416,7 @@ if test -f /etc/resolv.conf; then
     fi
 fi
 echo $ac_n "checking for site domain name""... $ac_c" 1>&6
-echo "configure:3242: checking for site domain name" >&5
+echo "configure:3420: checking for site domain name" >&5
 # Check whether --with-domain or --without-domain was given.
 if test "${with_domain+set}" = set; then
   withval="$with_domain"
@@ -3268,7 +3446,7 @@ EOF
 
 
 echo $ac_n "checking if chroot operation is desired""... $ac_c" 1>&6
-echo "configure:3272: checking if chroot operation is desired" >&5
+echo "configure:3450: checking if chroot operation is desired" >&5
 # Check whether --with-chroot or --without-chroot was given.
 if test "${with_chroot+set}" = set; then
   withval="$with_chroot"
@@ -3316,7 +3494,7 @@ prefix=$unet_save_prefix
 exec_prefix=$unet_save_exec_prefix
 
 echo $ac_n "checking where the binary will be for /restart""... $ac_c" 1>&6
-echo "configure:3320: checking where the binary will be for /restart" >&5
+echo "configure:3498: checking where the binary will be for /restart" >&5
 if test x"$unet_cv_with_symlink" = xno; then
     unet_spath="$unet_bindir/ircd"
 else
@@ -3338,7 +3516,7 @@ EOF
 
 
 echo $ac_n "checking what the data directory should be""... $ac_c" 1>&6
-echo "configure:3342: checking what the data directory should be" >&5
+echo "configure:3520: checking what the data directory should be" >&5
 # Check whether --with-dpath or --without-dpath was given.
 if test "${with_dpath+set}" = set; then
   withval="$with_dpath"
@@ -3381,7 +3559,7 @@ DPATH=$unet_cv_with_dpath
 
 
 echo $ac_n "checking where the default configuration file resides""... $ac_c" 1>&6
-echo "configure:3385: checking where the default configuration file resides" >&5
+echo "configure:3563: checking where the default configuration file resides" >&5
 # Check whether --with-cpath or --without-cpath was given.
 if test "${with_cpath+set}" = set; then
   withval="$with_cpath"
@@ -3423,7 +3601,7 @@ EOF
 
 
 echo $ac_n "checking where to put the debugging log if debugging enabled""... $ac_c" 1>&6
-echo "configure:3427: checking where to put the debugging log if debugging enabled" >&5
+echo "configure:3605: checking where to put the debugging log if debugging enabled" >&5
 # Check whether --with-lpath or --without-lpath was given.
 if test "${with_lpath+set}" = set; then
   withval="$with_lpath"
@@ -3469,7 +3647,7 @@ EOF
 unet_maxcon=`ulimit -Hn`
 unet_maxcon=`expr $unet_maxcon - 4`
 echo $ac_n "checking max connections""... $ac_c" 1>&6
-echo "configure:3473: checking max connections" >&5
+echo "configure:3651: checking max connections" >&5
 # Check whether --with-maxcon or --without-maxcon was given.
 if test "${with_maxcon+set}" = set; then
   withval="$with_maxcon"
@@ -3644,6 +3822,7 @@ s%@LN_S@%$LN_S%g
 s%@RMPROG@%$RMPROG%g
 s%@SHPROG@%$SHPROG%g
 s%@OSDEP_C@%$OSDEP_C%g
+s%@ENGINE_C@%$ENGINE_C%g
 s%@INSTALL_RULE@%$INSTALL_RULE%g
 s%@SYMLINK@%$SYMLINK%g
 s%@IRCDMODE@%$IRCDMODE%g
index 14b86d01edd79022b9a683d0d280b177ac4e18e0..07db11ff0a289331f77cf664a104a4f4943e2cc3 100644 (file)
@@ -76,6 +76,24 @@ if test x"$CFLAGS" != x"$unet_old_cflags"; then
     # If -pg was already there, force profiling to be enabled
     unet_cv_enable_profile=yes
 fi
+dnl Notice the -Wall flag and deal accordingly
+if test x"$CFLAGS" != x; then
+    unet_old_cflags=$CFLAGS
+    CFLAGS=`echo "$CFLAGS" | sed -e 's/-Wall//g'`
+fi
+if test x"$CFLAGS" != x"$unet_old_cflags"; then
+    # If -Wall was already there, force warnings to be enabled
+    unet_cv_enable_warnings=yes
+fi
+dnl Notice the -pedantic flag and deal accordingly
+if test x"$CFLAGS" != x; then
+    unet_old_cflags=$CFLAGS
+    CFLAGS=`echo "$CFLAGS" | sed -e 's/-pedantic//g'`
+fi
+if test x"$CFLAGS" != x"$unet_old_cflags"; then
+    # If -pedantic was already there, force pedatic to be enabled
+    unet_cv_enable_pedantic=yes
+fi
 
 dnl Checks for libraries.
 
@@ -93,7 +111,7 @@ AC_SEARCH_LIBS(res_mkquery, resolv, ,
 
 dnl Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS(poll.h)
+AC_CHECK_HEADERS(poll.h sys/devpoll.h sys/event.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics
 dnl AC_C_CONST
@@ -105,6 +123,7 @@ AC_TYPE_UID_T
 unet_CHECK_TYPE_SIZES
 
 dnl Checks for library functions.
+AC_CHECK_FUNC(kqueue)
 
 dnl Do we have restarting syscalls ?
 AC_SYS_RESTARTABLE_SYSCALLS
@@ -200,7 +219,11 @@ AC_MSG_RESULT([$unet_cv_enable_poll])
 
 if test x"$unet_cv_enable_poll" = xyes; then
     AC_DEFINE([USE_POLL], , [Specify whether or not to use poll()])
+    ENGINE_C=engine_poll.c
+else
+    ENGINE_C=engine_select.c
 fi
+AC_SUBST(ENGINE_C)
 
 dnl Now look for --enable-debug
 AC_MSG_CHECKING([whether to enable debug mode])
@@ -254,6 +277,32 @@ if test x"$unet_cv_enable_profile" = xyes; then
     CFLAGS="-pg $CFLAGS"
 fi
 
+dnl Now check for --enable-pedantic
+AC_MSG_CHECKING([whether to enable pedantic compiler warnings])
+AC_ARG_ENABLE([pedantic],
+[  --enable-pedantic       Enable pedantic warnings (add -pedantic to CFLAGS)],
+[unet_cv_enable_pedantic=$enable_pedantic],
+[AC_CACHE_VAL(unet_cv_enable_pedantic,
+[unet_cv_enable_pedantic=no])])
+AC_MSG_RESULT([$unet_cv_enable_pedantic])
+
+if test x"$unet_cv_enable_pedantic" = xyes; then
+    CFLAGS="-pedantic $CFLAGS"
+fi
+
+dnl Now check for --enable-warnings
+AC_MSG_CHECKING([whether to enable compiler warnings])
+AC_ARG_ENABLE([warnings],
+[  --enable-warnings       Enable warnings (add -Wall to CFLAGS)],
+[unet_cv_enable_warnings=$enable_warnings],
+[AC_CACHE_VAL(unet_cv_enable_warnings,
+[unet_cv_enable_warnings=no])])
+AC_MSG_RESULT([$unet_cv_enable_warnings])
+
+if test x"$unet_cv_enable_warnings" = xyes; then
+    CFLAGS="-Wall $CFLAGS"
+fi
+
 dnl --disable-inlines check...
 AC_MSG_CHECKING([whether to enable inlining for a few critical functions])
 AC_ARG_ENABLE([inlines],
@@ -267,6 +316,44 @@ if test x"$unet_cv_enable_inlines" = xyes; then
     AC_DEFINE([FORCEINLINE], , [Force inlining for a few critical functions])
 fi
 
+dnl --enable-devpoll check...
+AC_MSG_CHECKING([whether to enable the /dev/poll event engine])
+AC_ARG_ENABLE([devpoll],
+[  --enable-devpoll        Enable the experimental /dev/poll-based engine],
+[unet_cv_enable_devpoll=$enable_devpoll],
+[AC_CACHE_VAL(unet_cv_enable_devpoll,
+[unet_cv_enable_devpoll=no])])
+
+if test x"$ac_cv_header_sys_devpoll_h" = xno; then
+    unet_cv_enable_devpoll=no
+fi
+
+AC_MSG_RESULT([$unet_cv_enable_devpoll])
+
+if test x"$unet_cv_enable_devpoll" != xno; then
+    AC_DEFINE([USE_DEVPOLL], , [Define to enable the /dev/poll engine])
+    ENGINE_C="engine_devpoll.c $ENGINE_C"
+fi
+
+dnl --enable-kqueue check...
+AC_MSG_CHECKING([whether to enable the kqueue event engine])
+AC_ARG_ENABLE([kqueue],
+[  --enable-kqueue         Enable the experimental kqueue-based engine],
+[unet_cv_enable_kqueue=$enable_kqueue],
+[AC_CACHE_VAL(unet_cv_enable_kqueue,
+[unet_cv_enable_kqueue=no])])
+
+if test x"$ac_cv_header_sys_event_h" = xno -o x"$ac_cv_func_kqueue" = xno; then
+    unet_cv_enable_kqueue=no
+fi
+
+AC_MSG_RESULT([$unet_cv_enable_kqueue])
+
+if test x"$unet_cv_enable_kqueue" != xno; then
+    AC_DEFINE([USE_KQUEUE], , [Define to enable the kqueue engine])
+    ENGINE_C="engine_kqueue.c $ENGINE_C"
+fi
+
 dnl --with-symlink lets us set the name of the symlink; defaults to "ircd"
 AC_MSG_CHECKING([what name to give the symlink])
 AC_ARG_WITH([symlink],
index a81747ce77fe4d6337a6c6a333ef39e345eea5ad..4062a90edd62ab2eed0c4e06e98b764765a08ff5 100644 (file)
@@ -20,12 +20,12 @@ struct Client;
 /*
  * Prototypes
  */
+extern void IPcheck_init(void);
 extern int IPcheck_local_connect(struct in_addr ip, time_t* next_target_out);
 extern void IPcheck_connect_fail(struct in_addr ip);
 extern void IPcheck_connect_succeeded(struct Client *cptr);
 extern int IPcheck_remote_connect(struct Client *cptr, int is_burst);
 extern void IPcheck_disconnect(struct Client *cptr);
 extern unsigned short IPcheck_nr(struct Client* cptr);
-extern void IPcheck_expire();
 
 #endif /* INCLUDED_ipcheck_h */
index 61a57d2cfc48b8424af8f8876fde9031c311427c..21b8b353008d59f3d7d09a8422bbb0bfbef77ea5 100644 (file)
@@ -31,6 +31,9 @@
 #ifndef INCLUDED_msgq_h
 #include "msgq.h"
 #endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
 #ifndef INCLUDED_ircd_handler_h
 #include "ircd_handler.h"
 #endif
@@ -53,6 +56,7 @@ struct Whowas;
 struct DNSReply;
 struct hostent;
 struct Privs;
+struct AuthRequest;
 
 /*
  * Structures
@@ -110,11 +114,13 @@ struct Connection {
    *  to which the allocation is tied to! *Never* refer to
    *  these fields, if (from != self).
    */
+  unsigned long       con_magic; /* magic number */
   struct Connection*  con_next;  /* Next connection with queued data */
   struct Connection** con_prev_p; /* What points to us */
   struct Client*      con_client; /* Client associated with connection */
   unsigned int        con_count; /* Amount of data in buffer */
   int                 con_fd;    /* >= 0, for local clients */
+  int                 con_freeflag; /* indicates if connection can be freed */
   int                 con_error; /* last socket level error for client */
   unsigned int        con_snomask; /* mask for server messages */
   time_t              con_nextnick; /* Next time a nick change is allowed */
@@ -149,9 +155,15 @@ struct Connection {
   char con_passwd[PASSWDLEN + 1];
   char con_buffer[BUFSIZE];     /* Incoming message buffer; or the error that
                                    caused this clients socket to be `dead' */
+  struct Socket       con_socket; /* socket descriptor for client */
+  struct Timer        con_proc; /* process latent messages from client */
+  struct AuthRequest* con_auth; /* auth request for client */
 };
 
+#define CONNECTION_MAGIC 0x12f955f3
+
 struct Client {
+  unsigned long  cli_magic;     /* magic number */
   struct Client* cli_next;      /* link in GlobalClientList */
   struct Client* cli_prev;      /* link in GlobalClientList */
   struct Client* cli_hnext;     /* link in hash table bucket or this */
@@ -182,6 +194,10 @@ struct Client {
   char cli_info[REALLEN + 1];   /* Free form additional client information */
 };
 
+#define CLIENT_MAGIC 0x4ca08286
+
+#define cli_verify(cli)                ((cli)->cli_magic == CLIENT_MAGIC)
+#define cli_magic(cli)         ((cli)->cli_magic)
 #define cli_next(cli)          ((cli)->cli_next)
 #define cli_prev(cli)          ((cli)->cli_prev)
 #define cli_hnext(cli)         ((cli)->cli_hnext)
@@ -208,6 +224,7 @@ struct Client {
 
 #define cli_count(cli)         ((cli)->cli_connect->con_count)
 #define cli_fd(cli)            ((cli)->cli_connect->con_fd)
+#define cli_freeflag(cli)      ((cli)->cli_connect->con_freeflag)
 #define cli_error(cli)         ((cli)->cli_connect->con_error)
 #define cli_snomask(cli)       ((cli)->cli_connect->con_snomask)
 #define cli_nextnick(cli)      ((cli)->cli_connect->con_nextnick)
@@ -235,12 +252,18 @@ struct Client {
 #define cli_sockhost(cli)      ((cli)->cli_connect->con_sockhost)
 #define cli_passwd(cli)                ((cli)->cli_connect->con_passwd)
 #define cli_buffer(cli)                ((cli)->cli_connect->con_buffer)
+#define cli_socket(cli)                ((cli)->cli_connect->con_socket)
+#define cli_proc(cli)          ((cli)->cli_connect->con_proc)
+#define cli_auth(cli)          ((cli)->cli_connect->con_auth)
 
+#define con_verify(con)                ((con)->con_magic == CONNECTION_MAGIC)
+#define con_magic(con)         ((con)->con_magic)
 #define con_next(con)          ((con)->con_next)
 #define con_prev_p(con)                ((con)->con_prev_p)
 #define con_client(con)                ((con)->con_client)
 #define con_count(con)         ((con)->con_count)
 #define con_fd(con)            ((con)->con_fd)
+#define con_freeflag(con)      ((con)->con_freeflag)
 #define con_error(con)         ((con)->con_error)
 #define con_snomask(con)       ((con)->con_snomask)
 #define con_nextnick(con)      ((con)->con_nextnick)
@@ -268,6 +291,9 @@ struct Client {
 #define con_sockhost(con)      ((con)->con_sockhost)
 #define con_passwd(con)                ((con)->con_passwd)
 #define con_buffer(con)                ((con)->con_buffer)
+#define con_socket(con)                ((con)->con_socket)
+#define con_proc(con)          ((con)->con_proc)
+#define con_auth(con)          ((con)->con_auth)
 
 #define STAT_CONNECTING         0x001 /* connecting to another server */
 #define STAT_HANDSHAKE          0x002 /* pass - server sent */
@@ -407,6 +433,10 @@ struct Client {
 #define ClearWallops(x)         (cli_flags(x) &= ~FLAGS_WALLOP)
 #define ClearServNotice(x)      (cli_flags(x) &= ~FLAGS_SERVNOTICE)
 
+/* free flags */
+#define FREEFLAG_SOCKET        0x0001  /* socket needs to be freed */
+#define FREEFLAG_TIMER 0x0002  /* timer needs to be freed */
+
 /* server notice stuff */
 
 #define SNO_ADD         1
index df1a3980272fce4e7e329ebcdd17f22f92c26030..73c289009f5c5b52f0702d3bb30922a0e7a73e78 100644 (file)
@@ -59,6 +59,7 @@ extern time_t         nextping;
 extern char*          configfile;
 extern int            debuglevel;
 extern char*          debugmode;
+extern int           running;
 
 #endif /* INCLUDED_ircd_h */
 
diff --git a/include/ircd_events.h b/include/ircd_events.h
new file mode 100644 (file)
index 0000000..54d034f
--- /dev/null
@@ -0,0 +1,247 @@
+#ifndef INCLUDED_ircd_events_h
+#define INCLUDED_ircd_events_h
+/*
+ * IRC - Internet Relay Chat, include/ircd_events.h
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h> /* time_t */
+#define INCLUDED_sys_types_h
+#endif
+
+struct Event;
+
+typedef void (*EventCallBack)(struct Event*);
+
+enum SocketState {
+  SS_CONNECTING,       /* Connection in progress on socket */
+  SS_LISTENING,                /* Socket is a listening socket */
+  SS_CONNECTED,                /* Socket is a connected socket */
+  SS_DATAGRAM,         /* Socket is a datagram socket */
+  SS_CONNECTDG,                /* Socket is a connected datagram socket */
+  SS_NOTSOCK           /* Socket isn't a socket at all */
+};
+
+enum TimerType {
+  TT_ABSOLUTE,         /* timer that runs at a specific time */
+  TT_RELATIVE,         /* timer that runs so many seconds in the future */
+  TT_PERIODIC          /* timer that runs periodically */
+};
+
+enum EventType {
+  ET_READ,             /* Readable event detected */
+  ET_WRITE,            /* Writable event detected */
+  ET_ACCEPT,           /* Connection can be accepted */
+  ET_CONNECT,          /* Connection completed */
+  ET_EOF,              /* End-of-file on connection */
+  ET_ERROR,            /* Error condition detected */
+  ET_SIGNAL,           /* A signal was received */
+  ET_EXPIRE,           /* A timer expired */
+  ET_DESTROY           /* The generator is being destroyed */
+};
+
+struct GenHeader {
+  struct GenHeader*  gh_next;  /* linked list of generators */
+  struct GenHeader** gh_prev_p;
+#ifdef IRCD_THREADED
+  struct GenHeader*  gh_qnext; /* linked list of generators in queue */
+  struct GenHeader** gh_qprev_p;
+  struct Event*             gh_head;   /* head of event queue */
+  struct Event*             gh_tail;   /* tail of event queue */
+#endif
+  unsigned int      gh_flags;  /* generator flags */
+  unsigned int      gh_ref;    /* reference count */
+  EventCallBack             gh_call;   /* generator callback function */
+  void*                     gh_data;   /* extra data */
+  union {
+    void*           ed_ptr;    /* engine data == pointer */
+    int                     ed_int;    /* engine data == integer */
+  }                 gh_engdata;/* engine data */
+};
+
+#define GEN_DESTROY    0x0001  /* generator is to be destroyed */
+#define GEN_MARKED     0x0002  /* generator is marked for destruction */
+#define GEN_ACTIVE     0x0004  /* generator is active */
+
+struct Socket {
+  struct GenHeader s_header;   /* generator information */
+  enum SocketState s_state;    /* state socket's in */
+  unsigned int    s_events;    /* events socket is interested in */
+  int             s_fd;        /* file descriptor for socket */
+};
+
+#define SOCK_EVENT_READABLE    0x0001  /* interested in readable */
+#define SOCK_EVENT_WRITABLE    0x0002  /* interested in writable */
+
+#define SOCK_EVENT_MASK                (SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE)
+
+#define SOCK_ACTION_SET                0x0000  /* set interest set as follows */
+#define SOCK_ACTION_ADD                0x1000  /* add to interest set */
+#define SOCK_ACTION_DEL                0x2000  /* remove from interest set */
+
+#define SOCK_ACTION_MASK       0x3000  /* mask out the actions */
+
+#define s_state(sock)  ((sock)->s_state)
+#define s_events(sock) ((sock)->s_events)
+#define s_fd(sock)     ((sock)->s_fd)
+#define s_data(sock)   ((sock)->s_header.gh_data)
+#define s_ed_int(sock) ((sock)->s_header.gh_engdata.ed_int)
+#define s_ed_ptr(sock) ((sock)->s_header.gh_engdata.ed_ptr)
+#define s_active(sock) ((sock)->s_header.gh_flags & GEN_ACTIVE)
+
+/* Note: The socket state overrides the socket event mask; that is, if
+ * it's an SS_CONNECTING socket, the engine selects its own definition
+ * of what that looks like and ignores s_events.  s_events is meaningful
+ * only for SS_CONNECTED, SS_DATAGRAM, and SS_CONNECTDG, but may be set
+ * prior to the state transition, if desired.
+ */
+
+struct Signal {
+  struct GenHeader sig_header; /* generator information */
+  int             sig_signal;  /* signal number */
+};
+
+#define sig_signal(sig)        ((sig)->sig_signal)
+#define sig_data(sig)  ((sig)->sig_header.gh_data)
+#define sig_ed_int(sig)        ((sig)->sig_header.gh_engdata.ed_int)
+#define sig_ed_ptr(sig)        ((sig)->sig_header.gh_engdata.ed_ptr)
+#define sig_active(sig)        ((sig)->sig_header.gh_flags & GEN_ACTIVE)
+
+struct Timer {
+  struct GenHeader t_header;   /* generator information */
+  enum TimerType   t_type;     /* what type of timer this is */
+  time_t          t_value;     /* value timer was added with */
+  time_t          t_expire;    /* time at which timer expires */
+};
+
+#define t_type(tim)    ((tim)->t_type)
+#define t_value(tim)   ((tim)->t_value)
+#define t_expire(tim)  ((tim)->t_expire)
+#define t_data(tim)    ((tim)->t_header.gh_data)
+#define t_ed_int(tim)  ((tim)->t_header.gh_engdata.ed_int)
+#define t_ed_ptr(tim)  ((tim)->t_header.gh_engdata.ed_ptr)
+#define t_active(tim)  ((tim)->t_header.gh_flags & GEN_ACTIVE)
+
+struct Event {
+  struct Event*         ev_next;       /* linked list of events on queue */
+  struct Event** ev_prev_p;
+  enum EventType ev_type;      /* Event type */
+  int           ev_data;       /* extra data, like errno value */
+  union {
+    struct GenHeader* gen_header;      /* Generator header */
+    struct Socket*    gen_socket;      /* Socket generating event */
+    struct Signal*    gen_signal;      /* Signal generating event */
+    struct Timer*     gen_timer;       /* Timer generating event */
+  }             ev_gen;        /* object generating event */
+};
+
+#define ev_type(ev)    ((ev)->ev_type)
+#define ev_data(ev)    ((ev)->ev_data)
+#define ev_socket(ev)  ((ev)->ev_gen.gen_socket)
+#define ev_signal(ev)  ((ev)->ev_gen.gen_signal)
+#define ev_timer(ev)   ((ev)->ev_gen.gen_timer)
+
+struct Generators {
+  struct Socket* g_socket;     /* list of socket generators */
+  struct Signal* g_signal;     /* list of signal generators */
+  struct Timer*         g_timer;       /* list of timer generators */
+};
+
+/* returns 1 if successfully initialized, 0 if not */
+typedef int (*EngineInit)(int);
+
+/* Tell engine about new signal; set to 0 if engine doesn't know signals */
+typedef void (*EngineSignal)(struct Signal*);
+
+/* Tell engine about new socket */
+typedef int (*EngineAdd)(struct Socket*);
+
+/* Tell engine about socket's new_state */
+typedef void (*EngineState)(struct Socket*, enum SocketState new_state);
+
+/* Tell engine about socket's new_events */
+typedef void (*EngineEvents)(struct Socket*, unsigned int new_events);
+
+/* Tell engine a socket's going away */
+typedef void (*EngineDelete)(struct Socket*);
+
+/* The actual event loop */
+typedef void (*EngineLoop)(struct Generators*);
+
+struct Engine {
+  const char*  eng_name;       /* a name for the engine */
+  EngineInit   eng_init;       /* initialize engine */
+  EngineSignal eng_signal;     /* express interest in a signal */
+  EngineAdd    eng_add;        /* express interest in a socket */
+  EngineState  eng_state;      /* mention a change in state to engine */
+  EngineEvents eng_events;     /* express interest in socket events */
+  EngineDelete eng_closing;    /* socket is being closed */
+  EngineLoop   eng_loop;       /* actual event loop */
+};
+
+#define gen_ref_inc(gen)       (((struct GenHeader*) (gen))->gh_ref++)
+#define gen_ref_dec(gen)                                                     \
+do {                                                                         \
+  struct GenHeader* _gen = (struct GenHeader*) (gen);                        \
+  if (!--_gen->gh_ref && (_gen->gh_flags & GEN_DESTROY)) {                   \
+    gen_dequeue(_gen);                                                       \
+    event_generate(ET_DESTROY, _gen, 0);                                     \
+  }                                                                          \
+} while (0)
+
+void gen_dequeue(void* arg);
+
+void event_init(int max_sockets);
+void event_loop(void);
+void event_generate(enum EventType type, void* arg, int data);
+
+void timer_add(struct Timer* timer, EventCallBack call, void* data,
+              enum TimerType type, time_t value);
+void timer_del(struct Timer* timer);
+void timer_chg(struct Timer* timer, enum TimerType type, time_t value);
+void timer_run(void);
+#define timer_next(gen)        ((gen)->g_timer ? (gen)->g_timer->t_expire : 0)
+
+void signal_add(struct Signal* signal, EventCallBack call, void* data,
+               int sig);
+
+int socket_add(struct Socket* sock, EventCallBack call, void* data,
+              enum SocketState state, unsigned int events, int fd);
+void socket_del(struct Socket* sock);
+void socket_state(struct Socket* sock, enum SocketState state);
+void socket_events(struct Socket* sock, unsigned int events);
+
+const char* engine_name(void);
+
+#ifdef DEBUGMODE
+/* These routines pretty-print names for states and types for debug printing */
+
+const char* state_to_name(enum SocketState state);
+const char* timer_to_name(enum TimerType type);
+const char* event_to_name(enum EventType type);
+const char* gen_flags(unsigned int flags);
+const char* sock_flags(unsigned int flags);
+
+#endif /* DEBUGMODE */
+
+#endif /* INCLUDED_ircd_events_h */
index 981b902ceb533dbd172d48677c061f4dbc7911d9..2f9e4633e894dd57520b5b1db6df572dfb7d7f1f 100644 (file)
@@ -37,7 +37,7 @@ extern IOResult os_sendv_nonb(int fd, struct MsgQ* buf,
 extern IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int len,
                                  unsigned int* length_out,
                                  struct sockaddr_in* from_out);
-extern int os_connect_nonb(int fd, const struct sockaddr_in* sin);
+extern IOResult os_connect_nonb(int fd, const struct sockaddr_in* sin);
 extern int os_set_fdlimit(unsigned int max_descriptors);
 extern int os_set_listen(int fd, int backlog);
 extern int os_set_nonblocking(int fd);
index 21e8b62c734b236cf0cc12e0eb67bf0f4f8553be..849aab0a0e0e89a558a49ac0b60aea1ff7306904 100644 (file)
@@ -98,6 +98,7 @@
 #define HEAD_IN_SAND_STATS_R
 #define HEAD_IN_SAND_STATS_D
 #define HEAD_IN_SAND_STATS_d
+#define HEAD_IN_SAND_STATS_E
 #define HEAD_IN_SAND_STATS_t
 #define HEAD_IN_SAND_STATS_T
 #define HEAD_IN_SAND_STATS_U
index 509de683b419b81a7404318428870bd797e95c3e..afe43226d3bdbbfa986f645695ca868e9bb3dd8f 100644 (file)
@@ -11,6 +11,7 @@
 #endif
 
 struct Client;
+struct Connection;
 struct Channel;
 struct ConfItem;
 
@@ -53,6 +54,7 @@ extern struct SLink *make_link(void);
 extern struct SLink *find_user_link(struct SLink *lp, struct Client *ptr);
 extern void init_list(void);
 extern struct Client *make_client(struct Client *from, int status);
+extern void free_connection(struct Connection *con);
 extern void free_client(struct Client *cptr);
 extern struct Server *make_server(struct Client *cptr);
 extern void remove_client_from_list(struct Client *cptr);
index 8ba11e799dda4955e7176548ec591b062adf3958..26d5e86e34c123f375656e8bd71aa1b1a414ddfb 100644 (file)
@@ -23,6 +23,9 @@
 #ifndef INCLUDED_ircd_defs_h
 #include "ircd_defs.h"       /* HOSTLEN */
 #endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
 #ifndef INCLUDED_sys_types_h
 #include <sys/types.h>       /* size_t, broken BSD system headers */
 #define INCLUDED_sys_types_h
@@ -46,11 +49,11 @@ struct Listener {
   time_t           last_accept;        /* last time listener accepted */
   struct in_addr   addr;               /* virtual address or INADDR_ANY */
   struct in_addr   mask;               /* listener hostmask */
+  struct Socket    socket;             /* describe socket to event system */
 };
 
 extern struct Listener* ListenerPollList; /* GLOBAL - listener list */
 
-extern void        accept_connection(struct Listener* listener);
 extern void        add_listener(int port, const char* vaddr_ip, 
                                 const char* mask, int is_server, 
                                 int is_hidden);
index a260249eacee18bc0de2c3cb2679ffd871d4e86a..4f90cd4faeab55d221145ec54f5ac388f0944acb 100644 (file)
@@ -105,6 +105,7 @@ extern const struct Numeric* get_error_numeric(int err);
 #define RPL_SERVLIST         234       /* unused */
 #define RPL_SERVLISTEND      235       /* unused */
 
+#define RPL_STATSENGINE      237       /* Undernet engine name */
 #define RPL_STATSFLINE       238       /* Undernet feature lines */
 /*      RPL_STATSIAUTH       239           IRCnet extension */
 /*      RPL_STATSVLINE       240           IRCnet extension */
index 0b03355e93d13d82f978c5a3ec631e4028e917c6..d9aee6d8821e131b5467b9b8150cd37fc75f234d 100644 (file)
@@ -23,6 +23,9 @@
 #include <sys/types.h>
 #define INCLUDED_sys_types_h
 #endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
 
 struct Client;
 
@@ -32,8 +35,8 @@ struct AuthRequest {
   struct Client*      client;    /* pointer to client struct for request */
   unsigned int        flags;     /* current state of request */
   int                 fd;        /* file descriptor for auth queries */
-  int                 index;     /* select / poll index */
-  time_t              timeout;   /* time when query expires */
+  struct Socket       socket;    /* socket descriptor for auth queries */
+  struct Timer        timeout;   /* timeout timer for auth queries */
 };
 
 /*
@@ -44,6 +47,11 @@ struct AuthRequest {
 #define AM_AUTH_PENDING      0x02
 #define AM_DNS_PENDING       0x04
 
+#define AM_SOCKET            0x40 /* socket structure not destroyed */
+#define AM_TIMEOUT           0x80 /* timer structure not destroyed */
+
+#define AM_FREE_MASK         (AM_SOCKET | AM_TIMEOUT)
+
 #define SetDNSPending(x)     ((x)->flags |= AM_DNS_PENDING)
 #define ClearDNSPending(x)   ((x)->flags &= ~AM_DNS_PENDING)
 #define IsDNSPending(x)      ((x)->flags &  AM_DNS_PENDING)
@@ -63,10 +71,9 @@ struct AuthRequest {
 extern struct AuthRequest* AuthPollList; /* GLOBAL - auth queries pending io */
 
 extern void start_auth(struct Client *);
-extern void timeout_auth_queries(time_t now);
 extern void read_auth_reply(struct AuthRequest* req);
 extern void send_auth_query(struct AuthRequest* req);
-extern void remove_auth_request(struct AuthRequest *req);
+extern void destroy_auth_request(struct AuthRequest *req, int send_reports);
 
 #endif /* INCLUDED_s_auth_h */
 
index a0248c102d64095c32539d052250e66ce862d684..5952d480a411e38a59b8d22430ea92a700a6da9e 100644 (file)
@@ -46,6 +46,7 @@ extern const char* const SELECT_ERROR_MSG;
 extern const char* const CONNECT_ERROR_MSG;
 extern const char* const SETBUFS_ERROR_MSG;
 extern const char* const TOS_ERROR_MSG;
+extern const char* const REGISTER_ERROR_MSG;
 
 
 extern int            HighestFd;
@@ -89,5 +90,6 @@ extern void init_server_identity(void);
 extern void close_connections(int close_stderr);
 extern int  init_connection_limits(void);
 extern void set_virtual_host(struct in_addr addr);
+extern void update_write(struct Client* cptr);
 
 #endif /* INCLUDED_s_bsd_h */
index f3bbfd7852543e5bd6a19f4bb9506294c95f0daa..9bc2560f3b1e14e64c35d5d8baffe8255abbdc95 100644 (file)
@@ -27,16 +27,17 @@ struct Client;
 /*
  * defined debugging levels
  */
-#define DEBUG_FATAL  0
-#define DEBUG_ERROR  1  /* report_error() and other errors that are found */
-#define DEBUG_NOTICE 3
-#define DEBUG_DNS    4  /* used by all DNS related routines - a *lot* */
-#define DEBUG_INFO   5  /* general useful info */
-#define DEBUG_NUM    6  /* numerics */
-#define DEBUG_SEND   7  /* everything that is sent out */
-#define DEBUG_DEBUG  8  /* everything that is received */ 
-#define DEBUG_MALLOC 9  /* malloc/free calls */
-#define DEBUG_LIST  10  /* debug list use */
+#define DEBUG_FATAL   0
+#define DEBUG_ERROR   1  /* report_error() and other errors that are found */
+#define DEBUG_NOTICE  3
+#define DEBUG_DNS     4  /* used by all DNS related routines - a *lot* */
+#define DEBUG_INFO    5  /* general useful info */
+#define DEBUG_NUM     6  /* numerics */
+#define DEBUG_SEND    7  /* everything that is sent out */
+#define DEBUG_DEBUG   8  /* everything that is received */ 
+#define DEBUG_MALLOC  9  /* malloc/free calls */
+#define DEBUG_LIST   10  /* debug list use */
+#define DEBUG_ENGINE 11  /* debug event engine; can dump gigabyte logs */
 
 /*
  * proto types
index db0984c7a45f690abc7d4cdda31623a5170d1c3c..afdf2869e169d9b22d24b3e797145c659e1b71a2 100644 (file)
@@ -31,6 +31,9 @@
 #ifndef INCLUDED_ircd_defs_h
 #include "ircd_defs.h"
 #endif
+#ifndef INCLUDED_ircd_events_h
+#include "ircd_events.h"
+#endif
 
 struct Client;
 struct ConfItem;
@@ -46,15 +49,22 @@ struct UPing
   char               active;   /* ping active flag */
   struct Client*     client;   /* who requested the pings */
   time_t             lastsent; /* when last ping was sent */
-  time_t             timeout;  /* current ping timeout time */
   int                ms_min;   /* minimum time in milliseconds */
   int                ms_ave;   /* average time in milliseconds */
   int                ms_max;   /* maximum time in milliseconds */
   int                index;    /* index into poll array */
+  struct Socket      socket;   /* socket structure */
+  struct Timer       sender;   /* timer telling when next to send a ping */
+  struct Timer       killer;   /* timer to kill us */
+  unsigned int       freeable; /* zero when structure can be free()'d */
   char               name[HOSTLEN + 1]; /* server name to poing */
   char               buf[BUFSIZE];      /* buffer to hold ping times */
 };
 
+#define UPING_PENDING_SOCKET   0x01 /* pending socket destruction event */
+#define UPING_PENDING_SENDER   0x02 /* pending sender destruction event */
+#define UPING_PENDING_KILLER   0x04 /* pending killer destruction event */
+
 extern int UPingFileDescriptor;
 
 extern int  uping_init(void);
index 3d850d8f82e24070eae64fa39bcbf42893e63630..e1f052d79c7cd6b4330e5e8a931da8f0fcf917fd 100644 (file)
@@ -30,6 +30,7 @@
 #include "msg.h"
 #include "numnicks.h"       /* NumNick, NumServ (GODMODE) */
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "s_debug.h"        /* Debug */
 #include "s_user.h"         /* TARGET_DELAY */
 #include "send.h"
@@ -71,6 +72,8 @@ struct IPRegistryEntry {
 static struct IPRegistryEntry* hashTable[IP_REGISTRY_TABLE_SIZE];
 static struct IPRegistryEntry* freeList = 0;
 
+static struct Timer expireTimer;
+
 static unsigned int ip_registry_hash(unsigned int ip)
 {
   return ((ip >> 16) ^ ip) & (IP_REGISTRY_TABLE_SIZE - 1);
@@ -168,15 +171,16 @@ static void ip_registry_expire_entry(struct IPRegistryEntry* entry)
   }
 }
 
-/*
- * ip_registry_expire
- */
-static void ip_registry_expire()
+/* Callback to run an expiry of the IPcheck registry */
+static void ip_registry_expire(struct Event* ev)
 {
   int i;
   struct IPRegistryEntry* entry;
   struct IPRegistryEntry* entry_next;
 
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
   for (i = 0; i < IP_REGISTRY_TABLE_SIZE; ++i) {
     for (entry = hashTable[i]; entry; entry = entry_next) {
       entry_next = entry->next;
@@ -186,6 +190,16 @@ static void ip_registry_expire()
   }
 }
 
+/*
+ * IPcheck_init()
+ *
+ * Initializes the registry timer
+ */
+void IPcheck_init(void)
+{
+  timer_add(&expireTimer, ip_registry_expire, 0, TT_PERIODIC, 60);
+}
+
 /*
  * IPcheck_local_connect
  *
@@ -349,8 +363,8 @@ void ip_registry_connect_succeeded(struct Client *cptr)
     free_targets = entry->target->count;
     tr = " tr";
   }
-  sendcmdto_one(&me, CMD_NOTICE, cptr, ":on %u ca %u(%u) ft %u(%u)%s",
-               entry->connected, entry->attempts, IPCHECK_CLONE_LIMIT,
+  sendcmdto_one(&me, CMD_NOTICE, cptr, "%C :on %u ca %u(%u) ft %u(%u)%s",
+               cptr, entry->connected, entry->attempts, IPCHECK_CLONE_LIMIT,
                free_targets, STARTTARGETS, tr);
 }
 
@@ -554,14 +568,3 @@ unsigned short IPcheck_nr(struct Client *cptr)
   assert(0 != cptr);
   return ip_registry_count(cli_ip(cptr).s_addr);
 }
-
-void IPcheck_expire()
-{
-  static time_t next_expire = 0;
-  if (next_expire < CurrentTime) {
-    ip_registry_expire();
-    next_expire = CurrentTime + 60;
-  }
-}
-
-
index 706fdadd264984844662d8f15b319011132f111a..0a4f63628668b921d2518833abf1482c4c1952ea 100644 (file)
@@ -40,6 +40,7 @@ MKDIR = mkdir
 TOUCH = touch
 GREP = grep
 OSDEP_C = @OSDEP_C@
+ENGINE_C = @ENGINE_C@
 @SET_MAKE@
 
 BINDIR = @bindir@
@@ -68,6 +69,12 @@ OSDEP_SRC = \
        os_generic.c \
        os_solaris.c
 
+ENGINE_SRC = \
+       engine_devpoll.c \
+       engine_poll.c \
+       engine_kqueue.c \
+       engine_select.c
+
 IRCD_SRC = \
        IPcheck.c \
        channel.c \
@@ -81,6 +88,7 @@ IRCD_SRC = \
        hash.c \
        ircd.c \
        ircd_alloc.c \
+       ircd_events.c \
        ircd_features.c \
        ircd_log.c \
        ircd_relay.c \
@@ -188,11 +196,11 @@ IRCD_SRC = \
        whocmds.c \
        whowas.c
 
-SRC = ${IRCD_SRC} ${OSDEP_C}
+SRC = ${IRCD_SRC} ${OSDEP_C} ${ENGINE_C}
 
 OBJS = ${SRC:%.c=%.o}
 
-DEP_SRC = ${IRCD_SRC} ${OSDEP_SRC}
+DEP_SRC = ${IRCD_SRC} ${OSDEP_SRC} ${ENGINE_SRC}
 
 all:
        ( cd ..; make -f Makefile )
@@ -327,83 +335,93 @@ depend:
 
 IPcheck.o: IPcheck.c ../config.h ../include/IPcheck.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
- ../include/struct.h ../include/msg.h ../include/numnicks.h \
- ../include/ircd_alloc.h ../include/s_debug.h ../include/s_user.h \
- ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd.h ../include/struct.h ../include/msg.h \
+ ../include/numnicks.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/s_debug.h ../include/s_user.h ../include/send.h
 channel.o: channel.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
- ../include/ircd_chattr.h ../include/ircd_features.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_snprintf.h ../include/ircd_string.h ../include/list.h \
- ../include/match.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/querycmds.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
- ../include/s_user.h ../include/send.h ../include/sprintf_irc.h \
- ../include/support.h ../include/sys.h ../include/whowas.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \
+ ../include/ircd_features.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_snprintf.h \
+ ../include/ircd_string.h ../include/list.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/querycmds.h ../include/s_bsd.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h ../include/sprintf_irc.h ../include/support.h \
+ ../include/sys.h ../include/whowas.h
 class.o: class.c ../config.h ../include/class.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_features.h \
- ../include/ircd_reply.h ../include/list.h ../include/numeric.h \
- ../include/s_conf.h ../include/s_debug.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_features.h ../include/ircd_reply.h ../include/list.h \
+ ../include/numeric.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/send.h
 client.o: client.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/class.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/class.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
  ../include/ircd_reply.h ../include/list.h ../include/numeric.h \
  ../include/s_conf.h ../include/s_debug.h ../include/send.h
 crule.o: crule.c ../config.h ../include/crule.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
- ../include/ircd_string.h ../include/match.h ../include/s_bsd.h \
- ../include/s_debug.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_string.h ../include/match.h \
+ ../include/s_bsd.h ../include/s_debug.h
 dbuf.o: dbuf.c ../config.h ../include/dbuf.h ../include/ircd_alloc.h \
- ../include/ircd_chattr.h ../include/ircd_features.h ../include/send.h \
- ../include/sys.h
+ ../include/fda.h ../include/ircd_chattr.h ../include/ircd_features.h \
+ ../include/send.h ../include/sys.h
 fda.o: fda.c ../config.h
 fileio.o: fileio.c ../config.h ../include/fileio.h \
- ../include/ircd_alloc.h
+ ../include/ircd_alloc.h ../include/fda.h
 gline.o: gline.c ../config.h ../include/gline.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
  ../include/numeric.h ../include/s_bsd.h ../include/s_debug.h \
  ../include/s_misc.h ../include/send.h ../include/support.h \
  ../include/msg.h ../include/numnicks.h ../include/sys.h
 hash.o: hash.c ../config.h ../include/hash.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/channel.h \
- ../include/ircd_chattr.h ../include/ircd_string.h ../include/ircd.h \
- ../include/struct.h ../include/msg.h ../include/send.h \
- ../include/support.h ../include/sys.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/channel.h ../include/ircd_chattr.h \
+ ../include/ircd_string.h ../include/ircd.h ../include/struct.h \
+ ../include/msg.h ../include/send.h ../include/support.h \
+ ../include/sys.h
 ircd.o: ircd.c ../config.h ../include/ircd.h ../include/struct.h \
  ../include/ircd_defs.h ../include/IPcheck.h ../include/class.h \
  ../include/client.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/crule.h ../include/hash.h \
- ../include/ircd_alloc.h ../include/ircd_features.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_signal.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/jupe.h ../include/list.h \
- ../include/match.h ../include/motd.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/parse.h \
- ../include/res.h ../include/s_auth.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
- ../include/send.h ../include/sys.h ../include/uping.h \
- ../include/userload.h ../include/version.h ../include/whowas.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/crule.h \
+ ../include/hash.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_features.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_signal.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/jupe.h \
+ ../include/list.h ../include/match.h ../include/motd.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/parse.h ../include/res.h ../include/s_auth.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/send.h ../include/sys.h \
+ ../include/uping.h ../include/userload.h ../include/version.h \
+ ../include/whowas.h
 ircd_alloc.o: ircd_alloc.c ../config.h ../include/ircd_alloc.h \
- ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/fda.h ../include/ircd_string.h ../include/ircd_chattr.h \
  ../include/s_debug.h ../include/ircd_defs.h
+ircd_events.o: ircd_events.c ../config.h ../include/ircd_events.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_defs.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_log.h \
+ ../include/ircd_snprintf.h ../include/s_debug.h
 ircd_features.o: ircd_features.c ../config.h \
  ../include/ircd_features.h ../include/channel.h \
  ../include/ircd_defs.h ../include/class.h ../include/client.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
  ../include/motd.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/random.h ../include/s_bsd.h \
@@ -411,88 +429,91 @@ ircd_features.o: ircd_features.c ../config.h \
  ../include/support.h ../include/sys.h ../include/whowas.h
 ircd_log.o: ircd_log.c ../config.h ../include/ircd_log.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd_alloc.h \
- ../include/ircd_reply.h ../include/ircd_snprintf.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/ircd.h \
- ../include/struct.h ../include/numeric.h ../include/s_debug.h \
- ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_reply.h \
+ ../include/ircd_snprintf.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \
+ ../include/numeric.h ../include/s_debug.h ../include/send.h
 ircd_relay.o: ircd_relay.c ../config.h ../include/ircd_relay.h \
  ../include/channel.h ../include/ircd_defs.h ../include/client.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/match.h ../include/msg.h \
  ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
  ../include/s_misc.h ../include/s_user.h ../include/send.h
 ircd_reply.o: ircd_reply.c ../config.h ../include/ircd_reply.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_snprintf.h ../include/msg.h \
- ../include/numeric.h ../include/s_conf.h ../include/s_debug.h \
- ../include/send.h
-ircd_signal.o: ircd_signal.c ../config.h ../include/ircd_signal.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_defs.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_snprintf.h \
+ ../include/msg.h ../include/numeric.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/send.h
+ircd_signal.o: ircd_signal.c ../config.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_defs.h ../include/ircd_events.h \
+ ../include/ircd_signal.h ../include/s_conf.h
 ircd_snprintf.o: ircd_snprintf.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/channel.h \
- ../include/ircd_snprintf.h ../include/struct.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/channel.h ../include/ircd_snprintf.h ../include/struct.h
 ircd_string.o: ircd_string.c ../config.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/ircd_defs.h ../include/ircd_log.h \
  chattr.tab.c
 ircd_xopen.o: ircd_xopen.c ../config.h ../include/ircd_xopen.h
 jupe.o: jupe.c ../config.h ../include/jupe.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_alloc.h ../include/ircd_log.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
- ../include/s_misc.h ../include/send.h ../include/support.h \
- ../include/sys.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_bsd.h ../include/s_misc.h ../include/send.h \
+ ../include/support.h ../include/sys.h
 list.o: list.c ../config.h ../include/list.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h \
- ../include/listener.h ../include/match.h ../include/numeric.h \
- ../include/res.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
- ../include/send.h ../include/support.h ../include/whowas.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/listener.h ../include/match.h \
+ ../include/numeric.h ../include/res.h ../include/s_auth.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h \
+ ../include/support.h ../include/whowas.h
 listener.o: listener.c ../config.h ../include/listener.h \
- ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_alloc.h \
- ../include/ircd_features.h ../include/ircd_osdep.h \
+ ../include/ircd_defs.h ../include/ircd_events.h ../include/client.h \
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_features.h ../include/ircd_osdep.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/numeric.h ../include/s_bsd.h \
  ../include/s_conf.h ../include/s_misc.h ../include/send.h \
  ../include/sprintf_irc.h ../include/sys.h
 m_admin.o: m_admin.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
- ../include/s_user.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_conf.h ../include/s_user.h
 m_away.o: m_away.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
- ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_user.h ../include/send.h
 m_burst.o: m_burst.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/list.h ../include/match.h \
- ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_conf.h ../include/s_misc.h ../include/send.h \
- ../include/support.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/match.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_conf.h ../include/s_misc.h \
+ ../include/send.h ../include/support.h
 m_clearmode.o: m_clearmode.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/channel.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/channel.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
  ../include/ircd_features.h ../include/ircd_log.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
@@ -500,162 +521,175 @@ m_clearmode.o: m_clearmode.c ../config.h ../include/client.h \
  ../include/support.h
 m_close.o: m_close.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/numeric.h ../include/s_bsd.h \
- ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/numeric.h \
+ ../include/s_bsd.h ../include/send.h
 m_connect.o: m_connect.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/crule.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/jupe.h \
- ../include/match.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/s_user.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/crule.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/jupe.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_user.h \
+ ../include/send.h
 m_cprivmsg.o: m_cprivmsg.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/s_user.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/s_user.h
 m_create.o: m_create.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
- ../include/s_misc.h ../include/s_user.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h
 m_defaults.o: m_defaults.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/numeric.h ../include/numnicks.h \
- ../include/send.h ../include/supported.h ../include/channel.h \
- ../include/version.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h ../include/supported.h \
+ ../include/channel.h ../include/version.h
 m_destruct.o: m_destruct.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
 m_desynch.o: m_desynch.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/s_bsd.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+ ../include/send.h
 m_die.o: m_die.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/s_bsd.h ../include/send.h
 m_endburst.o: m_endburst.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h
 m_error.o: m_error.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_alloc.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
- ../include/s_misc.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/send.h
 m_get.o: m_get.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
  ../include/send.h
 m_gline.o: m_gline.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/gline.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
- ../include/s_misc.h ../include/send.h ../include/support.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/gline.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_conf.h ../include/s_misc.h ../include/send.h \
+ ../include/support.h
 m_help.o: m_help.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
 m_info.o: m_info.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \
  ../include/s_conf.h ../include/send.h ../include/version.h
 m_invite.o: m_invite.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
- ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_user.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/send.h
 m_ison.o: m_ison.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/numeric.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/numeric.h ../include/send.h
 m_join.o: m_join.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/gline.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_chattr.h ../include/ircd_features.h \
- ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
- ../include/s_user.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/gline.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h \
+ ../include/ircd_features.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_user.h \
+ ../include/send.h
 m_jupe.o: m_jupe.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/jupe.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
- ../include/s_misc.h ../include/send.h ../include/support.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/jupe.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_features.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_conf.h ../include/s_misc.h ../include/send.h \
+ ../include/support.h
 m_kick.o: m_kick.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h
 m_kill.o: m_kill.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_misc.h \
- ../include/send.h ../include/whowas.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_misc.h ../include/send.h \
+ ../include/whowas.h
 m_links.o: m_links.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_policy.h ../include/ircd_reply.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_policy.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
  ../include/s_user.h ../include/send.h
 m_list.o: m_list.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
- ../include/ircd_chattr.h ../include/ircd_features.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \
+ ../include/ircd_features.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+ ../include/send.h
 m_lusers.o: m_lusers.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/querycmds.h \
  ../include/ircd_features.h ../include/s_user.h ../include/s_serv.h \
  ../include/send.h
 m_map.o: m_map.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_policy.h ../include/ircd_reply.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_policy.h ../include/ircd_reply.h \
  ../include/ircd_snprintf.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/list.h ../include/match.h \
  ../include/msg.h ../include/numeric.h ../include/s_user.h \
@@ -663,237 +697,255 @@ m_map.o: m_map.c ../config.h ../include/client.h \
  ../include/ircd_features.h
 m_mode.o: m_mode.c ../config.h ../include/handlers.h \
  ../include/channel.h ../include/ircd_defs.h ../include/client.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/s_conf.h ../include/s_debug.h \
  ../include/s_user.h ../include/send.h
 m_motd.o: m_motd.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/match.h ../include/motd.h \
  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
  ../include/s_conf.h ../include/class.h ../include/s_user.h \
  ../include/send.h
 m_names.o: m_names.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
- ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_user.h ../include/send.h
 m_nick.o: m_nick.c ../config.h ../include/IPcheck.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
- ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
- ../include/s_misc.h ../include/s_user.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h
 m_notice.o: m_notice.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_chattr.h \
- ../include/ircd_relay.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/send.h ../include/handlers.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_chattr.h ../include/ircd_relay.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/send.h \
+ ../include/handlers.h
 m_oper.o: m_oper.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h ../include/ircd_log.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/ircd_xopen.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_user.h \
- ../include/s_misc.h ../include/send.h ../include/support.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/ircd_xopen.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_user.h ../include/s_misc.h \
+ ../include/send.h ../include/support.h
 m_opmode.o: m_opmode.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/channel.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/channel.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_features.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/send.h
 m_part.o: m_part.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h \
- ../include/numeric.h ../include/numnicks.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/send.h
 m_pass.o: m_pass.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/send.h
 m_ping.o: m_ping.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/ircd.h \
- ../include/struct.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/s_debug.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_debug.h ../include/send.h
 m_pong.o: m_pong.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/s_user.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/send.h
 m_privmsg.o: m_privmsg.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_chattr.h ../include/ircd_features.h \
- ../include/ircd_relay.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h \
+ ../include/ircd_features.h ../include/ircd_relay.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/send.h
 m_privs.o: m_privs.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
- ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
 m_proto.o: m_proto.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
- ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
- ../include/s_misc.h ../include/send.h ../include/supported.h \
- ../include/channel.h ../include/version.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/send.h ../include/supported.h ../include/channel.h \
+ ../include/version.h
 m_quit.o: m_quit.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/struct.h ../include/s_misc.h \
- ../include/ircd_reply.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/struct.h \
+ ../include/s_misc.h ../include/ircd_reply.h
 m_rehash.o: m_rehash.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/ircd_chattr.h ../include/motd.h \
  ../include/numeric.h ../include/s_conf.h ../include/send.h
 m_reset.o: m_reset.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
  ../include/send.h
 m_restart.o: m_restart.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/ircd_chattr.h \
  ../include/numeric.h ../include/numnicks.h ../include/send.h
 m_rping.o: m_rping.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/opercmds.h ../include/s_user.h \
- ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+ ../include/s_user.h ../include/send.h
 m_rpong.o: m_rpong.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/opercmds.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+ ../include/send.h
 m_server.o: m_server.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_log.h ../include/ircd_features.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/jupe.h ../include/list.h \
- ../include/match.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/querycmds.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
- ../include/s_serv.h ../include/send.h ../include/userload.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_log.h \
+ ../include/ircd_features.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/jupe.h \
+ ../include/list.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_serv.h ../include/send.h \
+ ../include/userload.h
 m_set.o: m_set.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
  ../include/send.h
 m_settime.o: m_settime.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_reply.h ../include/ircd_snprintf.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_user.h ../include/send.h
+m_silence.o: m_silence.c ../config.h ../include/channel.h \
+ ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
  ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
  ../include/send.h
-m_silence.o: m_silence.c ../config.h ../include/channel.h \
- ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
- ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_user.h ../include/send.h
 m_squit.o: m_squit.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/numeric.h ../include/numnicks.h \
- ../include/match.h ../include/s_debug.h ../include/s_misc.h \
- ../include/s_user.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \
+ ../include/numnicks.h ../include/match.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h
 m_stats.o: m_stats.c ../config.h ../include/handlers.h \
  ../include/s_stats.h ../include/channel.h ../include/ircd_defs.h \
  ../include/class.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/gline.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
- ../include/ircd_features.h ../include/ircd_policy.h \
- ../include/ircd_reply.h ../include/ircd_string.h ../include/list.h \
- ../include/listener.h ../include/match.h ../include/motd.h \
- ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/opercmds.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \
- ../include/s_user.h ../include/send.h ../include/userload.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/gline.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_features.h \
+ ../include/ircd_policy.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/list.h ../include/listener.h \
+ ../include/match.h ../include/motd.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_serv.h ../include/s_user.h \
+ ../include/send.h ../include/userload.h
 m_time.o: m_time.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \
  ../include/send.h
 m_topic.o: m_topic.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h
 m_trace.o: m_trace.c ../config.h ../include/class.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_user.h ../include/send.h \
+ ../include/version.h
+m_uping.o: m_uping.c ../config.h ../include/client.h \
+ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
  ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_bsd.h ../include/s_conf.h ../include/s_user.h \
- ../include/send.h ../include/version.h
-m_uping.o: m_uping.c ../config.h ../include/client.h \
- ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
- ../include/s_user.h ../include/send.h ../include/uping.h
+ ../include/s_conf.h ../include/s_user.h ../include/send.h \
+ ../include/uping.h
 m_user.o: m_user.c ../config.h ../include/handlers.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
- ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h
 m_userhost.o: m_userhost.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h \
- ../include/numeric.h ../include/s_user.h ../include/struct.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/s_user.h \
+ ../include/struct.h
 m_userip.o: m_userip.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h \
- ../include/numeric.h ../include/s_user.h ../include/struct.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/s_user.h \
+ ../include/struct.h
 m_version.o: m_version.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_features.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
  ../include/ircd_reply.h ../include/ircd_string.h \
  ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
  ../include/numnicks.h ../include/s_debug.h ../include/s_user.h \
@@ -901,108 +953,113 @@ m_version.o: m_version.c ../config.h ../include/client.h \
  ../include/version.h
 m_wallchops.o: m_wallchops.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
- ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_user.h ../include/send.h
 m_wallops.o: m_wallops.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/send.h
 m_wallusers.o: m_wallusers.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
- ../include/numeric.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/send.h
 m_who.o: m_who.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/match.h ../include/numeric.h \
- ../include/numnicks.h ../include/send.h ../include/support.h \
- ../include/whocmds.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/match.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h \
+ ../include/support.h ../include/whocmds.h
 m_whois.o: m_whois.c ../config.h ../include/channel.h \
  ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_policy.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
- ../include/send.h ../include/whocmds.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_policy.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_user.h ../include/send.h ../include/whocmds.h
 m_whowas.o: m_whowas.c ../config.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/s_user.h ../include/s_misc.h \
- ../include/send.h ../include/whowas.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/s_misc.h ../include/send.h ../include/whowas.h
 match.o: match.c ../config.h ../include/match.h \
  ../include/ircd_chattr.h
 motd.o: motd.c ../config.h ../include/motd.h ../include/class.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/fileio.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
- ../include/ircd_features.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
- ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_user.h \
- ../include/send.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/fileio.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_features.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_user.h ../include/send.h
 msgq.o: msgq.c ../config.h ../include/msgq.h ../include/ircd_defs.h \
- ../include/ircd_alloc.h ../include/ircd_snprintf.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_snprintf.h \
  ../include/s_debug.h
 numnicks.o: numnicks.c ../config.h ../include/numnicks.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_alloc.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/match.h ../include/s_bsd.h \
- ../include/s_debug.h ../include/s_misc.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/match.h ../include/s_bsd.h ../include/s_debug.h \
+ ../include/s_misc.h
 opercmds.o: opercmds.c ../config.h ../include/opercmds.h \
  ../include/class.h ../include/client.h ../include/ircd_defs.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/listener.h ../include/match.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
- ../include/send.h
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/listener.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_conf.h ../include/send.h
 packet.o: packet.c ../config.h ../include/packet.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_chattr.h ../include/parse.h ../include/s_bsd.h \
- ../include/s_misc.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/parse.h \
+ ../include/s_bsd.h ../include/s_misc.h ../include/send.h
 parse.o: parse.c ../config.h ../include/parse.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/channel.h ../include/handlers.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
- ../include/ircd_features.h ../include/ircd_policy.h \
- ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/opercmds.h \
- ../include/querycmds.h ../include/res.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
- ../include/s_numeric.h ../include/s_user.h ../include/send.h \
- ../include/sys.h ../include/whocmds.h ../include/whowas.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/channel.h ../include/handlers.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_chattr.h ../include/ircd_features.h \
+ ../include/ircd_policy.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/opercmds.h ../include/querycmds.h \
+ ../include/res.h ../include/s_bsd.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_numeric.h \
+ ../include/s_user.h ../include/send.h ../include/sys.h \
+ ../include/whocmds.h ../include/whowas.h
 querycmds.o: querycmds.c ../config.h ../include/querycmds.h \
  ../include/ircd_features.h
 random.o: random.c ../config.h ../include/random.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd_log.h \
- ../include/ircd_reply.h ../include/send.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd_log.h ../include/ircd_reply.h ../include/send.h
 res.o: res.c ../config.h ../include/res.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_osdep.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
- ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
- ../include/send.h ../include/sprintf_irc.h ../include/support.h \
- ../include/sys.h
-s_auth.o: s_auth.c ../config.h ../include/s_auth.h ../include/client.h \
- ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/IPcheck.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/s_bsd.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/send.h ../include/sprintf_irc.h \
+ ../include/support.h ../include/sys.h
+s_auth.o: s_auth.c ../config.h ../include/s_auth.h \
+ ../include/ircd_events.h ../include/client.h ../include/ircd_defs.h \
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
+ ../include/IPcheck.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \
  ../include/ircd_features.h ../include/ircd_log.h \
  ../include/ircd_osdep.h ../include/ircd_string.h ../include/list.h \
  ../include/numeric.h ../include/querycmds.h ../include/res.h \
@@ -1010,25 +1067,25 @@ s_auth.o: s_auth.c ../config.h ../include/s_auth.h ../include/client.h \
  ../include/send.h ../include/sprintf_irc.h ../include/sys.h
 s_bsd.o: s_bsd.c ../config.h ../include/s_bsd.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/IPcheck.h ../include/channel.h \
- ../include/class.h ../include/hash.h ../include/ircd_log.h \
- ../include/ircd_features.h ../include/ircd_osdep.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/ircd.h ../include/struct.h \
- ../include/list.h ../include/listener.h ../include/msg.h \
- ../include/numeric.h ../include/numnicks.h ../include/packet.h \
- ../include/parse.h ../include/querycmds.h ../include/res.h \
- ../include/s_auth.h ../include/s_conf.h ../include/s_debug.h \
- ../include/s_misc.h ../include/s_user.h ../include/send.h \
- ../include/sprintf_irc.h ../include/support.h ../include/sys.h \
- ../include/uping.h ../include/version.h
+ ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/IPcheck.h ../include/channel.h ../include/class.h \
+ ../include/hash.h ../include/ircd_log.h ../include/ircd_features.h \
+ ../include/ircd_osdep.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/ircd.h \
+ ../include/struct.h ../include/list.h ../include/listener.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/packet.h ../include/parse.h ../include/querycmds.h \
+ ../include/res.h ../include/s_auth.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h ../include/sprintf_irc.h ../include/support.h \
+ ../include/sys.h ../include/uping.h ../include/version.h
 s_conf.o: s_conf.c ../config.h ../include/s_conf.h \
  ../include/IPcheck.h ../include/class.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/crule.h \
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/crule.h \
  ../include/ircd_features.h ../include/fileio.h ../include/gline.h \
  ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \
  ../include/ircd_log.h ../include/ircd_reply.h \
  ../include/ircd_snprintf.h ../include/ircd_string.h ../include/list.h \
  ../include/listener.h ../include/match.h ../include/motd.h \
@@ -1039,79 +1096,84 @@ s_conf.o: s_conf.c ../config.h ../include/s_conf.h \
 s_debug.o: s_debug.c ../config.h ../include/s_debug.h \
  ../include/ircd_defs.h ../include/channel.h ../include/class.h \
  ../include/client.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd_alloc.h \
- ../include/ircd_features.h ../include/ircd_log.h \
- ../include/ircd_osdep.h ../include/ircd_reply.h ../include/ircd.h \
- ../include/struct.h ../include/list.h ../include/numeric.h \
- ../include/numnicks.h ../include/res.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/send.h ../include/sys.h \
- ../include/whowas.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_features.h \
+ ../include/ircd_log.h ../include/ircd_osdep.h ../include/ircd_reply.h \
+ ../include/ircd.h ../include/struct.h ../include/list.h \
+ ../include/numeric.h ../include/numnicks.h ../include/res.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/send.h \
+ ../include/sys.h ../include/whowas.h
 s_err.o: s_err.c ../config.h ../include/numeric.h ../include/s_debug.h \
  ../include/ircd_defs.h ../include/sprintf_irc.h
 s_misc.o: s_misc.c ../config.h ../include/s_misc.h \
  ../include/IPcheck.h ../include/channel.h ../include/ircd_defs.h \
  ../include/client.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
- ../include/struct.h ../include/ircd_alloc.h ../include/ircd_log.h \
- ../include/ircd_policy.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
- ../include/match.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/parse.h ../include/querycmds.h \
- ../include/ircd_features.h ../include/res.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/s_debug.h ../include/s_user.h \
- ../include/send.h ../include/sprintf_irc.h ../include/support.h \
- ../include/sys.h ../include/uping.h ../include/userload.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_log.h ../include/ircd_policy.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/list.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/parse.h ../include/querycmds.h ../include/ircd_features.h \
+ ../include/res.h ../include/s_bsd.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_user.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/support.h ../include/sys.h \
+ ../include/uping.h ../include/userload.h
 s_numeric.o: s_numeric.c ../config.h ../include/s_numeric.h \
  ../include/channel.h ../include/ircd_defs.h ../include/client.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_snprintf.h ../include/numnicks.h ../include/send.h
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_snprintf.h ../include/numnicks.h \
+ ../include/send.h
 s_serv.o: s_serv.c ../config.h ../include/s_serv.h \
  ../include/IPcheck.h ../include/channel.h ../include/ircd_defs.h \
  ../include/client.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/gline.h ../include/hash.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
- ../include/ircd_reply.h ../include/ircd_string.h \
- ../include/ircd_chattr.h ../include/ircd_snprintf.h \
- ../include/ircd_xopen.h ../include/jupe.h ../include/list.h \
- ../include/match.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/parse.h ../include/querycmds.h \
- ../include/ircd_features.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
- ../include/send.h ../include/sprintf_irc.h ../include/sys.h \
- ../include/userload.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/gline.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/ircd_snprintf.h ../include/ircd_xopen.h ../include/jupe.h \
+ ../include/list.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/parse.h \
+ ../include/querycmds.h ../include/ircd_features.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h ../include/sprintf_irc.h \
+ ../include/sys.h ../include/userload.h
 s_stats.o: s_stats.c ../config.h ../include/s_stats.h \
  ../include/class.h ../include/client.h ../include/ircd_defs.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
- ../include/ircd_log.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/listener.h ../include/match.h \
- ../include/msg.h ../include/numeric.h ../include/numnicks.h \
- ../include/s_conf.h ../include/s_user.h ../include/send.h
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/listener.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+ ../include/s_user.h ../include/send.h
 s_user.o: s_user.c ../config.h ../include/s_user.h \
  ../include/IPcheck.h ../include/channel.h ../include/ircd_defs.h \
  ../include/class.h ../include/client.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/gline.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
- ../include/ircd_features.h ../include/ircd_log.h \
- ../include/ircd_policy.h ../include/ircd_reply.h \
- ../include/ircd_string.h ../include/list.h ../include/match.h \
- ../include/motd.h ../include/msg.h ../include/numeric.h \
- ../include/numnicks.h ../include/parse.h ../include/querycmds.h \
- ../include/random.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \
- ../include/send.h ../include/sprintf_irc.h ../include/support.h \
- ../include/supported.h ../include/sys.h ../include/userload.h \
- ../include/version.h ../include/whowas.h ../include/handlers.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/gline.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_features.h \
+ ../include/ircd_log.h ../include/ircd_policy.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/list.h \
+ ../include/match.h ../include/motd.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/parse.h \
+ ../include/querycmds.h ../include/random.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_serv.h ../include/send.h ../include/sprintf_irc.h \
+ ../include/support.h ../include/supported.h ../include/sys.h \
+ ../include/userload.h ../include/version.h ../include/whowas.h \
+ ../include/handlers.h
 send.o: send.c ../config.h ../include/send.h ../include/channel.h \
  ../include/ircd_defs.h ../include/class.h ../include/client.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/ircd.h ../include/struct.h ../include/ircd_snprintf.h \
- ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
- ../include/match.h ../include/msg.h ../include/numnicks.h \
- ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
- ../include/s_user.h ../include/sprintf_irc.h ../include/sys.h
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_snprintf.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/list.h ../include/match.h \
+ ../include/msg.h ../include/numnicks.h ../include/s_bsd.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+ ../include/sprintf_irc.h ../include/sys.h
 sprintf_irc.o: sprintf_irc.c ../config.h ../include/sprintf_irc.h \
  ../include/sys.h
 support.o: support.c ../config.h ../include/support.h \
@@ -1120,9 +1182,10 @@ support.o: support.c ../config.h ../include/support.h \
  ../include/ircd_snprintf.h ../include/s_bsd.h ../include/s_debug.h \
  ../include/send.h ../include/sprintf_irc.h ../include/sys.h
 uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \
- ../include/client.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_log.h ../include/ircd_osdep.h \
+ ../include/ircd_events.h ../include/client.h ../include/dbuf.h \
+ ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/ircd_osdep.h \
  ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
  ../include/msg.h ../include/numeric.h ../include/numnicks.h \
  ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
@@ -1130,15 +1193,16 @@ uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \
  ../include/sys.h
 userload.o: userload.c ../config.h ../include/userload.h \
  ../include/client.h ../include/ircd_defs.h ../include/dbuf.h \
- ../include/msgq.h ../include/ircd_handler.h ../include/ircd.h \
- ../include/struct.h ../include/msg.h ../include/numnicks.h \
- ../include/querycmds.h ../include/ircd_features.h ../include/s_misc.h \
- ../include/send.h ../include/sys.h
+ ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
+ ../include/ircd.h ../include/struct.h ../include/msg.h \
+ ../include/numnicks.h ../include/querycmds.h \
+ ../include/ircd_features.h ../include/s_misc.h ../include/send.h \
+ ../include/sys.h
 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
  ../include/channel.h ../include/ircd_defs.h ../include/client.h \
- ../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
- ../include/hash.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
  ../include/ircd_string.h ../include/list.h ../include/match.h \
  ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \
  ../include/ircd_features.h ../include/random.h ../include/s_bsd.h \
@@ -1148,12 +1212,13 @@ whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
  ../include/whowas.h ../include/msg.h
 whowas.o: whowas.c ../config.h ../include/whowas.h ../include/client.h \
  ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
- ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
- ../include/ircd_alloc.h ../include/ircd_chattr.h \
- ../include/ircd_features.h ../include/ircd_string.h ../include/list.h \
- ../include/numeric.h ../include/s_debug.h ../include/s_misc.h \
- ../include/s_user.h ../include/send.h ../include/support.h \
- ../include/sys.h ../include/msg.h
+ ../include/ircd_events.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_features.h \
+ ../include/ircd_string.h ../include/list.h ../include/numeric.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h ../include/support.h ../include/sys.h \
+ ../include/msg.h
 os_bsd.o: os_bsd.c ../config.h ../include/ircd_osdep.h \
  ../include/msgq.h ../include/ircd_defs.h
 os_linux.o: os_linux.c ../config.h ../include/ircd_osdep.h \
@@ -1164,3 +1229,18 @@ os_generic.o: os_generic.c ../config.h ../include/ircd_osdep.h \
  ../include/msgq.h ../include/ircd_defs.h
 os_solaris.o: os_solaris.c ../config.h ../include/ircd_osdep.h \
  ../include/msgq.h ../include/ircd_defs.h
+engine_devpoll.o: engine_devpoll.c ../config.h \
+ ../include/ircd_events.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_defs.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/s_debug.h
+engine_poll.o: engine_poll.c ../config.h ../include/ircd_events.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_defs.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_log.h \
+ ../include/s_debug.h
+engine_kqueue.o: engine_kqueue.c ../config.h ../include/ircd_events.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_defs.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_log.h \
+ ../include/s_debug.h
+engine_select.o: engine_select.c ../config.h ../include/ircd_events.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_defs.h \
+ ../include/ircd_log.h ../include/s_debug.h
index bd13efe77be1e6ae0327ff17fe8e7bd58539f5cb..38a5356a8cd85487ab6779a482195d39df1874aa 100644 (file)
@@ -1247,6 +1247,8 @@ void list_next_channels(struct Client *cptr, int nr)
     (cli_listing(cptr))->chptr = chptr;
     chptr->mode.mode |= MODE_LISTED;
   }
+
+  update_write(cptr);
 }
 
 /*
diff --git a/ircd/engine_devpoll.c b/ircd/engine_devpoll.c
new file mode 100644 (file)
index 0000000..8bd9c75
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_devpoll.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/devpoll.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define DEVPOLL_ERROR_THRESHOLD        20      /* after 20 devpoll errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /* expire errors after an hour */
+
+#define POLLS_PER_DEVPOLL      20      /* get 20 pollfd's per turn */
+
+/* Figure out what bits to set for read */
+#if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
+#elif defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLIN|POLLRDNORM)
+#elif defined(POLLIN)
+#  define POLLREADFLAGS POLLIN
+#elif defined(POLLRDNORM)
+#  define POLLREADFLAGS POLLRDNORM
+#endif
+
+/* Figure out what bits to set for write */
+#if defined(POLLOUT) && defined(POLLWRNORM)
+#  define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
+#elif defined(POLLOUT)
+#  define POLLWRITEFLAGS POLLOUT
+#elif defined(POLLWRNORM)
+#  define POLLWRITEFLAGS POLLWRNORM
+#endif
+
+/* Figure out what bits indicate errors */
+#ifdef POLLHUP
+#  define POLLERRORS (POLLHUP|POLLERR)
+#else
+#  define POLLERRORS POLLERR
+#endif
+
+static struct Socket** sockList;
+static int devpoll_max;
+static int devpoll_fd;
+
+static int errors = 0;
+static struct Timer clear_error;
+
+/* decrements the error count once per hour */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/* initialize the devpoll engine */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  if ((devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
+    log_write(LS_SYSTEM, L_WARNING, 0,
+             "/dev/poll engine cannot open device: %m");
+    return 0; /* engine cannot be initialized; defer */
+  }
+
+  /* allocate necessary memory */
+  sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
+
+  /* initialize the data */
+  for (i = 0; i < max_sockets; i++)
+    sockList[i] = 0;
+
+  devpoll_max = max_sockets; /* number of sockets allocated */
+
+  return 1;
+}
+
+/* Figure out what events go with a given state */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/* Reset the desired events */
+static void
+set_events(struct Socket* sock, unsigned int events)
+{
+  struct pollfd pfd;
+
+  pfd.fd = s_fd(sock);
+
+  if (s_ed_int(sock)) { /* is one in /dev/poll already? */
+    pfd.events = POLLREMOVE; /* First, remove old pollfd */
+
+    Debug((DEBUG_ENGINE, "devpoll: Removing old entry for socket %d [%p]",
+          s_fd(sock), sock));
+
+    if (write(devpoll_fd, &pfd, sizeof(pfd)) != sizeof(pfd)) {
+      event_generate(ET_ERROR, sock, errno); /* report error */
+      return;
+    }
+
+    s_ed_int(sock) = 0; /* mark that it's gone */
+  }
+
+  if (!(events & SOCK_EVENT_MASK)) /* no events, so stop here */
+    return;
+
+  pfd.events = 0; /* Now, set up new pollfd... */
+  if (events & SOCK_EVENT_READABLE)
+    pfd.events |= POLLREADFLAGS; /* look for readable conditions */
+  if (events & SOCK_EVENT_WRITABLE)
+    pfd.events |= POLLWRITEFLAGS; /* look for writable conditions */
+
+  Debug((DEBUG_ENGINE, "devpoll: Registering interest on %d [%p] (state %s, "
+        "mask [%s])", s_fd(sock), sock, state_to_name(s_state(sock)),
+        sock_flags(s_events(sock))));
+
+  if (write(devpoll_fd, &pfd, sizeof(pfd)) != sizeof(pfd)) {
+    event_generate(ET_ERROR, sock, errno); /* report error */
+    return;
+  }
+
+  s_ed_int(sock) = 1; /* mark that we've added a pollfd */
+}
+
+/* add a socket to be listened on */
+static int
+engine_add(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(0 == sockList[s_fd(sock)]);
+
+  /* bounds-check... */
+  if (s_fd(sock) >= devpoll_max) {
+    log_write(LS_SYSTEM, L_ERROR, 0,
+             "Attempt to add socket %d (> %d) to event engine", s_fd(sock),
+             devpoll_max);
+    return 0;
+  }
+
+  sockList[s_fd(sock)] = sock; /* add to list */
+
+  Debug((DEBUG_ENGINE, "devpoll: Adding socket %d [%p], state %s, to engine",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  /* set the correct events */
+  set_events(sock, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/* socket switching to new state */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "devpoll: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_events(sock, state_to_events(new_state, s_events(sock)));
+}
+
+/* socket events changing */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "devpoll: Changing event mask for socket %p to [%s]",
+        sock, sock_flags(new_events)));
+
+  /* set the correct events */
+  set_events(sock, state_to_events(s_state(sock), new_events));
+}
+
+/* socket going away */
+static void
+engine_delete(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "devpoll: Deleting socket %d [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  set_events(sock, 0); /* get rid of the socket */
+
+  sockList[s_fd(sock)] = 0; /* zero the socket list entry */
+}
+
+/* engine event loop */
+static void
+engine_loop(struct Generators* gen)
+{
+  struct dvpoll dopoll;
+  struct pollfd polls[POLLS_PER_DEVPOLL];
+  struct Socket* sock;
+  int nfds;
+  int i;
+  int errcode;
+  size_t codesize;
+
+  while (running) {
+    dopoll.dp_fds = polls; /* set up the struct dvpoll */
+    dopoll.dp_nfds = POLLS_PER_DEVPOLL;
+
+    /* calculate the proper timeout */
+    dopoll.dp_timeout = timer_next(gen) ?
+      (timer_next(gen) - CurrentTime) * 1000 : -1;
+
+    Debug((DEBUG_INFO, "devpoll: delay: %Tu (%Tu) %d", timer_next(gen),
+          CurrentTime, dopoll.dp_timeout));
+
+    /* check for active files */
+    nfds = ioctl(devpoll_fd, DP_POLL, &dopoll);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nfds < 0) {
+      if (errno != EINTR) { /* ignore interrupts */
+       /* Log the poll error */
+       log_write(LS_SOCKET, L_ERROR, 0, "ioctl(DP_POLL) error: %m");
+       if (!errors++)
+         timer_add(&clear_error, error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > DEVPOLL_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many /dev/poll errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; i < nfds; i++) {
+      assert(-1 < polls[i].fd);
+      assert(0 != sockList[polls[i].fd]);
+      assert(s_fd(sockList[polls[i].fd]) == polls[i].fd);
+
+      sock = sockList[polls[i].fd];
+      if (!sock) /* slots may become empty while processing events */
+       continue;
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "devpoll: Checking socket %p (fd %d) state %s, "
+            "events %s", sock, s_fd(sock), state_to_name(s_state(sock)),
+            sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                      &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "devpoll: Error %d on fd %d, socket %p",
+                errcode, s_fd(sock), sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak reference counts */
+         continue;
+       }
+      }
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (polls[i].revents & POLLWRITEFLAGS) { /* connection completed */
+         Debug((DEBUG_ENGINE, "devpoll: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+       }
+       break;
+
+      case SS_LISTENING:
+       if (polls[i].revents & POLLREADFLAGS) { /* connect. to be accept. */
+         Debug((DEBUG_ENGINE, "devpoll: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+       }
+       break;
+
+      case SS_NOTSOCK:
+       if (polls[i].revents & POLLREADFLAGS) { /* data on socket */
+         /* can't peek; it's not a socket */
+         Debug((DEBUG_ENGINE, "devpoll: non-socket readable"));
+         event_generate(ET_READ, sock, 0);
+       }
+       break;
+
+      case SS_CONNECTED:
+       if (polls[i].revents & POLLREADFLAGS) { /* data on socket */
+         char c;
+
+         switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */
+         case -1: /* error occurred?!? */
+           if (errno == EAGAIN) {
+             Debug((DEBUG_ENGINE, "devpoll: Resource temporarily "
+                    "unavailable?"));
+             continue;
+           }
+           Debug((DEBUG_ENGINE, "devpoll: Uncaught error!"));
+           event_generate(ET_ERROR, sock, errno);
+           break;
+
+         case 0: /* EOF from client */
+           Debug((DEBUG_ENGINE, "devpoll: EOF from client"));
+           event_generate(ET_EOF, sock, 0);
+           break;
+
+         default: /* some data can be read */
+           Debug((DEBUG_ENGINE, "devpoll: Data to be read"));
+           event_generate(ET_READ, sock, 0);
+           break;
+         }
+       }
+       if (polls[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "devpoll: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (polls[i].revents & POLLREADFLAGS) { /* socket readable */
+         Debug((DEBUG_ENGINE, "devpoll: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (polls[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "devpoll: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+      }
+
+      assert(s_fd(sock) == polls[i].fd);
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+struct Engine engine_devpoll = {
+  "/dev/poll",         /* Engine name */
+  engine_init,         /* Engine initialization function */
+  0,                   /* Engine signal registration function */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/engine_kqueue.c b/ircd/engine_kqueue.c
new file mode 100644 (file)
index 0000000..aafbb59
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_kqueue.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#define KQUEUE_ERROR_THRESHOLD 20      /* after 20 kqueue errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /* expire errors after an hour */
+
+#define POLLS_PER_KQUEUE       20      /* get 20 kevents per turn */
+
+static struct Socket** sockList;
+static int kqueue_max;
+static int kqueue_id;
+
+static int errors = 0;
+static struct Timer clear_error;
+
+/* decrements the error count once per hour */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/* initialize the kqueue engine */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  if ((kqueue_id = kqueue()) < 0) { /* initialize... */
+    log_write(LS_SYSTEM, L_WARNING, 0,
+             "kqueue() engine cannot initialize: %m");
+    return 0;
+  }
+
+  /* allocate necessary memory */
+  sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
+
+  /* initialize the data */
+  for (i = 0; i < max_sockets; i++)
+    sockList[i] = 0;
+
+  kqueue_max = max_sockets; /* number of sockets allocated */
+
+  return 1; /* success! */
+}
+
+/* add a signel to be watched for */
+static void
+engine_signal(struct Signal* sig)
+{
+  struct kevent sigevent;
+  struct sigaction act;
+
+  assert(0 != signal);
+
+  Debug((DEBUG_ENGINE, "kqueue: Adding filter for signal %d [%p]",
+        sig_signal(sig), sig));
+
+  sigevent.ident = sig_signal(sig); /* set up the kqueue event */
+  sigevent.filter = EVFILT_SIGNAL; /* looking for signals... */
+  sigevent.flags = EV_ADD | EV_ENABLE; /* add and enable it */
+  sigevent.fflags = 0;
+  sigevent.data = 0;
+  sigevent.udata = sig; /* store our user data */
+
+  if (kevent(kqueue_id, &sigevent, 1, 0, 0, 0) < 0) { /* add event */
+    log_write(LS_SYSTEM, L_WARNING, 0, "Unable to trap signal %d",
+             sig_signal(sig));
+    return;
+  }
+
+  act.sa_handler = SIG_IGN; /* ignore the signal */
+  act.sa_flags = 0;
+  sigemptyset(&act.sa_mask);
+  sigaction(sig_signal(sig), &act, 0);
+}
+
+/* Figure out what events go with a given state */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket--just in case */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/* Activate kqueue filters as appropriate */
+static void
+set_or_clear(struct Socket* sock, unsigned int clear, unsigned int set)
+{
+  int i = 0;
+  struct kevent chglist[2];
+
+  assert(0 != sock);
+  assert(-1 < s_fd(sock));
+
+  if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
+    chglist[i].ident = s_fd(sock); /* set up the change list */
+    chglist[i].filter = EVFILT_READ; /* readable filter */
+    chglist[i].flags = EV_ADD; /* adding it */
+    chglist[i].fflags = 0;
+    chglist[i].data = 0;
+    chglist[i].udata = 0; /* I love udata, but it can't really be used here */
+
+    if (set & SOCK_EVENT_READABLE) /* it's set */
+      chglist[i].flags |= EV_ENABLE;
+    else /* clear it */
+      chglist[i].flags |= EV_DISABLE;
+
+    i++; /* advance to next element */
+  }
+
+  if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
+    chglist[i].ident = s_fd(sock); /* set up the change list */
+    chglist[i].filter = EVFILT_WRITE; /* writable filter */
+    chglist[i].flags = EV_ADD; /* adding it */
+    chglist[i].fflags = 0;
+    chglist[i].data = 0;
+    chglist[i].udata = 0;
+
+    if (set & SOCK_EVENT_WRITABLE) /* it's set */
+      chglist[i].flags |= EV_ENABLE;
+    else /* clear it */
+      chglist[i].flags |= EV_DISABLE;
+
+    i++; /* advance count... */
+  }
+
+  if (kevent(kqueue_id, chglist, i, 0, 0, 0) < 0)
+    event_generate(ET_ERROR, sock, errno); /* report error */
+}
+
+/* add a socket to be listened on */
+static int
+engine_add(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(0 == sockList[s_fd(sock)]);
+
+  /* bounds-check... */
+  if (sock->s_fd >= kqueue_max) {
+    log_write(LS_SYSTEM, L_ERROR, 0,
+             "Attempt to add socket %d (> %d) to event engine", s_fd(sock),
+             kqueue_max);
+    return 0;
+  }
+
+  sockList[s_fd(sock)] = sock; /* add to list */
+
+  Debug((DEBUG_ENGINE, "kqueue: Adding socket %d [%p], state %s, to engine",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  /* Add socket to queue */
+  set_or_clear(sock, 0, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/* socket switching to new state */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "kqueue: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_or_clear(sock,
+              state_to_events(s_state(sock), s_events(sock)), /* old state */
+              state_to_events(new_state, s_events(sock))); /* new state */
+
+}
+
+/* socket events changing */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "kqueue: Changing event mask for socket %p to [%s]",
+        sock, sock_flags(new_events)));
+
+  /* set the correct events */
+  set_or_clear(sock,
+              state_to_events(s_state(sock), s_events(sock)), /* old events */
+              state_to_events(s_state(sock), new_events)); /* new events */
+}
+
+/* socket going away */
+static void
+engine_delete(struct Socket* sock)
+{
+  struct kevent dellist[2];
+
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "kqueue: Deleting socket %d [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  dellist[0].ident = s_fd(sock); /* set up the delete list */
+  dellist[0].filter = EVFILT_READ; /* readable filter */
+  dellist[0].flags = EV_DELETE; /* delete it */
+  dellist[0].fflags = 0;
+  dellist[0].data = 0;
+  dellist[0].udata = 0;
+
+  dellist[1].ident = s_fd(sock);
+  dellist[1].filter = EVFILT_WRITE; /* writable filter */
+  dellist[1].flags = EV_DELETE; /* delete it */
+  dellist[1].fflags = 0;
+  dellist[1].data = 0;
+  dellist[1].udata = 0;
+
+  /* make it all go away */
+  if (kevent(kqueue_id, dellist, 2, 0, 0, 0) < 0)
+    log_write(LS_SOCKET, L_WARNING, 0,
+             "Unable to delete kevent items for socket %d", s_fd(sock));
+
+  sockList[s_fd(sock)] = 0;
+}
+
+/* engine event loop */
+static void
+engine_loop(struct Generators* gen)
+{
+  struct kevent events[POLLS_PER_KQUEUE];
+  struct Socket* sock;
+  struct timespec wait;
+  int nevs;
+  int i;
+  int errcode;
+  size_t codesize;
+
+  while (running) {
+    /* set up the sleep time */
+    wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1;
+    wait.tv_nsec = 0;
+
+    Debug((DEBUG_INFO, "kqueue: delay: %Tu (%Tu) %Tu", timer_next(gen),
+          CurrentTime, wait.tv_sec));
+
+    /* check for active events */
+    nevs = kevent(kqueue_id, 0, 0, events, POLLS_PER_KQUEUE,
+                 wait.tv_sec < 0 ? 0 : &wait);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nevs < 0) {
+      if (errno != EINTR) { /* ignore kevent interrupts */
+       /* Log the kqueue error */
+       log_write(LS_SOCKET, L_ERROR, 0, "kevent() error: %m");
+       if (!errors++)
+         timer_add(&clear_error, error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > KQUEUE_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many kevent errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; i < nevs; i++) {
+      if (events[i].filter == EVFILT_SIGNAL) {
+       /* it's a signal; deal appropriately */
+       event_generate(ET_SIGNAL, events[i].udata, events[i].ident);
+       continue; /* skip socket processing loop */
+      }
+
+      assert(events[i].filter == EVFILT_READ ||
+            events[i].filter == EVFILT_WRITE);
+
+      sock = sockList[events[i].ident];
+      if (!sock) /* slots may become empty while processing events */
+       continue;
+
+      assert(s_fd(sock) == events[i].ident);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "kqueue: Checking socket %p (fd %d) state %s, "
+            "events %s", sock, s_fd(sock), state_to_name(s_state(sock)),
+            sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                      &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "kqueue: Error %d on fd %d, socket %p", errcode,
+                s_fd(sock), sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak reference counts */
+         continue;
+       }
+      }
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (events[i].filter == EVFILT_WRITE) { /* connection completed */
+         Debug((DEBUG_ENGINE, "kqueue: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+       }
+       break;
+
+      case SS_LISTENING:
+       if (events[i].filter == EVFILT_READ) { /* connect. to be accept. */
+         Debug((DEBUG_ENGINE, "kqueue: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+       }
+       break;
+
+      case SS_NOTSOCK: /* doing nothing socket-specific */
+      case SS_CONNECTED:
+       if (events[i].filter == EVFILT_READ) { /* data on socket */
+         Debug((DEBUG_ENGINE, "kqueue: EOF or data to be read"));
+         event_generate(events[i].flags & EV_EOF ? ET_EOF : ET_READ, sock, 0);
+       }
+       if (events[i].filter == EVFILT_WRITE) { /* socket writable */
+         Debug((DEBUG_ENGINE, "kqueue: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (events[i].filter == EVFILT_READ) { /* socket readable */
+         Debug((DEBUG_ENGINE, "kqueue: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (events[i].filter == EVFILT_WRITE) { /* socket writable */
+         Debug((DEBUG_ENGINE, "kqueue: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       break;
+      }
+
+      assert(s_fd(sock) == events[i].ident);
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+struct Engine engine_kqueue = {
+  "kqueue()",          /* Engine name */
+  engine_init,         /* Engine initialization function */
+  engine_signal,       /* Engine signal registration function */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/engine_poll.c b/ircd/engine_poll.c
new file mode 100644 (file)
index 0000000..aa8dc2a
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_poll.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#define POLL_ERROR_THRESHOLD   20      /* after 20 poll errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /* expire errors after an hour */
+
+/* Figure out what bits to set for read */
+#if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
+#elif defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLIN|POLLRDNORM)
+#elif defined(POLLIN)
+#  define POLLREADFLAGS POLLIN
+#elif defined(POLLRDNORM)
+#  define POLLREADFLAGS POLLRDNORM
+#endif
+
+/* Figure out what bits to set for write */
+#if defined(POLLOUT) && defined(POLLWRNORM)
+#  define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
+#elif defined(POLLOUT)
+#  define POLLWRITEFLAGS POLLOUT
+#elif defined(POLLWRNORM)
+#  define POLLWRITEFLAGS POLLWRNORM
+#endif
+
+/* Figure out what bits indicate errors */
+#ifdef POLLHUP
+#  define POLLERRORS (POLLHUP|POLLERR)
+#else
+#  define POLLERRORS POLLERR
+#endif
+
+static struct Socket** sockList;
+static struct pollfd* pollfdList;
+static unsigned int poll_count;
+static unsigned int poll_max;
+
+static int errors = 0;
+static struct Timer clear_error;
+
+/* decrements the error count once per hour */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/* initialize the poll engine */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  /* allocate necessary memory */
+  sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
+  pollfdList = (struct pollfd*) MyMalloc(sizeof(struct pollfd) * max_sockets);
+
+  /* initialize the data */
+  for (i = 0; i < max_sockets; i++) {
+    sockList[i] = 0;
+    pollfdList[i].fd = -1;
+    pollfdList[i].events = 0;
+    pollfdList[i].revents = 0;
+  }
+
+  poll_count = 0; /* nothing in set */
+  poll_max = max_sockets; /* number of sockets allocated */
+
+  return 1;
+}
+
+/* Figure out what events go with a given state */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/* Toggle bits in the pollfd structs correctly */
+static void
+set_or_clear(int idx, unsigned int clear, unsigned int set)
+{
+  if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
+    if (set & SOCK_EVENT_READABLE) /* it's set */
+      pollfdList[idx].events |= POLLREADFLAGS;
+    else /* clear it */
+      pollfdList[idx].events &= ~POLLREADFLAGS;
+  }
+
+  if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
+    if (set & SOCK_EVENT_WRITABLE) /* it's set */
+      pollfdList[idx].events |= POLLWRITEFLAGS;
+    else /* clear it */
+      pollfdList[idx].events &= ~POLLWRITEFLAGS;
+  }
+}
+
+/* add a socket to be listened on */
+static int
+engine_add(struct Socket* sock)
+{
+  int i;
+
+  assert(0 != sock);
+
+  for (i = 0; sockList[i] && i < poll_count; i++) /* Find an empty slot */
+    ;
+
+  Debug((DEBUG_ENGINE, "poll: Looking at slot %d, contents %p", i,
+        sockList[i]));
+
+  if (i >= poll_count) { /* ok, need to allocate another off the list */
+    if (poll_count >= poll_max) { /* bounds-check... */
+      log_write(LS_SYSTEM, L_ERROR, 0,
+               "Attempt to add socket %d (> %d) to event engine", sock->s_fd,
+               poll_max);
+      return 0;
+    }
+
+    i = poll_count++;
+    Debug((DEBUG_ENGINE, "poll: Allocating a new slot: %d", i));
+  }
+
+  s_ed_int(sock) = i; /* set engine data */
+  sockList[i] = sock; /* enter socket into data structures */
+  pollfdList[i].fd = s_fd(sock);
+
+  Debug((DEBUG_ENGINE, "poll: Adding socket %d to engine on %d [%p], state %s",
+        s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
+
+  /* set the appropriate bits */
+  set_or_clear(i, 0, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/* socket switching to new state */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_ed_int(sock)]);
+  assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
+
+  Debug((DEBUG_ENGINE, "poll: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_or_clear(s_ed_int(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old state */
+              state_to_events(new_state, s_events(sock))); /* new state */
+}
+
+/* socket events changing */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_ed_int(sock)]);
+  assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
+
+  Debug((DEBUG_ENGINE, "poll: Changing event mask for socket %p to [%s]", sock,
+        sock_flags(new_events)));
+
+  /* set the correct events */
+  set_or_clear(s_ed_int(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old events */
+              state_to_events(s_state(sock), new_events)); /* new events */
+}
+
+/* socket going away */
+static void
+engine_delete(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_ed_int(sock)]);
+  assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
+
+  Debug((DEBUG_ENGINE, "poll: Deleting socket %d (%d) [%p], state %s",
+        s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
+
+  /* clear the events */
+  pollfdList[s_ed_int(sock)].fd = -1;
+  pollfdList[s_ed_int(sock)].events = 0;
+
+  /* zero the socket list entry */
+  sockList[s_ed_int(sock)] = 0;
+
+  /* update poll_count */
+  while (poll_count > 0 && sockList[poll_count - 1] == 0)
+    poll_count--;
+}
+
+/* socket event loop */
+static void
+engine_loop(struct Generators* gen)
+{
+  int wait;
+  int nfds;
+  int i;
+  int errcode;
+  size_t codesize;
+  struct Socket *sock;
+
+  while (running) {
+    wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
+
+    Debug((DEBUG_INFO, "poll: delay: %Tu (%Tu) %d", timer_next(gen),
+          CurrentTime, wait));
+
+    /* check for active files */
+    nfds = poll(pollfdList, poll_count, wait);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nfds < 0) {
+      if (errno != EINTR) { /* ignore poll interrupts */
+       /* Log the poll error */
+       log_write(LS_SOCKET, L_ERROR, 0, "poll() error: %m");
+       if (!errors++)
+         timer_add(&clear_error, error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > POLL_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many poll errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; nfds && i < poll_count; i++) {
+      if (!(sock = sockList[i])) /* skip empty socket elements */
+       continue;
+
+      assert(s_fd(sock) == pollfdList[i].fd);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "poll: Checking socket %p (fd %d, index %d, "
+            "state %s, events %s", sock, s_fd(sock), i,
+            state_to_name(s_state(sock)), sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
+                      &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "poll: Error %d on fd %d (index %d), socket %p",
+                errcode, s_fd(sock), i, sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak ref counts */
+         nfds--;
+         continue;
+       }
+      }
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (pollfdList[i].revents & POLLWRITEFLAGS) { /* connect completed */
+         Debug((DEBUG_ENGINE, "poll: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_LISTENING:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* ready for accept */
+         Debug((DEBUG_ENGINE, "poll: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_NOTSOCK:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
+         /* can't peek; it's not a socket */
+         Debug((DEBUG_ENGINE, "poll: non-socket readable"));
+         event_generate(ET_READ, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_CONNECTED:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
+         char c;
+
+         switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */
+         case -1: /* error occurred?!? */
+           if (errno == EAGAIN) {
+             Debug((DEBUG_ENGINE, "poll: Resource temporarily unavailable?"));
+             continue;
+           }
+           Debug((DEBUG_ENGINE, "poll: Uncaught error!"));
+           event_generate(ET_ERROR, sock, errno);
+           break;
+
+         case 0: /* EOF from client */
+           Debug((DEBUG_ENGINE, "poll: EOF from client"));
+           event_generate(ET_EOF, sock, 0);
+           break;
+
+         default: /* some data can be read */
+           Debug((DEBUG_ENGINE, "poll: Data to be read"));
+           event_generate(ET_READ, sock, 0);
+           break;
+         }
+       }
+       if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "poll: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
+         nfds--;
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (pollfdList[i].revents & POLLREADFLAGS) { /* socket readable */
+         Debug((DEBUG_ENGINE, "poll: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
+         Debug((DEBUG_ENGINE, "poll: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
+         nfds--;
+       break;
+      }
+
+      assert(s_fd(sock) == pollfdList[i].fd);
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+struct Engine engine_poll = {
+  "poll()",            /* Engine name */
+  engine_init,         /* Engine initialization function */
+  0,                   /* Engine signal registration function */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
diff --git a/ircd/engine_select.c b/ircd/engine_select.c
new file mode 100644 (file)
index 0000000..f09c771
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * IRC - Internet Relay Chat, ircd/engine_select.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+
+/* On BSD, define FD_SETSIZE to what we want before including sys/types.h */
+#if  defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__)
+# if !defined(FD_SETSIZE)
+#  define FD_SETSIZE   MAXCONNECTIONS
+# endif
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#define SELECT_ERROR_THRESHOLD 20      /* after 20 select errors, restart */
+#define ERROR_EXPIRE_TIME      3600    /* expire errors after an hour */
+
+static struct Socket* sockList[FD_SETSIZE];
+static int highest_fd;
+static fd_set global_read_set;
+static fd_set global_write_set;
+
+static int errors = 0;
+static struct Timer clear_error;
+
+/* decrements the error count once per hour */
+static void
+error_clear(struct Event* ev)
+{
+  if (!--errors) /* remove timer when error count reaches 0 */
+    timer_del(ev_timer(ev));
+}
+
+/* initialize the select engine */
+static int
+engine_init(int max_sockets)
+{
+  int i;
+
+  if (max_sockets > FD_SETSIZE) { /* too many sockets */
+    log_write(LS_SYSTEM, L_WARNING, 0,
+             "select() engine cannot handle %d sockets (> %d)",
+             max_sockets, FD_SETSIZE);
+    return 0;
+  }
+
+  FD_ZERO(&global_read_set); /* zero the global fd sets */
+  FD_ZERO(&global_write_set);
+
+  for (i = 0; i < FD_SETSIZE; i++) /* zero the sockList */
+    sockList[i] = 0;
+
+  highest_fd = -1; /* No fds in set */
+
+  return 1; /* initialization successful */
+}
+
+/* Figure out what events go with a given state */
+static unsigned int
+state_to_events(enum SocketState state, unsigned int events)
+{
+  switch (state) {
+  case SS_CONNECTING: /* connecting socket */
+    return SOCK_EVENT_WRITABLE;
+    break;
+
+  case SS_LISTENING: /* listening socket */
+  case SS_NOTSOCK: /* our signal socket */
+    return SOCK_EVENT_READABLE;
+    break;
+
+  case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
+    return events; /* ordinary socket */
+    break;
+  }
+
+  /*NOTREACHED*/
+  return 0;
+}
+
+/* Toggle bits in the global fd sets appropriately */
+static void
+set_or_clear(int fd, unsigned int clear, unsigned int set)
+{
+  if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
+    if (set & SOCK_EVENT_READABLE) /* it's set */
+      FD_SET(fd, &global_read_set);
+    else /* clear it */
+      FD_CLR(fd, &global_read_set);
+  }
+
+  if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
+    if (set & SOCK_EVENT_WRITABLE) /* it's set */
+      FD_SET(fd, &global_write_set);
+    else /* clear it */
+      FD_CLR(fd, &global_write_set);
+  }
+}
+
+/* add a socket to be listened on */
+static int
+engine_add(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(0 == sockList[s_fd(sock)]);
+
+  /* bounds-check... */
+  if (s_fd(sock) >= FD_SETSIZE) {
+    log_write(LS_SYSTEM, L_ERROR, 0,
+             "Attempt to add socket %d (> %d) to event engine", s_fd(sock),
+             FD_SETSIZE);
+    return 0;
+  }
+
+  sockList[s_fd(sock)] = sock; /* add to list */
+
+  if (s_fd(sock) >= highest_fd) /* update highest_fd */
+    highest_fd = s_fd(sock);
+
+  Debug((DEBUG_ENGINE, "select: Adding socket %d to engine [%p], state %s",
+        s_fd(sock), sock, state_to_name(s_state(sock))));
+
+  /* set the fd set bits */
+  set_or_clear(s_fd(sock), 0, state_to_events(s_state(sock), s_events(sock)));
+
+  return 1; /* success */
+}
+
+/* socket switching to new state */
+static void
+engine_state(struct Socket* sock, enum SocketState new_state)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "select: Changing state for socket %p to %s", sock,
+        state_to_name(new_state)));
+
+  /* set the correct events */
+  set_or_clear(s_fd(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old state */
+              state_to_events(new_state, s_events(sock))); /* new state */
+}
+
+/* socket events changing */
+static void
+engine_events(struct Socket* sock, unsigned int new_events)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "select: Changing event mask for socket %p to [%s]",
+        sock, sock_flags(new_events)));
+
+  /* set the correct events */
+  set_or_clear(s_fd(sock),
+              state_to_events(s_state(sock), s_events(sock)), /* old events */
+              state_to_events(s_state(sock), new_events)); /* new events */
+}
+
+/* socket going away */
+static void
+engine_delete(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(sock == sockList[s_fd(sock)]);
+
+  Debug((DEBUG_ENGINE, "select: Deleting socket %d [%p], state %s", s_fd(sock),
+        sock, state_to_name(s_state(sock))));
+
+  FD_CLR(s_fd(sock), &global_read_set); /* clear event set bits */
+  FD_CLR(s_fd(sock), &global_write_set);
+
+  sockList[s_fd(sock)] = 0; /* zero the socket list entry */
+
+  while (highest_fd > -1 && sockList[highest_fd] == 0) /* update highest_fd */
+    highest_fd--;
+}
+
+/* engine event loop */
+static void
+engine_loop(struct Generators* gen)
+{
+  struct timeval wait;
+  fd_set read_set;
+  fd_set write_set;
+  int nfds;
+  int i;
+  int errcode;
+  size_t codesize;
+  struct Socket *sock;
+
+  while (running) {
+    read_set = global_read_set; /* all hail structure copy!! */
+    write_set = global_write_set;
+
+    /* set up the sleep time */
+    wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1;
+    wait.tv_usec = 0;
+
+    Debug((DEBUG_INFO, "select: delay: %Tu (%Tu) %Tu", timer_next(gen),
+          CurrentTime, wait.tv_sec));
+
+    /* check for active files */
+    nfds = select(highest_fd + 1, &read_set, &write_set, 0,
+                 wait.tv_sec < 0 ? 0 : &wait);
+
+    CurrentTime = time(0); /* set current time... */
+
+    if (nfds < 0) {
+      if (errno != EINTR) { /* ignore select interrupts */
+       /* Log the select error */
+       log_write(LS_SOCKET, L_ERROR, 0, "select() error: %m");
+       if (!errors++)
+         timer_add(&clear_error, error_clear, 0, TT_PERIODIC,
+                   ERROR_EXPIRE_TIME);
+       else if (errors > SELECT_ERROR_THRESHOLD) /* too many errors... */
+         server_restart("too many select errors");
+      }
+      /* old code did a sleep(1) here; with usage these days,
+       * that may be too expensive
+       */
+      continue;
+    }
+
+    for (i = 0; nfds && i <= highest_fd; i++) {
+      if (!(sock = sockList[i])) /* skip empty socket elements */
+       continue;
+
+      assert(s_fd(sock) == i);
+
+      gen_ref_inc(sock); /* can't have it going away on us */
+
+      Debug((DEBUG_ENGINE, "select: Checking socket %p (fd %d) state %s, "
+            "events %s", sock, i, state_to_name(s_state(sock)),
+            sock_flags(s_events(sock))));
+
+      if (s_state(sock) != SS_NOTSOCK) {
+       errcode = 0; /* check for errors on socket */
+       codesize = sizeof(errcode);
+       if (getsockopt(i, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+         errcode = errno; /* work around Solaris implementation */
+
+       if (errcode) { /* an error occurred; generate an event */
+         Debug((DEBUG_ENGINE, "select: Error %d on fd %d, socket %p", errcode,
+                i, sock));
+         event_generate(ET_ERROR, sock, errcode);
+         gen_ref_dec(sock); /* careful not to leak reference counts */
+         continue;
+       }
+      }
+
+      switch (s_state(sock)) {
+      case SS_CONNECTING:
+       if (FD_ISSET(i, &write_set)) { /* connection completed */
+         Debug((DEBUG_ENGINE, "select: Connection completed"));
+         event_generate(ET_CONNECT, sock, 0);
+         nfds--;
+         continue;
+       }
+       break;
+
+      case SS_LISTENING:
+       if (FD_ISSET(i, &read_set)) { /* connection to be accepted */
+         Debug((DEBUG_ENGINE, "select: Ready for accept"));
+         event_generate(ET_ACCEPT, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_NOTSOCK:
+       if (FD_ISSET(i, &read_set)) { /* data on socket */
+         /* can't peek; it's not a socket */
+         Debug((DEBUG_ENGINE, "select: non-socket readable"));
+         event_generate(ET_READ, sock, 0);
+         nfds--;
+       }
+       break;
+
+      case SS_CONNECTED:
+       if (FD_ISSET(i, &read_set)) { /* data to be read from socket */
+         char c;
+
+         switch (recv(i, &c, 1, MSG_PEEK)) { /* check for EOF */
+         case -1: /* error occurred?!? */
+           if (errno == EAGAIN) {
+             Debug((DEBUG_ENGINE, "select: Resource temporarily "
+                    "unavailable?"));
+             continue;
+           }
+           Debug((DEBUG_ENGINE, "select: Uncaught error!"));
+           event_generate(ET_ERROR, sock, errno);
+           break;
+
+         case 0: /* EOF from client */
+           Debug((DEBUG_ENGINE, "select: EOF from client"));
+           event_generate(ET_EOF, sock, 0);
+           break;
+
+         default: /* some data can be read */
+           Debug((DEBUG_ENGINE, "select: Data to be read"));
+           event_generate(ET_READ, sock, 0);
+           break;
+         }
+       }
+       if (FD_ISSET(i, &write_set)) { /* data can be written to socket */
+         Debug((DEBUG_ENGINE, "select: Data can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (FD_ISSET(i, &read_set) || FD_ISSET(i, &write_set))
+         nfds--;
+       break;
+
+      case SS_DATAGRAM: case SS_CONNECTDG:
+       if (FD_ISSET(i, &read_set)) { /* data to be read from socket */
+         Debug((DEBUG_ENGINE, "select: Datagram to be read"));
+         event_generate(ET_READ, sock, 0);
+       }
+       if (FD_ISSET(i, &write_set)) { /* data can be written to socket */
+         Debug((DEBUG_ENGINE, "select: Datagram can be written"));
+         event_generate(ET_WRITE, sock, 0);
+       }
+       if (FD_ISSET(i, &read_set) || FD_ISSET(i, &write_set))
+         nfds--;
+       break;
+      }
+
+      assert(s_fd(sock) == i);
+
+      gen_ref_dec(sock); /* we're done with it */
+    }
+
+    timer_run(); /* execute any pending timers */
+  }
+}
+
+struct Engine engine_select = {
+  "select()",          /* Engine name */
+  engine_init,         /* Engine initialization function */
+  0,                   /* Engine signal registration function (none) */
+  engine_add,          /* Engine socket registration function */
+  engine_state,                /* Engine socket state change function */
+  engine_events,       /* Engine socket events mask function */
+  engine_delete,       /* Engine socket deletion function */
+  engine_loop          /* Core engine event loop */
+};
index 97ff9f1f8f11c41b93e320e4cab8229b40bde258..cfee4af807282c030b1719c438956a87ff32bdc7 100644 (file)
@@ -28,6 +28,7 @@
 #include "crule.h"
 #include "hash.h"
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "ircd_features.h"
 #include "ircd_log.h"
 #include "ircd_reply.h"
@@ -100,11 +101,12 @@ int            debuglevel        = -1;    /* Server debug level  */
 char          *debugmode         = "";    /* Server debug level */
 static char   *dpath             = DPATH;
 
-time_t         nextconnect       = 1; /* time for next try_connections call */
-time_t         nextping          = 1; /* same as above for check_pings() */
+static struct Timer connect_timer; /* timer structure for try_connections() */
+static struct Timer ping_timer; /* timer structure for check_pings() */
 
 static struct Daemon thisServer  = { 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0 };
 
+int running = 1;
 
 
 /*----------------------------------------------------------------------------
@@ -115,7 +117,7 @@ void server_die(const char* message) {
   log_write(LS_SYSTEM, L_CRIT, 0, "Server terminating: %s", message);
   flush_connections(0);
   close_connections(1);
-  thisServer.running = 0;
+  running = 0;
 }
 
 
@@ -215,7 +217,7 @@ static int check_pid(void)
  * function should be made latest. (No harm done if this
  * is called earlier or later...)
  *--------------------------------------------------------------------------*/
-static time_t try_connections(void) {
+static void try_connections(struct Event* ev) {
   struct ConfItem*  aconf;
   struct Client*    cptr;
   struct ConfItem** pconf;
@@ -227,6 +229,9 @@ static time_t try_connections(void) {
   struct Jupe*      ajupe;
   unsigned int      con_class   = 0;
 
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
   connecting = FALSE;
   Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(CurrentTime)));
   for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
@@ -286,8 +291,12 @@ static time_t try_connections(void) {
                           con_conf->name);
   }
 
+  if (next == 0)
+    next = CurrentTime + feature_int(FEAT_CONNECTFREQUENCY);
+
   Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
-  return(next);
+
+  timer_add(&connect_timer, try_connections, 0, TT_ABSOLUTE, next);
 }
 
 
@@ -298,12 +307,15 @@ static time_t try_connections(void) {
  *       get right down to it.  Can't really be done until the server is more
  *       modular, however...
  *--------------------------------------------------------------------------*/
-static time_t check_pings(void) {
-  int expire     = 0; 
+static void check_pings(struct Event* ev) {
+  int expire     = 0;
   int next_check = CurrentTime;
   int max_ping   = 0;
   int i;
 
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
   next_check += feature_int(FEAT_PINGFREQUENCY);
   
   /* Scan through the client table */
@@ -326,7 +338,8 @@ static time_t check_pings(void) {
       feature_int(FEAT_CONNECTTIMEOUT);
    
     Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d",
-          cli_name(cptr), (cli_flags(cptr) & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", 
+          cli_name(cptr),
+          (cli_flags(cptr) & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", 
           max_ping, (int)(CurrentTime - cli_lasttime(cptr))));
           
 
@@ -345,7 +358,8 @@ static time_t check_pings(void) {
       /* If it was a server, then tell ops about it. */
       if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
        sendto_opmask_butone(0, SNO_OLDSNO,
-                            "No response from %s, closing link", cli_name(cptr));
+                            "No response from %s, closing link",
+                            cli_name(cptr));
       exit_client_msg(cptr, cptr, &me, "Ping timeout");
       continue;
     }
@@ -395,7 +409,7 @@ static time_t check_pings(void) {
   Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is",
         CurrentTime, next_check-CurrentTime));
   
-  return next_check;
+  timer_add(&ping_timer, check_pings, 0, TT_ABSOLUTE, next_check);
 }
 
 
@@ -468,71 +482,6 @@ static void daemon_init(int no_fork) {
   setsid();
 }
 
-
-/*----------------------------------------------------------------------------
- * event_loop
- *--------------------------------------------------------------------------*/
-static void event_loop(void) {
-  time_t nextdnscheck = 0;
-  time_t delay        = 0;
-
-  thisServer.running = 1;
-  while (thisServer.running) {
-    /* We only want to connect if a connection is due, not every time through.
-     * Note, if there are no active C lines, this call to Tryconnections is
-     * made once only; it will return 0. - avalon
-     */
-    if (nextconnect && CurrentTime >= nextconnect)
-      nextconnect = try_connections();
-
-    /* DNS checks. One to timeout queries, one for cache expiries. */
-    nextdnscheck = timeout_resolver(CurrentTime);
-
-    /* Take the smaller of the two 'timed' event times as the time of next
-     * event (stops us being late :) - avalon
-     * WARNING - nextconnect can return 0!
-     */
-    if (nextconnect)
-      delay = IRCD_MIN(nextping, nextconnect);
-    else
-      delay = nextping;
-
-    delay = IRCD_MIN(nextdnscheck, delay) - CurrentTime;
-
-    /* Adjust delay to something reasonable [ad hoc values] (one might think
-     * something more clever here... --msa) We don't really need to check that
-     * often and as long as we don't delay too long, everything should be ok.
-     * waiting too long can cause things to timeout...  i.e. PINGS -> a
-     * disconnection :( - avalon
-     */
-    if (delay < 1)
-      read_message(1);
-    else
-      read_message(IRCD_MIN(delay, feature_int(FEAT_TIMESEC)));
-
-    /* ...perhaps should not do these loops every time, but only if there is
-     * some chance of something happening (but, note that conf->hold times may
-     * be changed elsewhere--so precomputed next event time might be too far
-     * away... (similarly with ping times) --msa
-     */
-    if (CurrentTime >= nextping)
-      nextping = check_pings();
-    
-    /* timeout pending queries that haven't been responded to */
-    timeout_auth_queries(CurrentTime);
-
-    IPcheck_expire();
-
-    if (GlobalRehashFlag) {
-      rehash(&me, 1);
-      GlobalRehashFlag = 0;
-    }
-
-    if (GlobalRestartFlag)
-      server_restart("caught signal: SIGINT");
-  }
-}
-
 /*----------------------------------------------------------------------------
  * check_file_access:  random helper function to make sure that a file is
  *                     accessible in a certain way, and complain if not.
@@ -672,6 +621,7 @@ int main(int argc, char **argv) {
 
   debug_init(thisServer.bootopt & BOOT_TTY);
   daemon_init(thisServer.bootopt & BOOT_TTY);
+  event_init(MAXCONNECTIONS);
 
   setup_signals();
   feature_init(); /* initialize features... */
@@ -709,9 +659,14 @@ int main(int argc, char **argv) {
 
   uping_init();
 
+  IPcheck_init();
+  timer_add(&connect_timer, try_connections, 0, TT_RELATIVE, 1);
+  timer_add(&ping_timer, check_pings, 0, TT_RELATIVE, 1);
+
   CurrentTime = time(NULL);
 
   SetMe(&me);
+  cli_magic(&me) = CLIENT_MAGIC;
   cli_from(&me) = &me;
   make_server(&me);
 
diff --git a/ircd/ircd_events.c b/ircd/ircd_events.c
new file mode 100644 (file)
index 0000000..6befeae
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_events.c
+ * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "config.h"
+
+#include "ircd_events.h"
+
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_snprintf.h"
+#include "s_debug.h"
+
+#include <assert.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define SIGS_PER_SOCK  10      /* number of signals to process per socket
+                                  readable event */
+
+#ifdef USE_KQUEUE
+extern struct Engine engine_kqueue;
+#define ENGINE_KQUEUE  &engine_kqueue,
+#else
+#define ENGINE_KQUEUE
+#endif /* USE_KQUEUE */
+
+#ifdef USE_DEVPOLL
+extern struct Engine engine_devpoll;
+#define ENGINE_DEVPOLL &engine_devpoll,
+#else
+#define ENGINE_DEVPOLL
+#endif /* USE_DEVPOLL */
+
+#ifdef USE_POLL
+extern struct Engine engine_poll;
+#define ENGINE_FALLBACK        &engine_poll,
+#else
+extern struct Engine engine_select;
+#define ENGINE_FALLBACK        &engine_select,
+#endif /* USE_POLL */
+
+/* list of engines to try */
+static const struct Engine *evEngines[] = {
+  ENGINE_KQUEUE
+  ENGINE_DEVPOLL
+  ENGINE_FALLBACK
+  0
+};
+
+/* signal routines pipe data */
+static struct {
+  int          fd;     /* signal routine's fd */
+  struct Socket        sock;   /* and its struct Socket */
+} sigInfo = { -1 };
+
+/* All the thread info */
+static struct {
+  struct Generators    gens;           /* List of all generators */
+  struct Event*               events_free;     /* struct Event free list */
+  unsigned int        events_alloc;    /* count of allocated struct Events */
+  const struct Engine* engine;         /* core engine being used */
+#ifdef IRCD_THREADED
+  struct GenHeader*    genq_head;      /* head of generator event queue */
+  struct GenHeader*    genq_tail;      /* tail of generator event queue */
+  unsigned int        genq_count;      /* count of generators on queue */
+#endif
+} evInfo = {
+  { 0, 0, 0 },
+  0, 0, 0
+#ifdef IRCD_THREADED
+  , 0, 0, 0
+#endif
+};
+
+/* Initialize a struct GenHeader */
+static void
+gen_init(struct GenHeader* gen, EventCallBack call, void* data,
+        struct GenHeader* next, struct GenHeader** prev_p)
+{
+  assert(0 != gen);
+
+  gen->gh_next = next;
+  gen->gh_prev_p = prev_p;
+#ifdef IRCD_THREADED
+  gen->gh_qnext = 0;
+  gen->gh_qprev_p = 0;
+  gen->gh_head = 0;
+  gen->gh_tail = 0;
+#endif
+  gen->gh_flags = GEN_ACTIVE;
+  gen->gh_ref = 0;
+  gen->gh_call = call;
+  gen->gh_data = data;
+  gen->gh_engdata.ed_int = 0;
+
+  if (prev_p) { /* Going to link into list? */
+    if (next) /* do so */
+      next->gh_prev_p = &gen->gh_next;
+    *prev_p = gen;
+  }
+}
+
+/* Execute an event; optimizations should inline this */
+static void
+event_execute(struct Event* event)
+{
+  assert(0 != event);
+  assert(0 == event->ev_prev_p); /* must be off queue first */
+  assert(event->ev_gen.gen_header->gh_flags & GEN_ACTIVE);
+
+  if (event->ev_type == ET_DESTROY) /* turn off active flag *before* destroy */
+    event->ev_gen.gen_header->gh_flags &= ~GEN_ACTIVE;
+
+  (*event->ev_gen.gen_header->gh_call)(event); /* execute the event */
+
+  /* The logic here is very careful; if the event was an ET_DESTROY,
+   * then we must assume the generator is now invalid; fortunately, we
+   * don't need to do anything to it if so.  Otherwise, we decrement
+   * the reference count; if reference count goes to zero, AND we need
+   * to destroy the generator, THEN we generate a DESTROY event.
+   */
+  if (event->ev_type != ET_DESTROY)
+    gen_ref_dec(event->ev_gen.gen_header);
+
+  event->ev_gen.gen_header = 0; /* clear event data */
+  event->ev_type = ET_DESTROY;
+
+  event->ev_next = evInfo.events_free; /* add to free list */
+  evInfo.events_free = event;
+}
+
+#ifndef IRCD_THREADED
+/* we synchronously execute the event when not threaded */
+#define event_add(event)       \
+do {                                                                         \
+  struct Event* _ev = (event);                                               \
+  _ev->ev_next = 0;                                                          \
+  _ev->ev_prev_p = 0;                                                        \
+  event_execute(_ev);                                                        \
+} while (0)
+
+#else
+/* add an event to the work queue */
+/* This is just a placeholder; don't expect ircd to be threaded soon */
+/* There should be locks all over the place in here */
+static void
+event_add(struct Event* event)
+{
+  struct GenHeader* gen;
+
+  assert(0 != event);
+
+  gen = event->ev_gen.gen_header;
+
+  /* First, place event on generator's event queue */
+  event->ev_next = 0;
+  if (gen->gh_head) {
+    assert(0 != gen->gh_tail);
+
+    event->ev_prev_p = &gen->gh_tail->ev_next;
+    gen->gh_tail->ev_next = event;
+    gen->gh_tail = event;
+  } else { /* queue was empty */
+    assert(0 == gen->gh_tail);
+
+    event->ev_prev_p = &gen->gh_head;
+    gen->gh_head = event;
+    gen->gh_tail = event;
+  }
+
+  /* Now, if the generator isn't on the queue yet... */
+  if (!gen->gh_qprev_p) {
+    gen->gh_qnext = 0;
+    if (evInfo.genq_head) {
+      assert(0 != evInfo.genq_tail);
+
+      gen->gh_qprev_p = &evInfo.genq_tail->gh_qnext;
+      evInfo.genq_tail->gh_qnext = gen;
+      evInfo.genq_tail = gen;
+    } else { /* queue was empty */
+      assert(0 == evInfo.genq_tail);
+
+      gen->gh_qprev_p = &evInfo.genq_head;
+      evInfo.genq_head = gen;
+      evInfo.genq_tail = gen;
+    }
+
+    /* We'd also have to signal the work crew here */
+  }
+}
+#endif /* IRCD_THREADED */
+
+/* Place a timer in the correct spot on the queue */
+static void
+timer_enqueue(struct Timer* timer)
+{
+  struct Timer** ptr_p;
+
+  assert(0 != timer);
+  assert(0 == timer->t_header.gh_prev_p); /* not already on queue */
+
+  /* Calculate expire time */
+  switch (timer->t_type) {
+  case TT_ABSOLUTE: /* no need to consider it relative */
+    timer->t_expire = timer->t_value;
+    break;
+
+  case TT_RELATIVE: case TT_PERIODIC: /* relative timer */
+    timer->t_expire = timer->t_value + CurrentTime;
+    break;
+  }
+
+  /* Find a slot to insert timer */
+  for (ptr_p = &evInfo.gens.g_timer; ;
+       ptr_p = (struct Timer**) &(*ptr_p)->t_header.gh_next)
+    if (!*ptr_p || timer->t_expire < (*ptr_p)->t_expire)
+      break;
+
+  /* link it in the right place */
+  timer->t_header.gh_next = (struct GenHeader*) *ptr_p;
+  timer->t_header.gh_prev_p = (struct GenHeader**) ptr_p;
+  if (*ptr_p)
+    (*ptr_p)->t_header.gh_prev_p = &timer->t_header.gh_next;
+  *ptr_p = timer;
+}
+
+/* signal handler for writing signal notification to pipe */
+static void
+signal_handler(int sig)
+{
+  unsigned char c;
+
+  assert(sigInfo.fd >= 0);
+
+  c = (unsigned char) sig; /* only write 1 byte to identify sig */
+
+  write(sigInfo.fd, &c, 1);
+}
+
+/* callback for signal "socket" events */
+static void
+signal_callback(struct Event* event)
+{
+  unsigned char sigstr[SIGS_PER_SOCK];
+  int sig, n_sigs, i;
+  struct Signal* ptr;
+
+  assert(event->ev_type == ET_READ); /* readable events only */
+
+  n_sigs = read(event->ev_gen.gen_socket->s_fd, sigstr, sizeof(sigstr));
+
+  for (i = 0; i < n_sigs; i++) {
+    sig = (int) sigstr[i]; /* get signal */
+
+    for (ptr = evInfo.gens.g_signal; ptr;
+        ptr = (struct Signal*) ptr->sig_header.gh_next)
+      if (ptr->sig_signal == sig) /* find its descriptor... */
+       break;
+
+    if (ptr)
+      event_generate(ET_SIGNAL, ptr, sig); /* generate signal event */
+  }
+}
+
+/* Remove something from its queue */
+void
+gen_dequeue(void* arg)
+{
+  struct GenHeader* gen = (struct GenHeader*) arg;
+
+  if (gen->gh_next) /* clip it out of the list */
+    gen->gh_next->gh_prev_p = gen->gh_prev_p;
+  if (gen->gh_prev_p)
+    *gen->gh_prev_p = gen->gh_next;
+
+  gen->gh_next = 0; /* mark that it's not in the list anymore */
+  gen->gh_prev_p = 0;
+}
+
+/* Initializes the event system */
+void
+event_init(int max_sockets)
+{
+  int i, p[2];
+
+  for (i = 0; evEngines[i]; i++) { /* look for an engine... */
+    assert(0 != evEngines[i]->eng_name);
+    assert(0 != evEngines[i]->eng_init);
+
+    if ((*evEngines[i]->eng_init)(max_sockets))
+      break; /* Found an engine that'll work */
+  }
+
+  assert(0 != evEngines[i]);
+
+  evInfo.engine = evEngines[i]; /* save engine */
+
+  if (!evInfo.engine->eng_signal) { /* engine can't do signals */
+    if (pipe(p)) {
+      log_write(LS_SYSTEM, L_CRIT, 0, "Failed to open signal pipe");
+      exit(8);
+    }
+
+    sigInfo.fd = p[1]; /* write end of pipe */
+    socket_add(&sigInfo.sock, signal_callback, 0, SS_NOTSOCK,
+              SOCK_EVENT_READABLE, p[0]); /* read end of pipe */
+  }
+}
+
+/* Do the event loop */
+void
+event_loop(void)
+{
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_loop);
+
+  (*evInfo.engine->eng_loop)(&evInfo.gens);
+}
+
+/* Generate an event and add it to the queue (or execute it) */
+void
+event_generate(enum EventType type, void* arg, int data)
+{
+  struct Event* ptr;
+  struct GenHeader* gen = (struct GenHeader*) arg;
+
+  assert(0 != gen);
+
+  /* don't create events (other than ET_DESTROY) for destroyed generators */
+  if (type != ET_DESTROY && (gen->gh_flags & GEN_DESTROY))
+    return;
+
+  Debug((DEBUG_LIST, "Generating event type %s for generator %p (%s)",
+        event_to_name(type), gen, gen_flags(gen->gh_flags)));
+
+  if ((ptr = evInfo.events_free))
+    evInfo.events_free = ptr->ev_next; /* pop one off the freelist */
+  else { /* allocate another structure */
+    ptr = (struct Event*) MyMalloc(sizeof(struct Event));
+    evInfo.events_alloc++; /* count of allocated events */
+  }
+
+  ptr->ev_type = type; /* Record event type */
+  ptr->ev_data = data;
+
+  ptr->ev_gen.gen_header = (struct GenHeader*) gen;
+  ptr->ev_gen.gen_header->gh_ref++;
+
+  event_add(ptr); /* add event to queue */
+}
+
+/* Add a timer to be processed */
+void
+timer_add(struct Timer* timer, EventCallBack call, void* data,
+         enum TimerType type, time_t value)
+{
+  assert(0 != timer);
+  assert(0 != call);
+
+  Debug((DEBUG_LIST, "Adding timer %p; time out %Tu (type %s)", timer, value,
+        timer_to_name(type)));
+
+  /* initialize a timer... */
+  gen_init((struct GenHeader*) timer, call, data, 0, 0);
+
+  timer->t_type = type;
+  timer->t_value = value;
+  timer->t_expire = 0;
+
+  timer_enqueue(timer); /* and enqueue it */
+}
+
+/* Remove a timer from the processing queue */
+void
+timer_del(struct Timer* timer)
+{
+  assert(0 != timer);
+
+  if (timer->t_header.gh_flags & GEN_MARKED)
+    return; /* timer already marked for destruction */
+
+  timer->t_header.gh_flags |= GEN_DESTROY;
+
+  Debug((DEBUG_LIST, "Deleting timer %p (type %s)", timer,
+        timer_to_name(timer->t_type)));
+
+  if (!timer->t_header.gh_ref) { /* not in use; destroy right now */
+    gen_dequeue(timer);
+    event_generate(ET_DESTROY, timer, 0);
+  }
+}
+
+/* Change the time a timer expires */
+void
+timer_chg(struct Timer* timer, enum TimerType type, time_t value)
+{
+  assert(0 != timer);
+  assert(0 != value);
+  assert(TT_PERIODIC != timer->t_type);
+  assert(TT_PERIODIC != type);
+
+  Debug((DEBUG_LIST, "Changing timer %p from type %s timeout %Tu to type %s "
+        "timeout %Tu", timer, timer_to_name(timer->t_type), timer->t_value,
+        timer_to_name(type), value));
+
+  gen_dequeue(timer); /* remove the timer from the queue */
+
+  timer->t_type = type; /* Set the new type and value */
+  timer->t_value = value;
+  timer->t_expire = 0;
+
+  timer_enqueue(timer); /* re-queue the timer */
+}
+
+/* Execute all expired timers */
+void
+timer_run(void)
+{
+  struct Timer* ptr;
+  struct Timer* next = 0;
+
+  /* go through queue... */
+  for (ptr = evInfo.gens.g_timer; ptr; ptr = next) {
+    next = (struct Timer*) ptr->t_header.gh_next;
+    if (CurrentTime < ptr->t_expire)
+      break; /* processed all pending timers */
+
+    gen_dequeue(ptr); /* must dequeue timer here */
+    if (ptr->t_type == TT_ABSOLUTE || ptr->t_type == TT_RELATIVE) {
+      Debug((DEBUG_LIST, "Marking timer %p for later destruction", ptr));
+      ptr->t_header.gh_flags |= GEN_MARKED; /* mark for destruction */
+    }
+    event_generate(ET_EXPIRE, ptr, 0); /* generate expire event */
+
+    if (ptr->t_header.gh_flags & (GEN_MARKED | GEN_DESTROY)) {
+      Debug((DEBUG_LIST, "Destroying timer %p", ptr));
+      event_generate(ET_DESTROY, ptr, 0);
+    } else if (ptr->t_type == TT_PERIODIC) {
+      Debug((DEBUG_LIST, "Re-enqueuing periodic timer %p", ptr));
+      timer_enqueue(ptr); /* re-queue periodic timer */
+    }
+  }
+}
+
+/* Adds a signal to the event callback system */
+void
+signal_add(struct Signal* signal, EventCallBack call, void* data, int sig)
+{
+  struct sigaction act;
+
+  assert(0 != signal);
+  assert(0 != call);
+  assert(0 != evInfo.engine);
+
+  /* set up struct */
+  gen_init((struct GenHeader*) signal, call, data,
+          (struct GenHeader*) evInfo.gens.g_signal,
+          (struct GenHeader**) &evInfo.gens.g_signal);
+
+  signal->sig_signal = sig;
+
+  if (evInfo.engine->eng_signal)
+    (*evInfo.engine->eng_signal)(signal); /* tell engine */
+  else {
+    act.sa_handler = signal_handler; /* set up signal handler */
+    act.sa_flags = 0;
+    sigemptyset(&act.sa_mask);
+    sigaction(sig, &act, 0);
+  }
+}
+
+/* Adds a socket to the event system */
+int
+socket_add(struct Socket* sock, EventCallBack call, void* data,
+          enum SocketState state, unsigned int events, int fd)
+{
+  assert(0 != sock);
+  assert(0 != call);
+  assert(fd >= 0);
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_add);
+
+  /* set up struct */
+  gen_init((struct GenHeader*) sock, call, data,
+          (struct GenHeader*) evInfo.gens.g_socket,
+          (struct GenHeader**) &evInfo.gens.g_socket);
+
+  sock->s_state = state;
+  sock->s_events = events & SOCK_EVENT_MASK;
+  sock->s_fd = fd;
+
+  return (*evInfo.engine->eng_add)(sock); /* tell engine about it */
+}
+
+/* deletes (or marks for deletion) a socket */
+void
+socket_del(struct Socket* sock)
+{
+  assert(0 != sock);
+  assert(!(sock->s_header.gh_flags & GEN_DESTROY));
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_closing);
+
+  /* tell engine socket is going away */
+  (*evInfo.engine->eng_closing)(sock);
+
+  sock->s_header.gh_flags |= GEN_DESTROY;
+
+  if (!sock->s_header.gh_ref) { /* not in use; destroy right now */
+    gen_dequeue(sock);
+    event_generate(ET_DESTROY, sock, 0);
+  }
+}
+
+/* Sets the socket state to something else */
+void
+socket_state(struct Socket* sock, enum SocketState state)
+{
+  assert(0 != sock);
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_state);
+
+  /* assertions for invalid socket state transitions */
+  assert(sock->s_state != state); /* not changing states ?! */
+  assert(sock->s_state != SS_LISTENING); /* listening socket to...?! */
+  assert(sock->s_state != SS_CONNECTED); /* connected socket to...?! */
+  /* connecting socket now connected */
+  assert(sock->s_state != SS_CONNECTING || state == SS_CONNECTED);
+  /* unconnected datagram socket now connected */
+  assert(sock->s_state != SS_DATAGRAM || state == SS_CONNECTDG);
+  /* connected datagram socket now unconnected */
+  assert(sock->s_state != SS_CONNECTDG || state == SS_DATAGRAM);
+
+  if (sock->s_header.gh_flags & GEN_DESTROY) /* socket's been destroyed */
+    return;
+
+  /* tell engine we're changing socket state */
+  (*evInfo.engine->eng_state)(sock, state);
+
+  sock->s_state = state; /* set new state */
+}
+
+/* sets the events a socket's interested in */
+void
+socket_events(struct Socket* sock, unsigned int events)
+{
+  unsigned int new_events = 0;
+
+  assert(0 != sock);
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_events);
+
+  if (sock->s_header.gh_flags & GEN_DESTROY) /* socket's been destroyed */
+    return;
+
+  switch (events & SOCK_ACTION_MASK) {
+  case SOCK_ACTION_SET: /* set events to given set */
+    new_events = events & SOCK_EVENT_MASK;
+    break;
+
+  case SOCK_ACTION_ADD: /* add some events */
+    new_events = sock->s_events | (events & SOCK_EVENT_MASK);
+    break;
+
+  case SOCK_ACTION_DEL: /* remove some events */
+    new_events = sock->s_events & ~(events & SOCK_EVENT_MASK);
+    break;
+  }
+
+  if (sock->s_events == new_events)
+    return; /* no changes have been made */
+
+  /* tell engine about event mask change */
+  (*evInfo.engine->eng_events)(sock, new_events);
+
+  sock->s_events = new_events; /* set new events */
+}
+
+/* Returns an engine's name for informational purposes */
+const char*
+engine_name(void)
+{
+  assert(0 != evInfo.engine);
+  assert(0 != evInfo.engine->eng_name);
+
+  return evInfo.engine->eng_name;
+}
+
+#ifdef DEBUGMODE
+/* These routines pretty-print names for states and types for debug printing */
+
+#define NS(TYPE) \
+struct {       \
+  char *name;  \
+  TYPE value;  \
+}
+
+#define NM(name)       { #name, name }
+
+#define NE             { 0, 0 }
+
+const char*
+state_to_name(enum SocketState state)
+{
+  int i;
+  NS(enum SocketState) map[] = {
+    NM(SS_CONNECTING),
+    NM(SS_LISTENING),
+    NM(SS_CONNECTED),
+    NM(SS_DATAGRAM),
+    NM(SS_CONNECTDG),
+    NM(SS_NOTSOCK),
+    NE
+  };
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value == state)
+      return map[i].name;
+
+  return "Undefined socket state";
+}
+
+const char*
+timer_to_name(enum TimerType type)
+{
+  int i;
+  NS(enum TimerType) map[] = {
+    NM(TT_ABSOLUTE),
+    NM(TT_RELATIVE),
+    NM(TT_PERIODIC),
+    NE
+  };
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value == type)
+      return map[i].name;
+
+  return "Undefined timer type";
+}
+
+const char*
+event_to_name(enum EventType type)
+{
+  int i;
+  NS(enum EventType) map[] = {
+    NM(ET_READ),
+    NM(ET_WRITE),
+    NM(ET_ACCEPT),
+    NM(ET_CONNECT),
+    NM(ET_EOF),
+    NM(ET_ERROR),
+    NM(ET_SIGNAL),
+    NM(ET_EXPIRE),
+    NM(ET_DESTROY),
+    NE
+  };
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value == type)
+      return map[i].name;
+
+  return "Undefined event type";
+}
+
+const char*
+gen_flags(unsigned int flags)
+{
+  int i, loc = 0;
+  static char buf[256];
+  NS(unsigned int) map[] = {
+    NM(GEN_DESTROY),
+    NM(GEN_MARKED),
+    NE
+  };
+
+  buf[0] = '\0';
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value & flags) {
+      if (loc != 0)
+       buf[loc++] = ' ';
+      loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
+      if (loc >= sizeof(buf))
+       return buf; /* overflow case */
+    }
+
+  return buf;
+}
+
+const char*
+sock_flags(unsigned int flags)
+{
+  int i, loc = 0;
+  static char buf[256];
+  NS(unsigned int) map[] = {
+    NM(SOCK_EVENT_READABLE),
+    NM(SOCK_EVENT_WRITABLE),
+    NM(SOCK_ACTION_SET),
+    NM(SOCK_ACTION_ADD),
+    NM(SOCK_ACTION_DEL),
+    NE
+  };
+
+  buf[0] = '\0';
+
+  for (i = 0; map[i].name; i++)
+    if (map[i].value & flags) {
+      if (loc != 0)
+       buf[loc++] = ' ';
+      loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
+      if (loc >= sizeof(buf))
+       return buf; /* overflow case */
+    }
+
+  return buf;
+}
+
+#endif /* DEBUGMODE */
index 00e09f500522defe43f60b0d2968e3373ab8af15..a250dd9697fdcb6f17fd910f17593f377dad16e7 100644 (file)
  */
 #include "config.h"
 
-#include "ircd_signal.h"
 #include "ircd.h"
+#include "ircd_events.h"
+#include "ircd_signal.h"
+#include "s_conf.h"
 
+#include <assert.h>
 #include <signal.h>
 
 static struct tag_SignalCounter {
@@ -31,25 +34,44 @@ static struct tag_SignalCounter {
   unsigned int hup;
 } SignalCounter;
 
-void sigalrm_handler(int sig)
+static struct Signal sig_hup;
+static struct Signal sig_int;
+static struct Signal sig_term;
+
+static void sigalrm_handler(int sig)
 {
   ++SignalCounter.alrm;
 }
 
-void sigterm_handler(int sig)
+static void sigterm_callback(struct Event* ev)
 {
+  assert(0 != ev_signal(ev));
+  assert(ET_SIGNAL == ev_type(ev));
+  assert(SIGTERM == sig_signal(ev_signal(ev)));
+  assert(SIGTERM == ev_data(ev));
+
   server_die("received signal SIGTERM");
 }
 
-static void sighup_handler(int sig)
+static void sighup_callback(struct Event* ev)
 {
+  assert(0 != ev_signal(ev));
+  assert(ET_SIGNAL == ev_type(ev));
+  assert(SIGHUP == sig_signal(ev_signal(ev)));
+  assert(SIGHUP == ev_data(ev));
+
   ++SignalCounter.hup;
-  GlobalRehashFlag = 1;
+  rehash(&me, 1);
 }
 
-static void sigint_handler(int sig)
+static void sigint_callback(struct Event* ev)
 {
-  GlobalRestartFlag = 1;
+  assert(0 != ev_signal(ev));
+  assert(ET_SIGNAL == ev_type(ev));
+  assert(SIGINT == sig_signal(ev_signal(ev)));
+  assert(SIGINT == ev_data(ev));
+
+  server_restart("caught signal: SIGINT");
 }
 
 void setup_signals(void)
@@ -70,16 +92,9 @@ void setup_signals(void)
   act.sa_handler = sigalrm_handler;
   sigaction(SIGALRM, &act, 0);
 
-  sigemptyset(&act.sa_mask);
-
-  act.sa_handler = sighup_handler;
-  sigaction(SIGHUP, &act, 0);
-
-  act.sa_handler = sigint_handler;
-  sigaction(SIGINT, &act, 0);
-
-  act.sa_handler = sigterm_handler;
-  sigaction(SIGTERM, &act, 0);
+  signal_add(&sig_hup, sighup_callback, 0, SIGHUP);
+  signal_add(&sig_int, sigint_callback, 0, SIGINT);
+  signal_add(&sig_term, sigterm_callback, 0, SIGTERM);
 
 #ifdef HAVE_RESTARTABLE_SYSCALLS
   /*
index 581a3ce8091760edba4313c687d7721427b76c47..b85597dae4ae459076ddc7c7f7d4fafbe9703ea4 100644 (file)
@@ -31,6 +31,7 @@
 #include "match.h"
 #include "numeric.h"
 #include "res.h"
+#include "s_auth.h"
 #include "s_bsd.h"
 #include "s_conf.h"
 #include "s_debug.h"
@@ -111,12 +112,17 @@ static struct Client* alloc_client(void)
 
 static void dealloc_client(struct Client* cptr)
 {
+  assert(cli_verify(cptr));
+  assert(0 == cli_connect(cptr));
+
 #ifdef DEBUGMODE
   --clients.inuse;
 #endif
 
   cli_next(cptr) = clientFreeList;
   clientFreeList = cptr;
+
+  cli_magic(cptr) = 0;
 }
 
 static struct Connection* alloc_connection(void)
@@ -140,6 +146,10 @@ static struct Connection* alloc_connection(void)
 
 static void dealloc_connection(struct Connection* con)
 {
+  assert(con_verify(con));
+
+  Debug((DEBUG_LIST, "Deallocating connection %p", con));
+
   if (con_dns_reply(con))
     --(con_dns_reply(con)->ref_count);
   if (-1 < con_fd(con))
@@ -156,6 +166,8 @@ static void dealloc_connection(struct Connection* con)
 
   con_next(con) = connectionFreeList;
   connectionFreeList = con;
+
+  con_magic(con) = 0;
 }
 
 /*
@@ -172,16 +184,23 @@ struct Client* make_client(struct Client *from, int status)
   struct Client* cptr = 0;
   struct Connection* con = 0;
 
+  assert(!from || cli_verify(from));
+
   cptr = alloc_client();
 
   assert(0 != cptr);
+  assert(!cli_magic(cptr));
+  assert(0 == from || 0 != cli_connect(from));
 
   if (!from) { /* local client, allocate a struct Connection */
     con = alloc_connection();
 
     assert(0 != con);
+    assert(!con_magic(con));
 
+    con_magic(con) = CONNECTION_MAGIC;
     con_fd(con) = -1; /* initialize struct Connection */
+    con_freeflag(con) = 0;
     con_nextnick(con) = CurrentTime - NICK_DELAY;
     con_nexttarget(con) = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
     con_handler(con) = UNREGISTERED_HANDLER;
@@ -194,7 +213,9 @@ struct Client* make_client(struct Client *from, int status)
     con = cli_connect(from); /* use 'from's connection */
 
   assert(0 != con);
+  assert(con_verify(con));
 
+  cli_magic(cptr) = CLIENT_MAGIC;
   cli_connect(cptr) = con; /* set the connection and other fields */
   cli_status(cptr) = status;
   cli_hnext(cptr) = cptr;
@@ -203,6 +224,17 @@ struct Client* make_client(struct Client *from, int status)
   return cptr;
 }
 
+void free_connection(struct Connection* con)
+{
+  if (!con)
+    return;
+
+  assert(con_verify(con));
+  assert(0 == con_client(con));
+
+  dealloc_connection(con); /* deallocate the connection */
+}
+
 void free_client(struct Client* cptr)
 {
   if (!cptr)
@@ -210,17 +242,39 @@ void free_client(struct Client* cptr)
   /*
    * forget to remove the client from the hash table?
    */
+  assert(cli_verify(cptr));
   assert(cli_hnext(cptr) == cptr);
 
-  if (cli_from(cptr) == cptr) /* in other words, we're local */
-    dealloc_connection(cli_connect(cptr)); /* deallocate the connection... */
-  dealloc_client(cptr); /* deallocate the client */
+  Debug((DEBUG_LIST, "Freeing client %s [%p], connection %p", cli_name(cptr),
+        cptr, cli_connect(cptr)));
+
+  if (cli_auth(cptr))
+    destroy_auth_request(cli_auth(cptr), 0);
+
+  if (cli_from(cptr) == cptr) { /* in other words, we're local */
+    cli_from(cptr) = 0;
+    /* timer must be marked as not active */
+    if (!cli_freeflag(cptr) && !t_active(&(cli_proc(cptr))))
+      dealloc_connection(cli_connect(cptr)); /* connection not open anymore */
+    else {
+      if (-1 < cli_fd(cptr) && cli_freeflag(cptr) & FREEFLAG_SOCKET)
+       socket_del(&(cli_socket(cptr))); /* queue a socket delete */
+      if (cli_freeflag(cptr) & FREEFLAG_TIMER)
+       timer_del(&(cli_proc(cptr))); /* queue a timer delete */
+    }
+  }
+
+  cli_connect(cptr) = 0;
+
+  dealloc_client(cptr); /* actually destroy the client */
 }
 
 struct Server *make_server(struct Client *cptr)
 {
   struct Server *serv = cli_serv(cptr);
 
+  assert(cli_verify(cptr));
+
   if (!serv)
   {
     serv = (struct Server*) MyMalloc(sizeof(struct Server));
@@ -243,11 +297,15 @@ struct Server *make_server(struct Client *cptr)
  */
 void remove_client_from_list(struct Client *cptr)
 {
+  assert(cli_verify(cptr));
+  assert(con_verify(cli_connect(cptr)));
+
   if (cli_prev(cptr))
     cli_next(cli_prev(cptr)) = cli_next(cptr);
   else {
     GlobalClientList = cli_next(cptr);
-    cli_prev(GlobalClientList) = 0;
+    if (GlobalClientList)
+      cli_prev(GlobalClientList) = 0;
   }
   if (cli_next(cptr))
     cli_prev(cli_next(cptr)) = cli_prev(cptr);
@@ -287,6 +345,7 @@ void remove_client_from_list(struct Client *cptr)
  */
 void add_client_to_list(struct Client *cptr)
 {
+  assert(cli_verify(cptr));
   /*
    * Since we always insert new clients to the top of the list,
    * this should mean the "me" is the bottom most item in the list.
index 75f4add370c757eb8a75e911200ff976a9751cf0..f7802879162604ab47e1753fdea3105b191c6716 100644 (file)
@@ -24,6 +24,7 @@
 #include "client.h"
 #include "ircd.h"
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "ircd_features.h"
 #include "ircd_osdep.h"
 #include "ircd_reply.h"
@@ -52,6 +53,8 @@
 
 struct Listener* ListenerPollList = 0;
 
+static void accept_connection(struct Event* ev);
+
 static struct Listener* make_listener(int port, struct in_addr addr)
 {
   struct Listener* listener = 
@@ -222,6 +225,14 @@ static int inetport(struct Listener* listener)
   if (!os_set_tos(fd,feature_int((listener->server)?FEAT_TOS_SERVER : FEAT_TOS_CLIENT))) {
     report_error(TOS_ERROR_MSG, get_listener_name(listener), errno);
   }
+
+  if (!socket_add(&listener->socket, accept_connection, (void*) listener,
+                 SS_LISTENING, 0, fd)) {
+    /* Error should already have been reported to the logs */
+    close(fd);
+    return 0;
+  }
+
   listener->fd = fd;
 
   return 1;
@@ -370,7 +381,7 @@ void close_listener(struct Listener* listener)
   }
   if (-1 < listener->fd)
     close(listener->fd);
-  free_listener(listener);
+  socket_del(&listener->socket);
 }
  
 /*
@@ -401,77 +412,88 @@ void release_listener(struct Listener* listener)
 /*
  * accept_connection - accept a connection on a listener
  */
-void accept_connection(struct Listener* listener)
+static void accept_connection(struct Event* ev)
 {
+  struct Listener* listener;
   struct sockaddr_in addr = { 0 };
   unsigned int       addrlen = sizeof(struct sockaddr_in);
   int                fd;
 
-  assert(0 != listener);
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
 
-  listener->last_accept = CurrentTime;
-  /*
-   * There may be many reasons for error return, but
-   * in otherwise correctly working environment the
-   * probable cause is running out of file descriptors
-   * (EMFILE, ENFILE or others?). The man pages for
-   * accept don't seem to list these as possible,
-   * although it's obvious that it may happen here.
-   * Thus no specific errors are tested at this
-   * point, just assume that connections cannot
-   * be accepted until some old is closed first.
-   */
-  if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen))) {
-    /* Lotsa admins seem to have problems with not giving enough file descriptors
-     * to their server so we'll add a generic warning mechanism here.  If it
-     * turns out too many messages are generated for meaningless reasons we
-     * can filter them back.
+  listener = s_data(ev_socket(ev));
+
+  if (ev_type(ev) == ET_DESTROY) /* being destroyed */
+    free_listener(listener);
+  else {
+    assert(ev_type(ev) == ET_ACCEPT);
+
+    listener->last_accept = CurrentTime;
+    /*
+     * There may be many reasons for error return, but
+     * in otherwise correctly working environment the
+     * probable cause is running out of file descriptors
+     * (EMFILE, ENFILE or others?). The man pages for
+     * accept don't seem to list these as possible,
+     * although it's obvious that it may happen here.
+     * Thus no specific errors are tested at this
+     * point, just assume that connections cannot
+     * be accepted until some old is closed first.
      */
-    sendto_opmask_butone(0, SNO_TCPCOMMON, "Unable to accept connection: %m");
-    return;
-  }
-  /*
-   * check for connection limit
-   */
-  if (fd > MAXCLIENTS - 1) {
-    ++ServerStats->is_ref;
-    send(fd, "ERROR :All connections in use\r\n", 32, 0);
-    close(fd);
-    return;
-  }
-  /*
-   * check to see if listener is shutting down
-   */
-  if (!listener->active) {
-    ++ServerStats->is_ref;
-    send(fd, "ERROR :Use another port\r\n", 25, 0);
-    close(fd);
-    return;
-  }
-  /*
-   * check to see if connection is allowed for this address mask
-   */
-  if (!connection_allowed((const char*) &addr, (const char*) &listener->mask)) {
-    ++ServerStats->is_ref;
-    send(fd, "ERROR :Use another port\r\n", 25, 0);
-    close(fd);
-    return;
-  }
+    if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr,
+                          &addrlen))) {
+      /* Lotsa admins seem to have problems with not giving enough file
+       * descriptors to their server so we'll add a generic warning mechanism
+       * here.  If it turns out too many messages are generated for
+       * meaningless reasons we can filter them back.
+       */
+      sendto_opmask_butone(0, SNO_TCPCOMMON,
+                          "Unable to accept connection: %m");
+      return;
+    }
+    /*
+     * check for connection limit
+     */
+    if (fd > MAXCLIENTS - 1) {
+      ++ServerStats->is_ref;
+      send(fd, "ERROR :All connections in use\r\n", 32, 0);
+      close(fd);
+      return;
+    }
+    /*
+     * check to see if listener is shutting down
+     */
+    if (!listener->active) {
+      ++ServerStats->is_ref;
+      send(fd, "ERROR :Use another port\r\n", 25, 0);
+      close(fd);
+      return;
+    }
+    /*
+     * check to see if connection is allowed for this address mask
+     */
+    if (!connection_allowed((const char*) &addr,
+                           (const char*) &listener->mask)) {
+      ++ServerStats->is_ref;
+      send(fd, "ERROR :Use another port\r\n", 25, 0);
+      close(fd);
+      return;
+    }
 #if 0
-  /*
-   * check conf for ip address access
-   */
-  if (!conf_connect_allowed(addr.sin_addr)) {
-    ++ServerStats->is_ref;
-    send(fd, "ERROR :Not authorized\r\n", 23, 0);
-    close(fd);
-    return;
-  }
+    /*
+     * check conf for ip address access
+     */
+    if (!conf_connect_allowed(addr.sin_addr)) {
+      ++ServerStats->is_ref;
+      send(fd, "ERROR :Not authorized\r\n", 23, 0);
+      close(fd);
+      return;
+    }
 #endif
-  ++ServerStats->is_ac;
-  nextping = CurrentTime;
+    ++ServerStats->is_ac;
+/*      nextping = CurrentTime; */
 
-  add_connection(listener, fd);
+    add_connection(listener, fd);
+  }
 }
-
-
index eaf970757c686cfb7519c4c072f1a771a01e06fe..e4c3a5d5ffed8c84f6e1f427f64c7b1d99c3626e 100644 (file)
 #include "msg.h"
 #include "numeric.h"
 #include "numnicks.h"
+#include "s_bsd.h"
 #include "send.h"
 
 #include <assert.h>
@@ -287,6 +288,7 @@ int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     MyFree(cli_listing(sptr));
     cli_listing(sptr) = 0;
     send_reply(sptr, RPL_LISTEND);
+    update_write(sptr);
     if (parc < 2)
       return 0;                 /* Let LIST abort a listing. */
   }
index e2124945b0e62e3249bf00c62cee6d2422b6b2a5..d0bba3020925207aae68bb7bb983cd4c8afcc817 100644 (file)
@@ -94,6 +94,7 @@
 #include "ircd.h"
 #include "ircd_alloc.h"
 #include "ircd_chattr.h"
+#include "ircd_events.h"
 #include "ircd_features.h"
 #include "ircd_policy.h"
 #include "ircd_reply.h"
@@ -263,6 +264,15 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 #endif
       break;
 
+    case 'E':
+    case 'e': /* report engine name */
+#ifdef HEAD_IN_SAND_STATS_E
+      return m_not_oper(sptr,cptr,parc,parv);
+#else
+      send_reply(sptr, RPL_STATSENGINE, engine_name());
+#endif
+      break;
+
     case 'G':
     case 'g': /* send glines */
 #ifdef HEAD_IN_SAND_STATS_G
@@ -590,6 +600,10 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     case 'c':
       report_configured_links(sptr, CONF_SERVER);
       break;
+    case 'E':
+    case 'e': /* report engine name */
+      send_reply(sptr, RPL_STATSENGINE, engine_name());
+      break;
     case 'G':
     case 'g': /* send glines */
       gline_stats(sptr);
@@ -809,6 +823,10 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     case 'c':
       report_configured_links(sptr, CONF_SERVER);
       break;
+    case 'E':
+    case 'e': /* report engine name */
+      send_reply(sptr, RPL_STATSENGINE, engine_name());
+      break;
     case 'G':
     case 'g': /* send glines */
       gline_stats(sptr);
index f26cb737b5d8accb7afeb109e656e77f5527857c..2f3bd666a19aa64872572fe6e0f257d459cd3099 100644 (file)
@@ -359,13 +359,11 @@ IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
   return IO_FAILURE;
 }
 
-int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+IOResult os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
-  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
-    if (errno != EINPROGRESS)
-      return 0;
-  }
-  return 1;
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in)))
+    return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
+  return IO_SUCCESS;
 }
       
 int os_get_sockname(int fd, struct sockaddr_in* sin_out)
index 73c2f7942736df1bd48a3d940d6a12a31a06c563..b996ecd66c80ea5b94e483cfac46dbc4742fd18b 100644 (file)
@@ -220,6 +220,16 @@ int os_set_sockbufs(int fd, unsigned int size)
                           (const char*) &opt, sizeof(opt)));
 }
 
+int os_set_tos(int fd,int tos)
+{
+#if defined(IP_TOS) && defined(IPPROTO_IP)
+  unsigned int opt = tos;
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)));
+#else
+  return 1;
+#endif
+}
+
 int os_disable_options(int fd)
 {
 #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
@@ -355,13 +365,11 @@ IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
   return IO_FAILURE;
 }
 
-int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+IOResult os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
-  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
-    if (errno != EINPROGRESS)
-      return 0;
-  }
-  return 1;
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in)))
+    return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
+  return IO_SUCCESS;
 }
       
 int os_get_sockname(int fd, struct sockaddr_in* sin_out)
index 7e371295b3088fe08b28a1ba43d91a4db38c56a5..9ea434b580a802415543734702f0e2c529269410 100644 (file)
@@ -303,13 +303,11 @@ IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
 }
 
 
-int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+IOResult os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
-  if (connect(fd, (const struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
-    if (errno != EINPROGRESS)
-      return 0;
-  }
-  return 1;
+  if (connect(fd, (const struct sockaddr*) sin, sizeof(struct sockaddr_in)))
+    return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
+  return IO_SUCCESS;
 }
       
 int os_get_sockname(int fd, struct sockaddr_in* sin_out)
index 805d87f0a52260c0844bbb7a0fc9749f1cb07c45..bf02113f38481cdb764df4abe6ca1600bf5206b3 100644 (file)
@@ -367,13 +367,11 @@ IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
   return IO_FAILURE;
 }
 
-int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+IOResult os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
-  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
-    if (errno != EINPROGRESS)
-      return 0;
-  }
-  return 1;
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in)))
+    return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
+  return IO_SUCCESS;
 }
       
 int os_get_sockname(int fd, struct sockaddr_in* sin_out)
index e4ba40fb7349dd120262d853f99043a115009575..c94fd3845bb70a862665ad0e0f79b408859ffd84 100644 (file)
@@ -21,8 +21,6 @@
  */
 #include "config.h"
 
-#define _XOPEN_SOURCE  /* make limits.h #define IOV_MAX */
-
 #include "ircd_osdep.h"
 #include "msgq.h"
 
@@ -32,6 +30,7 @@
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
+#include <stropts.h>
 #include <sys/filio.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
@@ -135,6 +134,12 @@ int os_set_sockbufs(int fd, unsigned int size)
                           (const char*) &opt, sizeof(opt)));
 }
 
+int os_set_tos(int fd,int tos)
+{
+  unsigned int opt = tos;
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)));
+}
+
 int os_disable_options(int fd)
 {
   return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
@@ -249,13 +254,11 @@ IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in,
   return IO_FAILURE;
 }
 
-int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+IOResult os_connect_nonb(int fd, const struct sockaddr_in* sin)
 {
-  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
-    if (errno != EINPROGRESS)
-      return 0;
-  }
-  return 1;
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in)))
+    return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
+  return IO_SUCCESS;
 }
       
 int os_get_sockname(int fd, struct sockaddr_in* sin_out)
index d9eb03579a75b5180952ad70b0f47c122b656d8b..3ded4cc5ab92ae8b9b51b3ebba60f03a7f29f9b5 100644 (file)
@@ -16,6 +16,7 @@
 #include "client.h"
 #include "ircd.h"
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "ircd_log.h"
 #include "ircd_osdep.h"
 #include "ircd_reply.h"
@@ -200,6 +201,10 @@ struct CacheTable {
 
 int ResolverFileDescriptor    = -1;   /* GLOBAL - used in s_bsd.c */
 
+static struct Socket resSock;          /* Socket describing resolver */
+static struct Timer  resExpireDNS;     /* Timer for DNS expiration */
+static struct Timer  resExpireCache;   /* Timer for cache expiration */
+
 static time_t nextDNSCheck    = 0;
 static time_t nextCacheExpire = 1;
 
@@ -222,6 +227,8 @@ static struct ResRequest* requestListTail;   /* tail of resolver request list */
 static void     add_request(struct ResRequest* request);
 static void     rem_request(struct ResRequest* request);
 static struct ResRequest*   make_request(const struct DNSQuery* query);
+static time_t   timeout_query_list(time_t now);
+static time_t   expire_cache(time_t now);
 static void     rem_cache(struct CacheEntry*);
 static void     do_query_name(const struct DNSQuery* query, 
                               const char* name, 
@@ -298,6 +305,14 @@ res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp)
   return (0);
 }
 
+/* Socket callback for resolver */
+static void res_callback(struct Event* ev)
+{
+  assert(ev_type(ev) == ET_READ);
+
+  resolver_read();
+}
+
 /*
  * start_resolver - do everything we need to read the resolv.conf file
  * and initialize the resolver file descriptor if needed
@@ -340,9 +355,33 @@ static void start_resolver(void)
     if (!os_set_nonblocking(ResolverFileDescriptor))
       report_error("Resolver: error setting non-blocking for %s: %s", 
                    cli_name(&me), errno);
+    if (!socket_add(&resSock, res_callback, 0, SS_DATAGRAM,
+                   SOCK_EVENT_READABLE, ResolverFileDescriptor))
+      report_error("Resolver: unable to queue resolver file descriptor for %s",
+                  cli_name(&me), ENFILE);
   }
 }
 
+/* Call the query timeout function */
+static void expire_DNS_callback(struct Event* ev)
+{
+  time_t next;
+
+  next = timeout_query_list(CurrentTime);
+
+  timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
+}
+
+/* Call the cache expire function */
+static void expire_cache_callback(struct Event* ev)
+{
+  time_t next;
+
+  next = expire_cache(CurrentTime);
+
+  timer_add(&resExpireCache, expire_cache_callback, 0, TT_ABSOLUTE, next);
+}
+
 /*
  * init_resolver - initialize resolver and resolver library
  */
@@ -358,6 +397,10 @@ int init_resolver(void)
 
   requestListHead = requestListTail = 0;
 
+  /* initiate the resolver timers */
+  timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_RELATIVE, 1);
+  timer_add(&resExpireCache, expire_cache_callback, 0, TT_RELATIVE, 1);
+
   errno = h_errno = 0;
 
   start_resolver();
index 01c207af95ef495ef56ef6337afce96c1337e4c7..5ac17026e57bf808463d022eaf7bafa8773e4aca 100644 (file)
@@ -35,6 +35,7 @@
 #include "ircd.h"
 #include "ircd_alloc.h"
 #include "ircd_chattr.h"
+#include "ircd_events.h"
 #include "ircd_features.h"
 #include "ircd_log.h"
 #include "ircd_osdep.h"
@@ -102,6 +103,118 @@ static struct AuthRequest* AuthIncompleteList = 0;
 
 enum { AUTH_TIMEOUT = 60 };
 
+static void release_auth_client(struct Client* client);
+static void unlink_auth_request(struct AuthRequest* request,
+                                struct AuthRequest** list);
+void free_auth_request(struct AuthRequest* auth);
+
+/*
+ * auth_timeout - timeout a given auth request
+ */
+static void auth_timeout_callback(struct Event* ev)
+{
+  struct AuthRequest* auth;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  auth = t_data(ev_timer(ev));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    auth->flags &= ~AM_TIMEOUT;
+
+    if (!(auth->flags & AM_FREE_MASK)) {
+      Debug((DEBUG_LIST, "Freeing auth from timeout callback; %p [%p]", auth,
+            ev_timer(ev)));
+      MyFree(auth); /* done with it, finally */
+    }
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    destroy_auth_request(auth, 1);
+  }
+}
+
+/*
+ * auth_sock_callback - called when an event occurs on the socket
+ */
+static void auth_sock_callback(struct Event* ev)
+{
+  struct AuthRequest* auth;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  auth = s_data(ev_socket(ev));
+
+  switch (ev_type(ev)) {
+  case ET_DESTROY: /* being destroyed */
+    auth->flags &= ~AM_SOCKET;
+
+    if (!(auth->flags & AM_FREE_MASK)) {
+      Debug((DEBUG_LIST, "Freeing auth from sock callback; %p [%p]", auth,
+            ev_socket(ev)));
+      MyFree(auth); /* done with it finally */
+    }
+    break;
+
+  case ET_CONNECT: /* socket connection completed */
+    Debug((DEBUG_LIST, "Connection completed for auth %p [%p]; sending query",
+          auth, ev_socket(ev)));
+    socket_state(&auth->socket, SS_CONNECTED);
+    send_auth_query(auth);
+    break;
+
+  case ET_READ: /* socket is readable */
+  case ET_EOF: /* end of file on socket */
+  case ET_ERROR: /* error on socket */
+    Debug((DEBUG_LIST, "Auth socket %p [%p] readable", auth, ev_socket(ev)));
+    read_auth_reply(auth);
+    break;
+
+  default:
+#ifndef NDEBUG
+    abort(); /* unrecognized event */
+#endif
+    break;
+  }
+}
+
+/*
+ * destroy_auth_request - stop an auth request completely
+ */
+void destroy_auth_request(struct AuthRequest* auth, int send_reports)
+{
+  struct AuthRequest** authList;
+
+  if (IsDoingAuth(auth)) {
+    authList = &AuthPollList;
+    if (-1 < auth->fd) {
+      close(auth->fd);
+      auth->fd = -1;
+      socket_del(&auth->socket);
+    }
+
+    if (send_reports && IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+  } else
+    authList = &AuthIncompleteList;
+
+  if (IsDNSPending(auth)) {
+    delete_resolver_queries(auth);
+    if (send_reports && IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_DNS);
+  }
+
+  if (send_reports)
+    log_write(LS_RESOLVER, L_INFO, 0, "DNS/AUTH timeout %s",
+             get_client_name(auth->client, HIDE_IP));
+
+  release_auth_client(auth->client);
+  unlink_auth_request(auth, authList);
+  free_auth_request(auth);
+}
+
 /*
  * make_auth_request - allocate a new auth request
  */
@@ -111,9 +224,12 @@ static struct AuthRequest* make_auth_request(struct Client* client)
                (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest));
   assert(0 != auth);
   memset(auth, 0, sizeof(struct AuthRequest));
+  auth->flags   = AM_TIMEOUT;
   auth->fd      = -1;
   auth->client  = client;
-  auth->timeout = CurrentTime + AUTH_TIMEOUT;
+  cli_auth(client) = auth;
+  timer_add(&auth->timeout, auth_timeout_callback, (void*) auth, TT_RELATIVE,
+           AUTH_TIMEOUT);
   return auth;
 }
 
@@ -122,9 +238,13 @@ static struct AuthRequest* make_auth_request(struct Client* client)
  */
 void free_auth_request(struct AuthRequest* auth)
 {
-  if (-1 < auth->fd)
+  if (-1 < auth->fd) {
     close(auth->fd);
-  MyFree(auth);
+    Debug((DEBUG_LIST, "Deleting auth socket for %p", auth->client));
+    socket_del(&auth->socket);
+  }
+  Debug((DEBUG_LIST, "Deleting auth timeout timer for %p", auth->client));
+  timer_del(&auth->timeout);
 }
 
 /*
@@ -162,12 +282,14 @@ static void link_auth_request(struct AuthRequest* request,
 static void release_auth_client(struct Client* client)
 {
   assert(0 != client);
+  cli_auth(client) = 0;
   cli_lasttime(client) = cli_since(client) = CurrentTime;
   if (cli_fd(client) > HighestFd)
     HighestFd = cli_fd(client);
   LocalClientArray[cli_fd(client)] = client;
 
   add_client_to_list(client);
+  socket_events(&(cli_socket(client)), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
   Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]",
          cli_username(client), cli_sockhost(client), cli_sock_ip(client)));
 }
@@ -263,6 +385,7 @@ static void auth_error(struct AuthRequest* auth, int kill)
   assert(0 != auth);
   close(auth->fd);
   auth->fd = -1;
+  socket_del(&auth->socket);
 
   if (IsUserPort(auth->client))
     sendheader(auth->client, REPORT_FAIL_ID);
@@ -301,6 +424,7 @@ static int start_auth_query(struct AuthRequest* auth)
   struct sockaddr_in remote_addr;
   struct sockaddr_in local_addr;
   int                fd;
+  IOResult           result;
 
   assert(0 != auth);
   assert(0 != auth->client);
@@ -353,7 +477,10 @@ static int start_auth_query(struct AuthRequest* auth)
   remote_addr.sin_port = htons(113);
   remote_addr.sin_family = AF_INET;
 
-  if (!os_connect_nonb(fd, &remote_addr)) {
+  if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE ||
+      !socket_add(&auth->socket, auth_sock_callback, (void*) auth,
+                 result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING,
+                 SOCK_EVENT_READABLE, fd)) {
     ServerStats->is_abad++;
     /*
      * No error report from this...
@@ -364,9 +491,13 @@ static int start_auth_query(struct AuthRequest* auth)
     return 0;
   }
 
+  auth->flags |= AM_SOCKET;
   auth->fd = fd;
 
   SetAuthConnect(auth);
+  if (result == IO_SUCCESS)
+    send_auth_query(auth); /* this does a SetAuthPending(auth) for us */
+
   return 1;
 }
 
@@ -524,6 +655,8 @@ void start_auth(struct Client* client)
   auth = make_auth_request(client);
   assert(0 != auth);
 
+  Debug((DEBUG_INFO, "Beginning auth request on client %p", client));
+
   if (!feature_bool(FEAT_NODNS)) {
     if (LOOPBACK == inet_netof(cli_ip(client)))
       strcpy(cli_sockhost(client), cli_name(&me));
@@ -545,69 +678,28 @@ void start_auth(struct Client* client)
                     HOSTLEN);
        if (IsUserPort(auth->client))
          sendheader(client, REPORT_FIN_DNSC);
+       Debug((DEBUG_LIST, "DNS entry for %p was cached", auth->client));
       } else
        SetDNSPending(auth);
     }
   }
 
-  if (start_auth_query(auth))
+  if (start_auth_query(auth)) {
+    Debug((DEBUG_LIST, "identd query for %p initiated successfully",
+          auth->client));
     link_auth_request(auth, &AuthPollList);
-  else if (IsDNSPending(auth))
+  } else if (IsDNSPending(auth)) {
+    Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
+          "waiting on DNS", auth->client));
     link_auth_request(auth, &AuthIncompleteList);
-  else {
+  } else {
+    Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
+          "no DNS pending; releasing immediately", auth->client));
     free_auth_request(auth);
     release_auth_client(client);
   }
 }
 
-/*
- * timeout_auth_queries - timeout resolver and identd requests
- * allow clients through if requests failed
- */
-void timeout_auth_queries(time_t now)
-{
-  struct AuthRequest* auth;
-  struct AuthRequest* auth_next = 0;
-
-  for (auth = AuthPollList; auth; auth = auth_next) {
-    auth_next = auth->next;
-    if (auth->timeout < CurrentTime) {
-      if (-1 < auth->fd) {
-        close(auth->fd);
-        auth->fd = -1;
-      }
-
-      if (IsUserPort(auth->client))
-        sendheader(auth->client, REPORT_FAIL_ID);
-      if (IsDNSPending(auth)) {
-        delete_resolver_queries(auth);
-        if (IsUserPort(auth->client))
-          sendheader(auth->client, REPORT_FAIL_DNS);
-      }
-      log_write(LS_RESOLVER, L_INFO, 0, "DNS/AUTH timeout %s",
-               get_client_name(auth->client, HIDE_IP));
-
-      release_auth_client(auth->client);
-      unlink_auth_request(auth, &AuthPollList);
-      free_auth_request(auth);
-    }
-  }
-  for (auth = AuthIncompleteList; auth; auth = auth_next) {
-    auth_next = auth->next;
-    if (auth->timeout < CurrentTime) {
-      delete_resolver_queries(auth);
-      if (IsUserPort(auth->client))
-        sendheader(auth->client, REPORT_FAIL_DNS);
-      log_write(LS_RESOLVER, L_INFO, 0, "DNS timeout %s",
-               get_client_name(auth->client, HIDE_IP));
-
-      release_auth_client(auth->client);
-      unlink_auth_request(auth, &AuthIncompleteList);
-      free_auth_request(auth);
-    }
-  }
-}
-
 /*
  * send_auth_query - send the ident server a query giving "theirport , ourport"
  * The write is only attempted *once* so it is deemed to be a fail if the
@@ -660,14 +752,19 @@ void read_auth_reply(struct AuthRequest* auth)
 
   assert(0 != auth);
   assert(0 != auth->client);
+  assert(auth = cli_auth(auth->client));
 
   if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) {
     buf[len] = '\0';
+    Debug((DEBUG_LIST, "Auth %p [%p] reply: %s", auth, &auth->socket, buf));
     username = check_ident_reply(buf);
+    Debug((DEBUG_LIST, "Username: %s", username));
   }
 
   close(auth->fd);
   auth->fd = -1;
+  Debug((DEBUG_LIST, "Deleting auth [%p] socket %p", auth, &auth->socket));
+  socket_del(&auth->socket);
   ClearAuth(auth);
   
   if (!EmptyString(username)) {
index 020336e0b79cda580ab523ac542fc07e66e17087..9d1564830371681a862c2c73625d35f2fead27c8 100644 (file)
@@ -96,6 +96,7 @@ const char* const LISTEN_ERROR_MSG    = "listen error for %s: %s";
 const char* const NONB_ERROR_MSG      = "error setting non-blocking for %s: %s";
 const char* const PEERNAME_ERROR_MSG  = "getpeername failed for %s: %s";
 const char* const POLL_ERROR_MSG      = "poll error for %s: %s";
+const char* const REGISTER_ERROR_MSG  = "registering %s: %s";
 const char* const REUSEADDR_ERROR_MSG = "error setting SO_REUSEADDR for %s: %s";
 const char* const SELECT_ERROR_MSG    = "select error for %s: %s";
 const char* const SETBUFS_ERROR_MSG   = "error setting buffer size for %s: %s";
@@ -103,6 +104,9 @@ const char* const SOCKET_ERROR_MSG    = "error creating socket for %s: %s";
 const char* const TOS_ERROR_MSG              = "error setting TOS for %s: %s";
 
 
+static void client_sock_callback(struct Event* ev);
+static void client_timer_callback(struct Event* ev);
+
 #if !defined(USE_POLL)
 #if FD_SETSIZE < (MAXCONNECTIONS + 4)
 /*
@@ -226,6 +230,7 @@ int init_connection_limits(void)
 static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
 {
   static struct sockaddr_in sin;
+  IOResult result;
   assert(0 != aconf);
   assert(0 != cptr);
   /*
@@ -264,6 +269,8 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
       bind(cli_fd(cptr), (struct sockaddr*) &VirtualHost,
           sizeof(VirtualHost))) {
     report_error(BIND_ERROR_MSG, cli_name(cptr), errno);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
     return 0;
   }
 
@@ -283,6 +290,8 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
   if (!os_set_sockbufs(cli_fd(cptr), SERVER_TCP_WINDOW)) {
     cli_error(cptr) = errno;
     report_error(SETBUFS_ERROR_MSG, cli_name(cptr), errno);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
     return 0;
   }
   /*
@@ -291,13 +300,28 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
   if (!os_set_nonblocking(cli_fd(cptr))) {
     cli_error(cptr) = errno;
     report_error(NONB_ERROR_MSG, cli_name(cptr), errno);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
     return 0;
   }
-  if (!os_connect_nonb(cli_fd(cptr), &sin)) {
+  if ((result = os_connect_nonb(cli_fd(cptr), &sin)) == IO_FAILURE) {
     cli_error(cptr) = errno;
     report_error(CONNECT_ERROR_MSG, cli_name(cptr), errno);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
     return 0;
   }
+  if (!socket_add(&(cli_socket(cptr)), client_sock_callback,
+                 (void*) cli_connect(cptr),
+                 (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING,
+                 SOCK_EVENT_READABLE, cli_fd(cptr))) {
+    cli_error(cptr) = ENFILE;
+    report_error(REGISTER_ERROR_MSG, cli_name(cptr), ENFILE);
+    close(cli_fd(cptr));
+    cli_fd(cptr) = -1;
+    return 0;
+  }
+  cli_freeflag(cptr) |= FREEFLAG_SOCKET;
   return 1;
 }
 
@@ -409,6 +433,8 @@ static int completed_connection(struct Client* cptr)
     sendto_opmask_butone(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr));
     return 0;
   }
+  if (s_state(&(cli_socket(cptr))) == SS_CONNECTING)
+    socket_state(&(cli_socket(cptr)), SS_CONNECTED);
 
   if (!EmptyString(aconf->passwd))
     sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd);
@@ -481,8 +507,8 @@ void close_connection(struct Client *cptr)
       aconf->hold += ((aconf->hold - cli_since(cptr) >
                       feature_int(FEAT_HANGONGOODLINK)) ?
                      feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf));
-      if (nextconnect > aconf->hold)
-        nextconnect = aconf->hold;
+/*        if (nextconnect > aconf->hold) */
+/*          nextconnect = aconf->hold; */
     }
   }
   else if (IsUser(cptr)) {
@@ -508,6 +534,7 @@ void close_connection(struct Client *cptr)
     flush_connections(cptr);
     LocalClientArray[cli_fd(cptr)] = 0;
     close(cli_fd(cptr));
+    socket_del(&(cli_socket(cptr))); /* queue a socket delete */
     cli_fd(cptr) = -1;
   }
   cli_flags(cptr) |= FLAGS_DEADSOCKET;
@@ -564,6 +591,8 @@ void add_connection(struct Listener* listener, int fd) {
   const char* const throttle_message =
          "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n";
        /* 12345678901234567890123456789012345679012345678901234567890123456 */
+  const char* const register_message =
+         "ERROR :Unable to complete your registration\r\n";
   
   assert(0 != listener);
 
@@ -607,6 +636,15 @@ void add_connection(struct Listener* listener, int fd) {
     cli_nexttarget(new_client) = next_target;
 
   cli_fd(new_client) = fd;
+  if (!socket_add(&(cli_socket(new_client)), client_sock_callback,
+                 (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) {
+    ++ServerStats->is_ref;
+    write(fd, register_message, strlen(register_message));
+    close(fd);
+    cli_fd(new_client) = -1;
+    return;
+  }
+  cli_freeflag(new_client) |= FREEFLAG_SOCKET;
   cli_listener(new_client) = listener;
   ++listener->ref_count;
 
@@ -615,6 +653,23 @@ void add_connection(struct Listener* listener, int fd) {
   start_auth(new_client);
 }
 
+/*
+ * update_write
+ *
+ * Determines whether to tell the events engine we're interested in
+ * writable events
+ */
+void update_write(struct Client* cptr)
+{
+  /* If there are messages that need to be sent along, or if the client
+   * is in the middle of a /list, then we need to tell the engine that
+   * we're interested in writable events--otherwise, we need to drop
+   * that interest.
+   */
+  socket_events(&(cli_socket(cptr)),
+               ((MsgQLength(&cli_sendQ(cptr)) || cli_listing(cptr)) ?
+                SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE);
+}
 
 /*
  * read_packet
@@ -703,580 +758,19 @@ static int read_packet(struct Client *cptr, int socket_ready)
       else if (CPTR_KILLED == client_dopacket(cptr, dolen))
         return CPTR_KILLED;
     }
-  }
-  return 1;
-}
 
-static int on_write_unblocked(struct Client* cptr)
-{
-  /*
-   *  ...room for writing, empty some queue then...
-   */
-  cli_flags(cptr) &= ~FLAGS_BLOCKED;
-  if (IsConnecting(cptr)) {
-    if (!completed_connection(cptr))
-      return 0;
-  }
-  else if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
-    list_next_channels(cptr, 64);
-  send_queued(cptr);
-  return 1;
-}
-
-/*
- * Select / Poll Read Algorithm for ircd
- *
- * We need to check the file descriptors for all the different types
- * of things that use them, so check for reads on everything but connects
- * and writes on connects and descriptors that are blocked
- *
- * for each (client in local) {
- *   if (not connecting)
- *     check for read;
- *   if (connecting or blocked)
- *     check for write;
- * }
- * wait for activity;
- *
- * for each (client in local) {
- *   if (there are descriptors to check) {
- *     if (write activity)
- *       send data;
- *     if (read activity)
- *       read data;
- *   }
- *   process data read;
- * }
- * Note we must always process data read whether or not there has been
- * read activity or file descriptors set, since data is buffered by the client.
- */
-
-
-#ifdef USE_POLL
-
-/*
- * poll macros
- */
-#if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
-#  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
-#else
-#  if defined(POLLIN) && defined(POLLRDNORM)
-#    define POLLREADFLAGS (POLLIN|POLLRDNORM)
-#  else
-#    if defined(POLLIN)
-#      define POLLREADFLAGS POLLIN
-#    else
-#      if defined(POLLRDNORM)
-#        define POLLREADFLAGS POLLRDNORM
-#      endif
-#    endif
-#  endif
-#endif
-
-#if defined(POLLOUT) && defined(POLLWRNORM)
-#define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
-#else
-#  if defined(POLLOUT)
-#    define POLLWRITEFLAGS POLLOUT
-#  else
-#    if defined(POLLWRNORM)
-#      define POLLWRITEFLAGS POLLWRNORM
-#    endif
-#  endif
-#endif
-
-#ifdef POLLHUP
-#define POLLERRORS (POLLHUP|POLLERR)
-#else
-#define POLLERRORS POLLERR
-#endif
-
-/*
- * NOTE: pfd and pfd_count are local variable names in read_message
- */
-#define PFD_SETR(xfd) \
-  do { CHECK_ADD_PFD(xfd) pfd->events |= POLLREADFLAGS; } while(0)
-#define PFD_SETW(xfd) \
-  do { CHECK_ADD_PFD(xfd) pfd->events |= POLLWRITEFLAGS; } while(0)
-
-#define CHECK_ADD_PFD(xfd) \
-  if (pfd->fd != xfd) { \
-    pfd = &poll_fds[pfd_count++]; \
-    poll_fds[pfd_count].fd = -1; \
-    pfd->fd = xfd; \
-    pfd->events = 0; \
-  }
-
-/*
- * 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.
- *
- * Don't ever use ZERO for `delay', unless you mean to poll and then
- * you have to have sleep/wait somewhere else in the code.--msa
- */
-int read_message(time_t delay)
-{
-  struct pollfd poll_fds[MAXCONNECTIONS + 1];
-  struct Client*      cptr;
-  struct Listener*    listener   = 0;
-  struct AuthRequest* auth       = 0;
-  struct AuthRequest* auth_next  = 0;
-  struct UPing*       uping      = 0;
-  struct UPing*       uping_next = 0;
-  time_t delay2 = delay;
-  int nfds;
-  int length;
-  int i;
-  int res = 0;
-  int pfd_count;
-  struct pollfd* pfd;
-  struct pollfd* res_pfd;
-  struct pollfd* uping_pfd;
-  int read_ready;
-  int write_ready;
-
-  unsigned int timeout;
-
-  for ( ; ; ) {
-    pfd_count = 0;
-    pfd = poll_fds;
-    res_pfd = 0;
-    uping_pfd = 0;
-    pfd->fd = -1;
-
-    if (-1 < ResolverFileDescriptor) {
-      PFD_SETR(ResolverFileDescriptor);
-      res_pfd = pfd;
-    }
-    if (-1 < UPingFileDescriptor) {
-      PFD_SETR(UPingFileDescriptor);
-      uping_pfd = pfd;
-    }
-    /*
-     * add uping descriptors
-     */
-    for (uping = uping_begin(); uping; uping = uping_next) {
-      uping_next = uping->next;
-      if (uping->active) {
-        delay2 = 1;
-       if (uping->lastsent && CurrentTime > uping->timeout) {
-          uping_end(uping);
-          continue;
-        }
-        uping->index = pfd_count;
-        PFD_SETR(uping->fd);
-      }
-    }
-    /*
-     * add auth file descriptors
-     */
-    for (auth = AuthPollList; auth; auth = auth->next) {
-      assert(-1 < auth->fd);
-      auth->index = pfd_count;
-      if (IsAuthConnect(auth))
-        PFD_SETW(auth->fd);
-      else
-        PFD_SETR(auth->fd);
-    }
-    /*
-     * add listener file descriptors
-     */    
-    for (listener = ListenerPollList; listener; listener = listener->next) {
-      assert(-1 < listener->fd);
-      /*
-       * pfd_count is incremented by PFD_SETR so we need to save the 
-       * index first 
-       */
-      listener->index = pfd_count;
-      PFD_SETR(listener->fd);
-    }
-
-    for (i = HighestFd; -1 < i; --i) {
-      if ((cptr = LocalClientArray[i])) {
-
-        if (DBufLength(&(cli_recvQ(cptr))))
-          delay2 = 1;
-        if (DBufLength(&(cli_recvQ(cptr))) < 4088 || IsServer(cptr)) {
-          PFD_SETR(i);
-        }
-        if (MsgQLength(&(cli_sendQ(cptr))) || IsConnecting(cptr) ||
-            (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)) {
-          PFD_SETW(i);
-        }
-      }
-    }
-
-    Debug((DEBUG_INFO, "poll: %d %d", delay, delay2));
-
-    timeout = (IRCD_MIN(delay2, delay)) * 1000;
-
-    nfds = poll(poll_fds, pfd_count, timeout);
-
-    CurrentTime = time(0);
-    if (-1 < nfds)
-      break;
-
-    if (EINTR == errno)
-      return -1;
-    report_error(POLL_ERROR_MSG, cli_name(&me), errno);
-    ++res;
-    if (res > 5)
-      server_restart("too many poll errors");
-    sleep(1);
-    CurrentTime = time(0);
-  }
-
-  if (uping_pfd && (uping_pfd->revents & (POLLREADFLAGS | POLLERRORS))) {
-    uping_echo();
-    --nfds;
-  }
-  /*
-   * check uping replies
-   */
-  for (uping = uping_begin(); uping; uping = uping_next) {
-    uping_next = uping->next;
-    if (uping->active) {
-      assert(-1 < uping->index);
-      if (poll_fds[uping->index].revents) {
-        uping_read(uping);
-        if (0 == --nfds)
-          break;
-      }
-      else if (CurrentTime > uping->lastsent) {
-        uping->lastsent = CurrentTime;
-        uping_send(uping);
-      }
-    }
-  }
-
-  if (res_pfd && (res_pfd->revents & (POLLREADFLAGS | POLLERRORS))) {
-    resolver_read();
-    --nfds;
-  }
-  /*
-   * check auth queries
-   */
-  for (auth = AuthPollList; auth; auth = auth_next) {
-    auth_next = auth->next;
-    i = auth->index;
-    /*
-     * check for any event, we only ask for one at a time
-     */
-    if (poll_fds[i].revents) {
-      if (IsAuthConnect(auth))
-        send_auth_query(auth);
-      else
-        read_auth_reply(auth);
-      if (0 == --nfds)
-        break;
-    }
-  }
-  /*
-   * check listeners
-   */
-  for (listener = ListenerPollList; listener; listener = listener->next) {
-    i = listener->index;
-    if (poll_fds[i].revents) {
-      accept_connection(listener);
-      if (0 == --nfds)
-        break;
+    /* If there's still data to process, wait 2 seconds first */
+    if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
+       !(cli_freeflag(cptr) & FREEFLAG_TIMER)) {
+      Debug((DEBUG_LIST, "Adding client process timer for %C", cptr));
+      cli_freeflag(cptr) |= FREEFLAG_TIMER;
+      timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr),
+               TT_RELATIVE, 2);
     }
   }
-  /*
-   * i contains the next non-auth/non-listener index, since we put the
-   * resolver, auth and listener, file descriptors in poll_fds first,
-   * the very next one should be the start of the clients
-   */
-  pfd = &poll_fds[++i];
-
-  for ( ; (i < pfd_count); ++i, ++pfd) {
-    if (!(cptr = LocalClientArray[pfd->fd]))
-      continue;
-    read_ready = write_ready = 0;
-
-    if (0 < nfds && pfd->revents) {
-      --nfds;
-    
-      read_ready  = pfd->revents & POLLREADFLAGS;
-      write_ready = pfd->revents & POLLWRITEFLAGS;
-
-      if (pfd->revents & POLLERRORS) {
-        if (pfd->events & POLLREADFLAGS)
-          ++read_ready;
-        if (pfd->events & POLLWRITEFLAGS)
-          ++write_ready;
-      }
-    }
-    if (write_ready) {
-      if (!on_write_unblocked(cptr) || IsDead(cptr)) {
-        const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : cli_info(cptr);
-        if (!msg)
-          msg = "Unknown error";
-        exit_client(cptr, cptr, &me, msg);
-        continue;
-      }
-    }
-    length = 1;                 /* for fall through case */
-    if ((!NoNewLine(cptr) || read_ready) && !IsDead(cptr)) {
-      if (CPTR_KILLED == (length = read_packet(cptr, read_ready)))
-        continue;
-    }
-#if 0
-    /* Bullshit, why would we want to flush sockets while using non-blocking?
-     * This uses > 4% cpu! --Run */
-    if (length > 0)
-      flush_connections(poll_cptr[i]);
-#endif
-    if (IsDead(cptr)) {
-      const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : cli_info(cptr);
-      if (!msg)
-        msg = "Unknown error";
-      exit_client(cptr, cptr, &me, (char*) msg);
-      continue;
-    }
-    if (length > 0)
-      continue;
-    cli_flags(cptr) |= FLAGS_DEADSOCKET;
-    /*
-     * ...hmm, with non-blocking sockets we might get
-     * here from quite valid reasons, although.. why
-     * would select report "data available" when there
-     * wasn't... So, this must be an error anyway...  --msa
-     * actually, EOF occurs when read() returns 0 and
-     * in due course, select() returns that fd as ready
-     * for reading even though it ends up being an EOF. -avalon
-     */
-    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", pfd->fd, errno, length));
-
-    if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0 && length == 0)
-      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
-                      cli_name(cptr), cli_serv(cptr)->last_error_msg);
-    else {
-      const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : "EOF from client";
-      if (!msg)
-        msg = "Unknown error";
-      exit_client_msg(cptr, cptr, &me, "Read error: %s", msg);
-    }
-  }
-  return 0;
-}
-#else /* USE_SELECT */
-
-/*
- * 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.
- *
- * Don't ever use ZERO for `delay', unless you mean to poll and then
- * you have to have sleep/wait somewhere else in the code.--msa
- */
-int read_message(time_t delay)
-{
-  struct Client*   cptr;
-  struct Listener* listener;
-  struct AuthRequest* auth = 0;
-  struct AuthRequest* auth_next = 0;
-  struct UPing*       uping;
-  struct UPing*       uping_next;
-  int              nfds;
-  struct timeval   wait;
-  time_t           delay2 = delay;
-  unsigned int     usec = 0;
-  int              res = 0;
-  int              length;
-  int              i;
-  int              read_ready;
-  fd_set           read_set;
-  fd_set           write_set;
-
-  for ( ; ; )
-  {
-    FD_ZERO(&read_set);
-    FD_ZERO(&write_set);
-
-    if (-1 < ResolverFileDescriptor)
-      FD_SET(ResolverFileDescriptor, &read_set);
-    if (-1 < UPingFileDescriptor)
-      FD_SET(UPingFileDescriptor, &read_set);
-    /*
-     * set up uping file descriptors
-     */
-    for (uping = uping_begin(); uping; uping = uping_next) {
-      uping_next = uping->next;
-      if (uping->active) {
-        delay2 = 1;
-        if (uping->lastsent && CurrentTime > uping->timeout) {
-          uping_end(uping);
-          continue;
-        }
-        assert(-1 < uping->fd);
-        FD_SET(uping->fd, &read_set);
-      }
-    }
-    /*
-     * set auth file descriptors
-     */
-    for (auth = AuthPollList; auth; auth = auth->next) {
-      assert(-1 < auth->fd);
-      if (IsAuthConnect(auth))
-        FD_SET(auth->fd, &write_set);
-      else /* if (IsAuthPending(auth)) */
-        FD_SET(auth->fd, &read_set);
-    }
-    /*
-     * set listener file descriptors
-     */
-    for (listener = ListenerPollList; listener; listener = listener->next) {
-      assert(-1 < listener->fd);
-      FD_SET(listener->fd, &read_set);
-    }
-
-    for (i = HighestFd; i > -1; --i) {
-      if ((cptr = LocalClientArray[i])) {
-        if (DBufLength(&(cli_recvQ(cptr))))
-          delay2 = 1;
-        if (DBufLength(&(cli_recvQ(cptr))) < 4088 || IsServer(cptr))
-          FD_SET(i, &read_set);
-        if (MsgQLength(&(cli_sendQ(cptr))) || IsConnecting(cptr) ||
-            (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048))
-          FD_SET(i, &write_set);
-      }
-    }
-
-    wait.tv_sec = IRCD_MIN(delay2, delay);
-    wait.tv_usec = usec;
-
-    Debug((DEBUG_INFO, "select: %d %d", delay, delay2));
-
-    nfds = select(FD_SETSIZE, &read_set, &write_set, 0, &wait);
-
-    CurrentTime = time(0);
-
-    if (-1 < nfds)
-      break;
-
-    if (errno == EINTR)
-      return -1;
-    report_error(SELECT_ERROR_MSG, cli_name(&me), errno);
-    if (++res > 5)
-      server_restart("too many select errors");
-    sleep(1);
-    CurrentTime = time(0);
-  }
-
-  if (-1 < UPingFileDescriptor && FD_ISSET(UPingFileDescriptor, &read_set)) {
-    uping_echo();
-    --nfds;
-  }
-  for (uping = uping_begin(); uping; uping = uping_next) {
-    uping_next = uping->next;
-    if (uping->active) {
-      assert(-1 < uping->fd);
-      if (FD_ISSET(uping->fd, &read_set)) {
-        uping_read(uping);
-        if (0 == --nfds)
-          break;
-      }
-      else if (CurrentTime > uping->lastsent) {
-        uping->lastsent = CurrentTime;
-        uping_send(uping);
-      }
-    }
-  }
-  if (-1 < ResolverFileDescriptor && FD_ISSET(ResolverFileDescriptor, &read_set)) {
-    resolver_read();
-    --nfds;
-  }
-  /*
-   * Check fd sets for the auth fd's (if set and valid!) first
-   * because these can not be processed using the normal loops below.
-   * -avalon
-   */
-  for (auth = AuthPollList; auth; auth = auth_next) {
-    auth_next = auth->next;
-    assert(-1 < auth->fd);
-    if (IsAuthConnect(auth) && FD_ISSET(auth->fd, &write_set)) {
-      send_auth_query(auth);
-      if (0 == --nfds)
-        break;
-    }
-    else if (FD_ISSET(auth->fd, &read_set)) {
-      read_auth_reply(auth);
-      if (0 == --nfds)
-        break;
-    }
-  }
-  /*
-   * next accept connections from active listeners
-   */
-  for (listener = ListenerPollList; listener; listener = listener->next) {
-    assert(-1 < listener->fd);
-    if (0 < nfds && FD_ISSET(listener->fd, &read_set))
-      accept_connection(listener);
-  } 
-
-  for (i = HighestFd; -1 < i; --i) {
-    if (!(cptr = LocalClientArray[i]))
-      continue;
-    read_ready = 0;
-    if (0 < nfds) {
-      if (FD_ISSET(i, &write_set)) {
-        --nfds;
-        if (!on_write_unblocked(cptr) || IsDead(cptr)) {
-          const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : cli_info(cptr);
-          if (!msg)
-            msg = "Unknown error";
-          if (FD_ISSET(i, &read_set))
-            --nfds;
-          exit_client(cptr, cptr, &me, msg);
-          continue;
-        }
-      }
-      if ((read_ready = FD_ISSET(i, &read_set)))
-        --nfds;
-    }
-    length = 1;                 /* for fall through case */
-    if ((!NoNewLine(cptr) || read_ready) && !IsDead(cptr)) {
-      if (CPTR_KILLED == (length = read_packet(cptr, read_ready)))
-        continue;
-    }
-    if (IsDead(cptr)) {
-      const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : cli_info(cptr);
-      if (!msg)
-        msg = "Unknown error";
-      exit_client(cptr, cptr, &me, msg);
-      continue;
-    }
-    if (length > 0)
-      continue;
-
-    /*
-     * ...hmm, with non-blocking sockets we might get
-     * here from quite valid reasons, although.. why
-     * would select report "data available" when there
-     * wasn't... So, this must be an error anyway...  --msa
-     * actually, EOF occurs when read() returns 0 and
-     * in due course, select() returns that fd as ready
-     * for reading even though it ends up being an EOF. -avalon
-     */
-    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", i, cli_error(cptr), length));
-
-    if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0 && length == 0)
-      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
-                      cli_name(cptr), cli_serv(cptr)->last_error_msg);
-    else {
-      const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : "EOF from client";
-      if (!msg)
-        msg = "Unknown error";
-      exit_client_msg(cptr, cptr, &me, "Read error: %s", msg);
-    }
-  }
-  return 0;
+  return 1;
 }
 
-#endif /* USE_SELECT */
-
 /*
  * connect_server - start or complete a connection to another server
  * returns true (1) if successful, false (0) otherwise
@@ -1420,9 +914,10 @@ int connect_server(struct ConfItem* aconf, struct Client* by,
    */
   add_client_to_list(cptr);
   hAddClient(cptr);
-  nextping = CurrentTime;
+/*    nextping = CurrentTime; */
 
-  return 1;
+  return (s_state(&cli_socket(cptr)) == SS_CONNECTED) ?
+    completed_connection(cptr) : 1;
 }
 
 /*
@@ -1449,4 +944,125 @@ void init_server_identity(void)
   SetYXXServerName(&me, conf->numeric);
 }
 
+/*
+ * Process events on a client socket
+ */
+static void client_sock_callback(struct Event* ev)
+{
+  struct Client* cptr;
+  struct Connection* con;
+  char *fmt = "%s";
+  char *fallback = 0;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  con = s_data(ev_socket(ev));
+
+  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);
+
+  cptr = con_client(con);
+
+  assert(0 == cptr || con == cli_connect(cptr));
+
+  switch (ev_type(ev)) {
+  case ET_DESTROY:
+    con_freeflag(con) &= ~FREEFLAG_SOCKET;
+
+    if (!con_freeflag(con) && !cptr)
+      free_connection(con);
+    break;
+
+  case ET_CONNECT: /* socket connection completed */
+    if (!completed_connection(cptr) || IsDead(cptr))
+      fallback = cli_info(cptr);
+    break;
+
+  case ET_ERROR: /* an error occurred */
+    fallback = cli_info(cptr);
+    cli_error(cptr) = ev_data(ev);
+    if (s_state(&(con_socket(con))) == SS_CONNECTING) {
+      completed_connection(cptr);
+      break;
+    }
+    /*FALLTHROUGH*/
+  case ET_EOF: /* end of file on socket */
+    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr),
+          cli_error(cptr)));
+    cli_flags(cptr) |= FLAGS_DEADSOCKET;
+    if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) {
+      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
+                     cli_name(cptr), cli_serv(cptr)->last_error_msg);
+      return;
+    } else {
+      fmt = "Read error: %s";
+      fallback = "EOF from client";
+    }
+    break;
+
+  case ET_WRITE: /* socket is writable */
+    cli_flags(cptr) &= ~FLAGS_BLOCKED;
+    if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
+      list_next_channels(cptr, 64);
+    Debug((DEBUG_SEND, "Sending queued data to %C", cptr));
+    send_queued(cptr);
+    break;
+
+  case ET_READ: /* socket is readable */
+    if (!IsDead(cptr)) {
+      Debug((DEBUG_DEBUG, "Reading data from %C", cptr));
+      if (read_packet(cptr, 1) == 0) /* error while reading packet */
+       fallback = "EOF from client";
+    }
+    break;
+
+  default:
+#ifndef NDEBUG
+    abort(); /* unrecognized event */
+#endif
+    break;
+  }
+
+  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
+
+  if (fallback) {
+    const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback;
+    if (!msg)
+      msg = "Unknown error";
+    exit_client_msg(cptr, cptr, &me, fmt, msg);
+  }
+}
+
+/*
+ * Process a timer on client socket
+ */
+static void client_timer_callback(struct Event* ev)
+{
+  struct Client* cptr;
+  struct Connection* con;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+  assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));
+
+  con = t_data(ev_timer(ev));
 
+  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);
+
+  cptr = con_client(con);
+
+  assert(0 == cptr || con == cli_connect(cptr));
+
+  con_freeflag(con) &= ~FREEFLAG_TIMER; /* timer has expired... */
+
+  if (ev_type(ev)== ET_DESTROY) {
+    if (!con_freeflag(con) && !cptr)
+      free_connection(con); /* client is being destroyed */
+  } else {
+    Debug((DEBUG_LIST, "Client process timer for %C expired; processing",
+          cptr));
+    read_packet(cptr, 0); /* read_packet will re-add timer if needed */
+  }
+
+  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
+}
index 49f56494f8d1a8e88b07a68c390d8c3bede04641..05cd7ce2b8e81a689cb835398401eb9a697495f9 100644 (file)
@@ -1231,7 +1231,7 @@ int read_configuration_file(void)
   if (aconf)
     free_conf(aconf);
   fbclose(file);
-  nextping = nextconnect = CurrentTime;
+/*    nextping = nextconnect = CurrentTime; */
   feature_mark(); /* reset unmarked features */
   return 1;
 }
index d0702656e26e31faaf353cea7814d05cbf05d9f8..7a4fda37f4620ff7a7fee4c24804c6455a0dc18f 100644 (file)
@@ -507,7 +507,7 @@ static Numeric replyTable[] = {
 /* 236 */
   { 0 },
 /* 237 */
-  { 0 },
+  { RPL_STATSENGINE, "%s :Event loop engine", "237" },
 /* 238 */
   { RPL_STATSFLINE, "%c %s %s", "238" },
 /* 239 */
index 4777df1280abb8b148435c8939bedfe3593571e0..ff5d2e0149dba658a4091ff9dabe5bb17b70334d 100644 (file)
@@ -137,7 +137,7 @@ int server_estab(struct Client *cptr, struct ConfItem *aconf,
 
   SetBurst(cptr);
 
-  nextping = CurrentTime;
+/*    nextping = CurrentTime; */
 
   /*
    * NOTE: check for acptr->user == cptr->serv->user is necessary to insure
index 38ecc7cda24c65c9355128f19ce0a1d1bd73075c..8743ae45dcd2962450f61a1fa3335b29c974f482 100644 (file)
@@ -73,6 +73,7 @@ const char *statsinfo[] = {
     "g - Global bans (G-lines).",
     "k - Local bans (K-Lines).",
     "o - Operator information.", 
+    "e - Report server event loop engine.",
     "f - Feature settings.",
     "m - Message usage information.",
     "t - Local connection statistics (Total SND/RCV, etc).", 
index 0a71c4a742b1370d67fed4851949b6b008a0f3ea..6d7cc911a40a0119fbbef57ff251724ef4100069 100644 (file)
@@ -535,7 +535,7 @@ int register_user(struct Client *cptr, struct Client *sptr,
     m_lusers(sptr, sptr, 1, parv);
     update_load();
     motd_signon(sptr);
-    nextping = CurrentTime;
+/*      nextping = CurrentTime; */
     if (cli_snomask(sptr) & SNO_NOISY)
       set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
     IPcheck_connect_succeeded(sptr);
index 89ee2b908f010e91f28d91980950009ec508c849..bf8335dc7b26ab951f409a54c22be4b9369947d6 100644 (file)
@@ -140,8 +140,10 @@ void send_queued(struct Client *to)
     if ((len = deliver_it(to, &(cli_sendQ(to))))) {
       msgq_delete(&(cli_sendQ(to)), len);
       cli_lastsq(to) = MsgQLength(&(cli_sendQ(to))) / 1024;
-      if (IsBlocked(to))
+      if (IsBlocked(to)) {
+       update_write(to);
         return;
+      }
     }
     else {
       if (IsDead(to)) {
@@ -155,6 +157,7 @@ void send_queued(struct Client *to)
 
   /* Ok, sendq is now empty... */
   client_drop_sendq(cli_connect(to));
+  update_write(to);
 }
 
 void send_buffer(struct Client* to, struct MsgBuf* buf, int prio)
@@ -184,6 +187,7 @@ void send_buffer(struct Client* to, struct MsgBuf* buf, int prio)
 
   msgq_add(&(cli_sendQ(to)), buf, prio);
   client_add_sendq(cli_connect(to), &send_queues);
+  update_write(to);
 
   /*
    * Update statistics. The following is slightly incorrect
index 1c35a7f21c018ed14aa41bcb67de211c87f038df..a83c57ed424817fe6a1ae5e9e290de01270fc08c 100644 (file)
@@ -24,6 +24,7 @@
 #include "client.h"
 #include "ircd.h"
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "ircd_log.h"
 #include "ircd_osdep.h"
 #include "ircd_string.h"
@@ -59,6 +60,8 @@
 static struct UPing* pingList = 0;
 int UPingFileDescriptor       = -1; /* UDP listener socket for upings */
 
+static struct Socket upingSock;
+
 /*
  * pings_begin - iterator function for ping list 
  */
@@ -88,6 +91,14 @@ static void uping_erase(struct UPing* p)
   }
 }
 
+/* Called when the event engine detects activity on the UPing socket */
+static void uping_echo_callback(struct Event* ev)
+{
+  assert(ev_type(ev) == ET_READ);
+
+  uping_echo();
+}
+
 /*
  * Setup a UDP socket and listen for incoming packets
  */
@@ -129,6 +140,12 @@ int uping_init(void)
     close(fd);
     return -1;
   }
+  if (!socket_add(&upingSock, uping_echo_callback, 0, SS_DATAGRAM,
+                 SOCK_EVENT_READABLE, fd)) {
+    Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
+    close(fd);
+    return -1;
+  }
   UPingFileDescriptor = fd;
   return fd;
 }
@@ -168,6 +185,85 @@ void uping_echo()
 }
 
 
+/* Callback when socket has data to read */
+static void uping_read_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  pptr = s_data(ev_socket(ev));
+
+  Debug((DEBUG_SEND, "uping_read_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_SOCKET;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_READ);
+
+    uping_read(pptr); /* read uping response */
+  }
+}
+
+/* Callback to send another ping */
+static void uping_sender_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  pptr = t_data(ev_timer(ev));
+
+  Debug((DEBUG_SEND, "uping_sender_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_SENDER;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    pptr->lastsent = CurrentTime; /* store last ping time */
+    uping_send(pptr); /* send a ping */
+
+    if (pptr->sent == pptr->count) /* done sending pings, don't send more */
+      timer_del(ev_timer(ev));
+  }
+}
+
+/* Callback to kill a ping */
+static void uping_killer_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  pptr = t_data(ev_timer(ev));
+
+  Debug((DEBUG_SEND, "uping_killer_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_KILLER;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    uping_end(pptr); /* <FUDD>kill the uping, kill the uping!</FUDD> */
+  }
+}
+
 /*
  * start_ping
  */
@@ -175,10 +271,15 @@ static void uping_start(struct UPing* pptr)
 {
   assert(0 != pptr);
 
+  timer_add(&pptr->sender, uping_sender_callback, (void*) pptr,
+           TT_PERIODIC, 1);
+  timer_add(&pptr->killer, uping_killer_callback, (void*) pptr,
+           TT_RELATIVE, UPINGTIMEOUT);
+  pptr->freeable |= UPING_PENDING_SENDER | UPING_PENDING_KILLER;
+
   sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :Sending %d ping%s to %s",
                pptr->client, pptr->count, (pptr->count == 1) ? "" : "s",
                pptr->name);
-  pptr->timeout = CurrentTime + UPINGTIMEOUT;
   pptr->active = 1;
 }
 
@@ -264,11 +365,8 @@ void uping_read(struct UPing* pptr)
     pptr->ms_min = pingtime;
   if (pingtime > pptr->ms_max)
     pptr->ms_max = pingtime;
-  
-  pptr->timeout = CurrentTime + UPINGTIMEOUT;
 
-  Debug((DEBUG_SEND, "read_ping: %d bytes, ti %lu: [%s %s] %lu ms",
-         len, pptr->timeout, buf, (buf + strlen(buf) + 1), pingtime));
+  timer_chg(&pptr->killer, TT_RELATIVE, UPINGTIMEOUT);
 
   s = pptr->buf + strlen(pptr->buf);
   sprintf(s, " %u", pingtime);
@@ -311,6 +409,15 @@ int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int coun
   assert(0 != pptr);
   memset(pptr, 0, sizeof(struct UPing));
 
+  if (!socket_add(&pptr->socket, uping_read_callback, (void*) pptr,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't queue fd for "
+                 "reading", sptr);
+    close(fd);
+    MyFree(pptr);
+    return 0;
+  }
+
   pptr->fd                  = fd;
   pptr->sin.sin_port        = htons(port);
   pptr->sin.sin_addr.s_addr = aconf->ipnum.s_addr;
@@ -318,6 +425,7 @@ int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int coun
   pptr->count               = IRCD_MIN(20, count);
   pptr->client              = sptr;
   pptr->index               = -1;
+  pptr->freeable            = UPING_PENDING_SOCKET;
   strcpy(pptr->name, aconf->name);
 
   pptr->next = pingList;
@@ -356,7 +464,12 @@ void uping_end(struct UPing* pptr)
   uping_erase(pptr);
   if (pptr->client)
     ClearUPing(pptr->client);
-  MyFree(pptr);
+  if (pptr->freeable & UPING_PENDING_SOCKET)
+    socket_del(&pptr->socket);
+  if (pptr->freeable & UPING_PENDING_SENDER)
+    timer_del(&pptr->sender);
+  if (pptr->freeable & UPING_PENDING_KILLER)
+    timer_del(&pptr->killer);
 }
 
 void uping_cancel(struct Client *sptr, struct Client* acptr)