1/*
2 * netio.h -- network I/O support.
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 *
9 * The netio module implements event based I/O handling using
10 * pselect(2).  Multiple event handlers can wait for a certain event
11 * to occur simultaneously.  Each event handler is called when an
12 * event occurs that the event handler has indicated that it is
13 * willing to handle.
14 *
15 * There are four types of events that can be handled:
16 *
17 *   NETIO_EVENT_READ: reading will not block.
18 *   NETIO_EVENT_WRITE: writing will not block.
19 *   NETIO_EVENT_TIMEOUT: the timeout expired.
20 *
21 * A file descriptor must be specified if the handler is interested in
22 * the first three event types.  A timeout must be specified if the
23 * event handler is interested in timeouts.  These event types can be
24 * OR'ed together if the handler is willing to handle multiple types
25 * of events.
26 *
27 * The special event type NETIO_EVENT_NONE is available if you wish to
28 * temporarily disable the event handler without removing and adding
29 * the handler to the netio structure.
30 *
31 * The event callbacks are free to modify the netio_handler_type
32 * structure to change the file descriptor, timeout, event types, user
33 * data, or handler functions.
34 *
35 * The main loop of the program must call netio_dispatch to check for
36 * events and dispatch them to the handlers.  An additional timeout
37 * can be specified as well as the signal mask to install while
38 * blocked in pselect(2).
39 */
40
41#ifndef NETIO_H
42#define NETIO_H
43
44#ifdef	HAVE_SYS_SELECT_H
45#include <sys/select.h>
46#endif
47
48#include <signal.h>
49
50#include "region-allocator.h"
51
52/*
53 * The type of events a handler is interested in.  These can be OR'ed
54 * together to specify multiple event types.
55 */
56enum netio_event_types {
57	NETIO_EVENT_NONE    = 0,
58	NETIO_EVENT_READ    = 1,
59	NETIO_EVENT_WRITE   = 2,
60	NETIO_EVENT_TIMEOUT = 4,
61};
62typedef enum netio_event_types netio_event_types_type;
63
64typedef struct netio netio_type;
65typedef struct netio_handler netio_handler_type;
66typedef struct netio_handler_list netio_handler_list_type;
67
68struct netio
69{
70	region_type             *region;
71	netio_handler_list_type *handlers;
72	netio_handler_list_type *deallocated;
73
74	/*
75	 * Cached value of the current time.  The cached value is
76	 * cleared at the start of netio_dispatch to calculate the
77	 * relative timeouts of the event handlers and after calling
78	 * pselect(2) so handlers can use it to calculate a new
79	 * absolute timeout.
80	 *
81	 * Use netio_current_time() to read the current time.
82	 */
83	int have_current_time;
84	struct timespec cached_current_time;
85
86	/*
87	 * Next handler in the dispatch. Only valid during callbacks.
88	 * To make sure that deletes respect the state of the iterator.
89	 */
90	netio_handler_list_type *dispatch_next;
91};
92
93typedef void (*netio_event_handler_type)(netio_type *netio,
94					 netio_handler_type *handler,
95					 netio_event_types_type event_types);
96
97struct netio_handler
98{
99	/*
100	 * The file descriptor that should be checked for events.  If
101	 * the file descriptor is negative only timeout events are
102	 * checked for.
103	 */
104	int fd;
105
106	/** index of the pollfd array for this handler */
107	int pfd;
108
109	/*
110	 * The time when no events should be checked for and the
111	 * handler should be called with the NETIO_EVENT_TIMEOUT
112	 * event type.  Unlike most timeout parameters the time should
113	 * be absolute, not relative!
114	 */
115	struct timespec *timeout;
116
117	/*
118	 * Additional user data.
119	 */
120	void *user_data;
121
122	/*
123	 * The type of events that should be checked for.  These types
124	 * can be OR'ed together to wait for multiple types of events.
125	 */
126	netio_event_types_type event_types;
127
128	/*
129	 * The event handler.  The event_types parameter contains the
130	 * OR'ed set of event types that actually triggered.  The
131	 * event handler is allowed to modify this handler object.
132	 * The event handler SHOULD NOT block.
133	 */
134	netio_event_handler_type event_handler;
135};
136
137
138struct netio_handler_list
139{
140	netio_handler_list_type *next;
141	netio_handler_type      *handler;
142};
143
144
145/*
146 * Create a new netio instance using the specified REGION.  The netio
147 * instance is cleaned up when the REGION is deallocated.
148 */
149netio_type *netio_create(region_type *region);
150
151/*
152 * Add a new HANDLER to NETIO.
153 */
154void netio_add_handler(netio_type *netio, netio_handler_type *handler);
155
156/*
157 * Remove the HANDLER from NETIO.
158 */
159void netio_remove_handler(netio_type *netio, netio_handler_type *handler);
160
161/*
162 * Retrieve the current time (using gettimeofday(2).
163 */
164const struct timespec *netio_current_time(netio_type *netio);
165
166/*
167 * Check for events and dispatch them to the handlers.  If TIMEOUT is
168 * specified it specifies the maximum time to wait for an event to
169 * arrive.  SIGMASK is passed to the underlying pselect(2) call.
170 * Returns the number of non-timeout events dispatched, 0 on timeout,
171 * and -1 on error (with errno set appropriately).
172 */
173int netio_dispatch(netio_type *netio,
174		   const struct timespec *timeout,
175		   const sigset_t *sigmask);
176
177
178#ifdef __cplusplus
179inline netio_event_types_type
180operator | (netio_event_types_type lhs, netio_event_types_type rhs) {
181	return (netio_event_types_type) (lhs | rhs);
182}
183inline netio_event_types_type
184operator |= (netio_event_types_type &lhs, netio_event_types_type rhs) {
185	lhs = (netio_event_types_type) (lhs | rhs);
186	return lhs;
187}
188#endif /* __cplusplus */
189
190#endif /* NETIO_H */
191