xref: /openbsd/usr.sbin/nsd/netio.h (revision 91f110e0)
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_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 /*
54  * The type of events a handler is interested in.  These can be OR'ed
55  * together to specify multiple event types.
56  */
57 enum netio_event_types {
58 	NETIO_EVENT_NONE    = 0,
59 	NETIO_EVENT_READ    = 1,
60 	NETIO_EVENT_WRITE   = 2,
61 	NETIO_EVENT_EXCEPT  = 4,
62 	NETIO_EVENT_TIMEOUT = 8,
63 };
64 typedef enum netio_event_types netio_event_types_type;
65 
66 typedef struct netio netio_type;
67 typedef struct netio_handler netio_handler_type;
68 typedef struct netio_handler_list netio_handler_list_type;
69 
70 struct netio
71 {
72 	region_type             *region;
73 	netio_handler_list_type *handlers;
74 	netio_handler_list_type *deallocated;
75 
76 	/*
77 	 * Cached value of the current time.  The cached value is
78 	 * cleared at the start of netio_dispatch to calculate the
79 	 * relative timeouts of the event handlers and after calling
80 	 * pselect(2) so handlers can use it to calculate a new
81 	 * absolute timeout.
82 	 *
83 	 * Use netio_current_time() to read the current time.
84 	 */
85 	int have_current_time;
86 	struct timespec cached_current_time;
87 
88 	/*
89 	 * Next handler in the dispatch. Only valid during callbacks.
90 	 * To make sure that deletes respect the state of the iterator.
91 	 */
92 	netio_handler_list_type *dispatch_next;
93 };
94 
95 typedef void (*netio_event_handler_type)(netio_type *netio,
96 					 netio_handler_type *handler,
97 					 netio_event_types_type event_types);
98 
99 struct netio_handler
100 {
101 	/*
102 	 * The file descriptor that should be checked for events.  If
103 	 * the file descriptor is negative only timeout events are
104 	 * checked for.
105 	 */
106 	int fd;
107 
108 	/*
109 	 * The time when no events should be checked for and the
110 	 * handler should be called with the NETIO_EVENT_TIMEOUT
111 	 * event type.  Unlike most timeout parameters the time should
112 	 * be absolute, not relative!
113 	 */
114 	struct timespec *timeout;
115 
116 	/*
117 	 * Additional user data.
118 	 */
119 	void *user_data;
120 
121 	/*
122 	 * The type of events that should be checked for.  These types
123 	 * can be OR'ed together to wait for multiple types of events.
124 	 */
125 	netio_event_types_type event_types;
126 
127 	/*
128 	 * The event handler.  The event_types parameter contains the
129 	 * OR'ed set of event types that actually triggered.  The
130 	 * event handler is allowed to modify this handler object.
131 	 * The event handler SHOULD NOT block.
132 	 */
133 	netio_event_handler_type event_handler;
134 };
135 
136 
137 struct netio_handler_list
138 {
139 	netio_handler_list_type *next;
140 	netio_handler_type      *handler;
141 };
142 
143 
144 /*
145  * Create a new netio instance using the specified REGION.  The netio
146  * instance is cleaned up when the REGION is deallocated.
147  */
148 netio_type *netio_create(region_type *region);
149 
150 /*
151  * Add a new HANDLER to NETIO.
152  */
153 void netio_add_handler(netio_type *netio, netio_handler_type *handler);
154 
155 /*
156  * Remove the HANDLER from NETIO.
157  */
158 void netio_remove_handler(netio_type *netio, netio_handler_type *handler);
159 
160 /*
161  * Retrieve the current time (using gettimeofday(2).
162  */
163 const struct timespec *netio_current_time(netio_type *netio);
164 
165 /*
166  * Check for events and dispatch them to the handlers.  If TIMEOUT is
167  * specified it specifies the maximum time to wait for an event to
168  * arrive.  SIGMASK is passed to the underlying pselect(2) call.
169  * Returns the number of non-timeout events dispatched, 0 on timeout,
170  * and -1 on error (with errno set appropriately).
171  */
172 int netio_dispatch(netio_type *netio,
173 		   const struct timespec *timeout,
174 		   const sigset_t *sigmask);
175 
176 
177 #ifdef __cplusplus
178 inline netio_event_types_type
179 operator | (netio_event_types_type lhs, netio_event_types_type rhs) {
180 	return (netio_event_types_type) (lhs | rhs);
181 }
182 inline netio_event_types_type
183 operator |= (netio_event_types_type &lhs, netio_event_types_type rhs) {
184 	lhs = (netio_event_types_type) (lhs | rhs);
185 	return lhs;
186 }
187 #endif /* __cplusplus */
188 
189 #endif /* _NETIO_H_ */
190