/* * netio.h -- network I/O support. * * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * * The netio module implements event based I/O handling using * pselect(2). Multiple event handlers can wait for a certain event * to occur simultaneously. Each event handler is called when an * event occurs that the event handler has indicated that it is * willing to handle. * * There are four types of events that can be handled: * * NETIO_EVENT_READ: reading will not block. * NETIO_EVENT_WRITE: writing will not block. * NETIO_EVENT_EXCEPT: an exception occurred. * NETIO_EVENT_TIMEOUT: the timeout expired. * * A file descriptor must be specified if the handler is interested in * the first three event types. A timeout must be specified if the * event handler is interested in timeouts. These event types can be * OR'ed together if the handler is willing to handle multiple types * of events. * * The special event type NETIO_EVENT_NONE is available if you wish to * temporarily disable the event handler without removing and adding * the handler to the netio structure. * * The event callbacks are free to modify the netio_handler_type * structure to change the file descriptor, timeout, event types, user * data, or handler functions. * * The main loop of the program must call netio_dispatch to check for * events and dispatch them to the handlers. An additional timeout * can be specified as well as the signal mask to install while * blocked in pselect(2). */ #ifndef _NETIO_H_ #define _NETIO_H_ #ifdef HAVE_SYS_SELECT_H #include #endif #include #include "region-allocator.h" #define NETIO_SLOW_ACCEPT_TIMEOUT 2 /* in seconds */ /* * The type of events a handler is interested in. These can be OR'ed * together to specify multiple event types. */ enum netio_event_types { NETIO_EVENT_NONE = 0, NETIO_EVENT_READ = 1, NETIO_EVENT_WRITE = 2, NETIO_EVENT_EXCEPT = 4, NETIO_EVENT_TIMEOUT = 8, NETIO_EVENT_ACCEPT = 16 }; typedef enum netio_event_types netio_event_types_type; typedef struct netio netio_type; typedef struct netio_handler netio_handler_type; typedef struct netio_handler_list netio_handler_list_type; struct netio { region_type *region; netio_handler_list_type *handlers; netio_handler_list_type *deallocated; /* * Cached value of the current time. The cached value is * cleared at the start of netio_dispatch to calculate the * relative timeouts of the event handlers and after calling * pselect(2) so handlers can use it to calculate a new * absolute timeout. * * Use netio_current_time() to read the current time. */ int have_current_time; struct timespec cached_current_time; /* * Next handler in the dispatch. Only valid during callbacks. * To make sure that deletes respect the state of the iterator. */ netio_handler_list_type *dispatch_next; }; typedef void (*netio_event_handler_type)(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types); struct netio_handler { /* * The file descriptor that should be checked for events. If * the file descriptor is negative only timeout events are * checked for. */ int fd; /* * The time when no events should be checked for and the * handler should be called with the NETIO_EVENT_TIMEOUT * event type. Unlike most timeout parameters the time should * be absolute, not relative! */ struct timespec *timeout; /* * Additional user data. */ void *user_data; /* * The type of events that should be checked for. These types * can be OR'ed together to wait for multiple types of events. */ netio_event_types_type event_types; /* * The event handler. The event_types parameter contains the * OR'ed set of event types that actually triggered. The * event handler is allowed to modify this handler object. * The event handler SHOULD NOT block. */ netio_event_handler_type event_handler; }; struct netio_handler_list { netio_handler_list_type *next; netio_handler_type *handler; }; /* * Create a new netio instance using the specified REGION. The netio * instance is cleaned up when the REGION is deallocated. */ netio_type *netio_create(region_type *region); /* * Add a new HANDLER to NETIO. */ void netio_add_handler(netio_type *netio, netio_handler_type *handler); /* * Remove the HANDLER from NETIO. */ void netio_remove_handler(netio_type *netio, netio_handler_type *handler); /* * Retrieve the current time (using gettimeofday(2). */ const struct timespec *netio_current_time(netio_type *netio); /* * Check for events and dispatch them to the handlers. If TIMEOUT is * specified it specifies the maximum time to wait for an event to * arrive. SIGMASK is passed to the underlying pselect(2) call. * Returns the number of non-timeout events dispatched, 0 on timeout, * and -1 on error (with errno set appropriately). */ int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask); #ifdef __cplusplus inline netio_event_types_type operator | (netio_event_types_type lhs, netio_event_types_type rhs) { return (netio_event_types_type) (lhs | rhs); } inline netio_event_types_type operator |= (netio_event_types_type &lhs, netio_event_types_type rhs) { lhs = (netio_event_types_type) (lhs | rhs); return lhs; } #endif /* __cplusplus */ #endif /* _NETIO_H_ */