summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd/netio.h
blob: a0e805e9ea56ed22b21d737110902197f1849d29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
 * 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_ */