191 lines
5.3 KiB
C
191 lines
5.3 KiB
C
/*
|
|
* netio.h -- network I/O support.
|
|
*
|
|
* Copyright (c) 2001-2006, 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_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 <sys/select.h>
|
|
#endif
|
|
|
|
#include <signal.h>
|
|
|
|
#include "region-allocator.h"
|
|
|
|
/*
|
|
* 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_TIMEOUT = 4,
|
|
};
|
|
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;
|
|
|
|
/** index of the pollfd array for this handler */
|
|
int pfd;
|
|
|
|
/*
|
|
* 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 */
|