162ac0c33Sjakob /* 262ac0c33Sjakob * netio.h -- network I/O support. 362ac0c33Sjakob * 4d3fecca9Ssthen * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 562ac0c33Sjakob * 662ac0c33Sjakob * See LICENSE for the license. 762ac0c33Sjakob * 862ac0c33Sjakob * 962ac0c33Sjakob * The netio module implements event based I/O handling using 1062ac0c33Sjakob * pselect(2). Multiple event handlers can wait for a certain event 1162ac0c33Sjakob * to occur simultaneously. Each event handler is called when an 1262ac0c33Sjakob * event occurs that the event handler has indicated that it is 1362ac0c33Sjakob * willing to handle. 1462ac0c33Sjakob * 1562ac0c33Sjakob * There are four types of events that can be handled: 1662ac0c33Sjakob * 1762ac0c33Sjakob * NETIO_EVENT_READ: reading will not block. 1862ac0c33Sjakob * NETIO_EVENT_WRITE: writing will not block. 1962ac0c33Sjakob * NETIO_EVENT_TIMEOUT: the timeout expired. 2062ac0c33Sjakob * 2162ac0c33Sjakob * A file descriptor must be specified if the handler is interested in 2262ac0c33Sjakob * the first three event types. A timeout must be specified if the 2362ac0c33Sjakob * event handler is interested in timeouts. These event types can be 2462ac0c33Sjakob * OR'ed together if the handler is willing to handle multiple types 2562ac0c33Sjakob * of events. 2662ac0c33Sjakob * 2762ac0c33Sjakob * The special event type NETIO_EVENT_NONE is available if you wish to 2862ac0c33Sjakob * temporarily disable the event handler without removing and adding 2962ac0c33Sjakob * the handler to the netio structure. 3062ac0c33Sjakob * 3162ac0c33Sjakob * The event callbacks are free to modify the netio_handler_type 3262ac0c33Sjakob * structure to change the file descriptor, timeout, event types, user 3362ac0c33Sjakob * data, or handler functions. 3462ac0c33Sjakob * 3562ac0c33Sjakob * The main loop of the program must call netio_dispatch to check for 3662ac0c33Sjakob * events and dispatch them to the handlers. An additional timeout 3762ac0c33Sjakob * can be specified as well as the signal mask to install while 3862ac0c33Sjakob * blocked in pselect(2). 3962ac0c33Sjakob */ 4062ac0c33Sjakob 41*3efee2e1Sflorian #ifndef NETIO_H 42*3efee2e1Sflorian #define NETIO_H 4362ac0c33Sjakob 4462ac0c33Sjakob #ifdef HAVE_SYS_SELECT_H 4562ac0c33Sjakob #include <sys/select.h> 4662ac0c33Sjakob #endif 4762ac0c33Sjakob 4862ac0c33Sjakob #include <signal.h> 4962ac0c33Sjakob 5062ac0c33Sjakob #include "region-allocator.h" 5162ac0c33Sjakob 5262ac0c33Sjakob /* 5362ac0c33Sjakob * The type of events a handler is interested in. These can be OR'ed 5462ac0c33Sjakob * together to specify multiple event types. 5562ac0c33Sjakob */ 5662ac0c33Sjakob enum netio_event_types { 5762ac0c33Sjakob NETIO_EVENT_NONE = 0, 5862ac0c33Sjakob NETIO_EVENT_READ = 1, 5962ac0c33Sjakob NETIO_EVENT_WRITE = 2, 603126abd5Ssthen NETIO_EVENT_TIMEOUT = 4, 6162ac0c33Sjakob }; 6262ac0c33Sjakob typedef enum netio_event_types netio_event_types_type; 6362ac0c33Sjakob 6462ac0c33Sjakob typedef struct netio netio_type; 6562ac0c33Sjakob typedef struct netio_handler netio_handler_type; 6662ac0c33Sjakob typedef struct netio_handler_list netio_handler_list_type; 6762ac0c33Sjakob 6862ac0c33Sjakob struct netio 6962ac0c33Sjakob { 7062ac0c33Sjakob region_type *region; 7162ac0c33Sjakob netio_handler_list_type *handlers; 7262ac0c33Sjakob netio_handler_list_type *deallocated; 7362ac0c33Sjakob 7462ac0c33Sjakob /* 7562ac0c33Sjakob * Cached value of the current time. The cached value is 7662ac0c33Sjakob * cleared at the start of netio_dispatch to calculate the 7762ac0c33Sjakob * relative timeouts of the event handlers and after calling 7862ac0c33Sjakob * pselect(2) so handlers can use it to calculate a new 7962ac0c33Sjakob * absolute timeout. 8062ac0c33Sjakob * 8162ac0c33Sjakob * Use netio_current_time() to read the current time. 8262ac0c33Sjakob */ 8362ac0c33Sjakob int have_current_time; 8462ac0c33Sjakob struct timespec cached_current_time; 8562ac0c33Sjakob 8662ac0c33Sjakob /* 8762ac0c33Sjakob * Next handler in the dispatch. Only valid during callbacks. 8862ac0c33Sjakob * To make sure that deletes respect the state of the iterator. 8962ac0c33Sjakob */ 9062ac0c33Sjakob netio_handler_list_type *dispatch_next; 9162ac0c33Sjakob }; 9262ac0c33Sjakob 9362ac0c33Sjakob typedef void (*netio_event_handler_type)(netio_type *netio, 9462ac0c33Sjakob netio_handler_type *handler, 9562ac0c33Sjakob netio_event_types_type event_types); 9662ac0c33Sjakob 9762ac0c33Sjakob struct netio_handler 9862ac0c33Sjakob { 9962ac0c33Sjakob /* 10062ac0c33Sjakob * The file descriptor that should be checked for events. If 10162ac0c33Sjakob * the file descriptor is negative only timeout events are 10262ac0c33Sjakob * checked for. 10362ac0c33Sjakob */ 10462ac0c33Sjakob int fd; 10562ac0c33Sjakob 1063126abd5Ssthen /** index of the pollfd array for this handler */ 1073126abd5Ssthen int pfd; 1083126abd5Ssthen 10962ac0c33Sjakob /* 11062ac0c33Sjakob * The time when no events should be checked for and the 11162ac0c33Sjakob * handler should be called with the NETIO_EVENT_TIMEOUT 11262ac0c33Sjakob * event type. Unlike most timeout parameters the time should 11362ac0c33Sjakob * be absolute, not relative! 11462ac0c33Sjakob */ 11562ac0c33Sjakob struct timespec *timeout; 11662ac0c33Sjakob 11762ac0c33Sjakob /* 11862ac0c33Sjakob * Additional user data. 11962ac0c33Sjakob */ 12062ac0c33Sjakob void *user_data; 12162ac0c33Sjakob 12262ac0c33Sjakob /* 12362ac0c33Sjakob * The type of events that should be checked for. These types 12462ac0c33Sjakob * can be OR'ed together to wait for multiple types of events. 12562ac0c33Sjakob */ 12662ac0c33Sjakob netio_event_types_type event_types; 12762ac0c33Sjakob 12862ac0c33Sjakob /* 12962ac0c33Sjakob * The event handler. The event_types parameter contains the 13062ac0c33Sjakob * OR'ed set of event types that actually triggered. The 13162ac0c33Sjakob * event handler is allowed to modify this handler object. 13262ac0c33Sjakob * The event handler SHOULD NOT block. 13362ac0c33Sjakob */ 13462ac0c33Sjakob netio_event_handler_type event_handler; 13562ac0c33Sjakob }; 13662ac0c33Sjakob 13762ac0c33Sjakob 13812455795Ssthen struct netio_handler_list 13912455795Ssthen { 14012455795Ssthen netio_handler_list_type *next; 14112455795Ssthen netio_handler_type *handler; 14212455795Ssthen }; 14312455795Ssthen 14412455795Ssthen 14562ac0c33Sjakob /* 14662ac0c33Sjakob * Create a new netio instance using the specified REGION. The netio 14762ac0c33Sjakob * instance is cleaned up when the REGION is deallocated. 14862ac0c33Sjakob */ 14962ac0c33Sjakob netio_type *netio_create(region_type *region); 15062ac0c33Sjakob 15162ac0c33Sjakob /* 15262ac0c33Sjakob * Add a new HANDLER to NETIO. 15362ac0c33Sjakob */ 15462ac0c33Sjakob void netio_add_handler(netio_type *netio, netio_handler_type *handler); 15562ac0c33Sjakob 15662ac0c33Sjakob /* 15762ac0c33Sjakob * Remove the HANDLER from NETIO. 15862ac0c33Sjakob */ 15962ac0c33Sjakob void netio_remove_handler(netio_type *netio, netio_handler_type *handler); 16062ac0c33Sjakob 16162ac0c33Sjakob /* 16262ac0c33Sjakob * Retrieve the current time (using gettimeofday(2). 16362ac0c33Sjakob */ 16462ac0c33Sjakob const struct timespec *netio_current_time(netio_type *netio); 16562ac0c33Sjakob 16662ac0c33Sjakob /* 16762ac0c33Sjakob * Check for events and dispatch them to the handlers. If TIMEOUT is 16862ac0c33Sjakob * specified it specifies the maximum time to wait for an event to 16962ac0c33Sjakob * arrive. SIGMASK is passed to the underlying pselect(2) call. 17062ac0c33Sjakob * Returns the number of non-timeout events dispatched, 0 on timeout, 17162ac0c33Sjakob * and -1 on error (with errno set appropriately). 17262ac0c33Sjakob */ 17362ac0c33Sjakob int netio_dispatch(netio_type *netio, 17462ac0c33Sjakob const struct timespec *timeout, 17562ac0c33Sjakob const sigset_t *sigmask); 17662ac0c33Sjakob 17762ac0c33Sjakob 17862ac0c33Sjakob #ifdef __cplusplus 17962ac0c33Sjakob inline netio_event_types_type 18062ac0c33Sjakob operator | (netio_event_types_type lhs, netio_event_types_type rhs) { 18162ac0c33Sjakob return (netio_event_types_type) (lhs | rhs); 18262ac0c33Sjakob } 18362ac0c33Sjakob inline netio_event_types_type 18462ac0c33Sjakob operator |= (netio_event_types_type &lhs, netio_event_types_type rhs) { 18562ac0c33Sjakob lhs = (netio_event_types_type) (lhs | rhs); 18662ac0c33Sjakob return lhs; 18762ac0c33Sjakob } 18862ac0c33Sjakob #endif /* __cplusplus */ 18962ac0c33Sjakob 190*3efee2e1Sflorian #endif /* NETIO_H */ 191