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