xref: /openbsd/usr.sbin/nsd/netio.h (revision 3efee2e1)
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  */
56 enum netio_event_types {
57 	NETIO_EVENT_NONE    = 0,
58 	NETIO_EVENT_READ    = 1,
59 	NETIO_EVENT_WRITE   = 2,
60 	NETIO_EVENT_TIMEOUT = 4,
61 };
62 typedef enum netio_event_types netio_event_types_type;
63 
64 typedef struct netio netio_type;
65 typedef struct netio_handler netio_handler_type;
66 typedef struct netio_handler_list netio_handler_list_type;
67 
68 struct 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 
93 typedef void (*netio_event_handler_type)(netio_type *netio,
94 					 netio_handler_type *handler,
95 					 netio_event_types_type event_types);
96 
97 struct 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 
138 struct 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  */
149 netio_type *netio_create(region_type *region);
150 
151 /*
152  * Add a new HANDLER to NETIO.
153  */
154 void netio_add_handler(netio_type *netio, netio_handler_type *handler);
155 
156 /*
157  * Remove the HANDLER from NETIO.
158  */
159 void netio_remove_handler(netio_type *netio, netio_handler_type *handler);
160 
161 /*
162  * Retrieve the current time (using gettimeofday(2).
163  */
164 const 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  */
173 int netio_dispatch(netio_type *netio,
174 		   const struct timespec *timeout,
175 		   const sigset_t *sigmask);
176 
177 
178 #ifdef __cplusplus
179 inline netio_event_types_type
180 operator | (netio_event_types_type lhs, netio_event_types_type rhs) {
181 	return (netio_event_types_type) (lhs | rhs);
182 }
183 inline netio_event_types_type
184 operator |= (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