OpenDNSSEC-signer  2.1.6
netio.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
3  *
4  * See LICENSE for the license.
5  *
6  */
7 
8 #include <config.h>
9 
10 #include <assert.h>
11 #include <errno.h>
12 #include <sys/time.h>
13 #include <string.h>
14 #include <stdlib.h>
15 
16 #include "log.h"
17 #include "wire/netio.h"
18 
19 
20 #ifndef HAVE_PSELECT
21 int pselect(int n, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
22  const struct timespec* timeout, const sigset_t* sigmask);
23 #else
24 #include <sys/select.h>
25 #endif
26 
27 /* One second is 1e9 nanoseconds. */
28 #define NANOSECONDS_PER_SECOND 1000000000L
29 
30 static const char* netio_str = "netio";
31 
32 
33 /*
34  * Create a new netio instance.
35  * \return netio_type* netio instance
36  *
37  */
40 {
41  netio_type* netio = NULL;
42  CHECKALLOC(netio = (netio_type*) malloc(sizeof(netio_type)));
43  netio->handlers = NULL;
44  netio->dispatch_next = NULL;
45  return netio;
46 }
47 
48 /*
49  * Add a new handler to netio.
50  *
51  */
52 void
54 {
55  netio_handler_list_type* l = NULL;
56 
57  ods_log_assert(netio);
58  ods_log_assert(handler);
59 
60  CHECKALLOC(l = (netio_handler_list_type*) malloc(sizeof(netio_handler_list_type)));
61  l->next = netio->handlers;
62  l->handler = handler;
63  netio->handlers = l;
64  ods_log_debug("[%s] handler added", netio_str);
65 }
66 
67 /*
68  * Remove the handler from netio. Caller is responsible for freeing
69  * handler afterwards.
70  */
71 void
73 {
75  if (!netio || !handler) {
76  return;
77  }
78  for (lptr = &netio->handlers; *lptr; lptr = &(*lptr)->next) {
79  if ((*lptr)->handler == handler) {
80  netio_handler_list_type* next = (*lptr)->next;
81  if ((*lptr) == netio->dispatch_next) {
82  netio->dispatch_next = next;
83  }
84  (*lptr)->handler = NULL;
85  free(*lptr);
86  *lptr = next;
87  break;
88  }
89  }
90  ods_log_debug("[%s] handler removed", netio_str);
91 }
92 
93 
94 /*
95  * Convert timeval to timespec.
96  *
97  */
98 static void
99 timeval_to_timespec(struct timespec* left, const struct timeval* right)
100 {
101  left->tv_sec = right->tv_sec;
102  left->tv_nsec = 1000 * right->tv_usec;
103 }
104 
109 static int
110 timespec_compare(const struct timespec* left,
111  const struct timespec* right)
112 {
113  if (left->tv_sec < right->tv_sec) {
114  return -1;
115  } else if (left->tv_sec > right->tv_sec) {
116  return 1;
117  } else if (left->tv_nsec < right->tv_nsec) {
118  return -1;
119  } else if (left->tv_nsec > right->tv_nsec) {
120  return 1;
121  }
122  return 0;
123 }
124 
125 
130 void
131 timespec_add(struct timespec* left, const struct timespec* right)
132 {
133  left->tv_sec += right->tv_sec;
134  left->tv_nsec += right->tv_nsec;
135  if (left->tv_nsec >= NANOSECONDS_PER_SECOND) {
136  ++left->tv_sec;
137  left->tv_nsec -= NANOSECONDS_PER_SECOND;
138  }
139 }
140 
141 
146 static void
147 timespec_subtract(struct timespec* left, const struct timespec* right)
148 {
149  left->tv_sec -= right->tv_sec;
150  left->tv_nsec -= right->tv_nsec;
151  if (left->tv_nsec < 0L) {
152  --left->tv_sec;
153  left->tv_nsec += NANOSECONDS_PER_SECOND;
154  }
155 }
156 
157 
158 /*
159  * Retrieve the current time (using gettimeofday(2)).
160  *
161  */
162 const struct timespec*
164 {
165  struct timeval current_timeval;
166  ods_log_assert(netio);
167  if (!netio->have_current_time) {
168  if (gettimeofday(&current_timeval, NULL) == -1) {
169  ods_log_crit("[%s] unable to get current time: "
170  "gettimeofday() failed (%s)", netio_str,
171  strerror(errno));
172  abort();
173  }
174  timeval_to_timespec(&netio->cached_current_time,
175  &current_timeval);
176  netio->have_current_time = 1;
177  }
178  return &netio->cached_current_time;
179 }
180 
181 
182 /*
183  * Check for events and dispatch them to the handlers.
184  *
185  */
186 int
187 netio_dispatch(netio_type* netio, const struct timespec* timeout,
188  const sigset_t* sigmask)
189 {
190  fd_set readfds, writefds, exceptfds;
191  int max_fd;
192  int have_timeout = 0;
193  struct timespec minimum_timeout;
194  netio_handler_type* timeout_handler = NULL;
195  netio_handler_list_type* l = NULL;
196  int rc = 0;
197  int result = 0;
198 
199  if (!netio || !netio->handlers) {
200  return 0;
201  }
202  /* Clear the cached current time */
203  netio->have_current_time = 0;
204  /* Initialize the minimum timeout with the timeout parameter */
205  if (timeout) {
206  have_timeout = 1;
207  memcpy(&minimum_timeout, timeout, sizeof(struct timespec));
208  }
209  /* Initialize the fd_sets and timeout based on the handler
210  * information */
211  max_fd = -1;
212  FD_ZERO(&readfds);
213  FD_ZERO(&writefds);
214  FD_ZERO(&exceptfds);
215  for (l = netio->handlers; l; l = l->next) {
216  netio_handler_type* handler = l->handler;
217  if (handler->fd >= 0 && handler->fd < (int) FD_SETSIZE) {
218  if (handler->fd > max_fd) {
219  max_fd = handler->fd;
220  }
221  if (handler->event_types & NETIO_EVENT_READ) {
222  FD_SET(handler->fd, &readfds);
223  }
224  if (handler->event_types & NETIO_EVENT_WRITE) {
225  FD_SET(handler->fd, &writefds);
226  }
227  if (handler->event_types & NETIO_EVENT_EXCEPT) {
228  FD_SET(handler->fd, &exceptfds);
229  }
230  }
231  if (handler->timeout &&
232  (handler->event_types & NETIO_EVENT_TIMEOUT)) {
233  struct timespec relative;
234  relative.tv_sec = handler->timeout->tv_sec;
235  relative.tv_nsec = handler->timeout->tv_nsec;
236  timespec_subtract(&relative, netio_current_time(netio));
237 
238  if (!have_timeout ||
239  timespec_compare(&relative, &minimum_timeout) < 0) {
240  have_timeout = 1;
241  minimum_timeout.tv_sec = relative.tv_sec;
242  minimum_timeout.tv_nsec = relative.tv_nsec;
243  timeout_handler = handler;
244  }
245  }
246  }
247 
248  if (have_timeout && minimum_timeout.tv_sec < 0) {
249  /*
250  * On negative timeout for a handler, immediately
251  * dispatch the timeout event without checking for other events.
252  */
253  ods_log_debug("[%s] dispatch timeout event without checking for "
254  "other events", netio_str);
255  if (timeout_handler &&
256  (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) {
257  timeout_handler->event_handler(netio, timeout_handler,
259  }
260  return result;
261  }
262  /* Check for events. */
263  rc = pselect(max_fd + 1, &readfds, &writefds, &exceptfds,
264  have_timeout ? &minimum_timeout : NULL, sigmask);
265  if (rc == -1) {
266  if(errno == EINVAL || errno == EACCES || errno == EBADF) {
267  ods_fatal_exit("[%s] fatal error pselect: %s", netio_str,
268  strerror(errno));
269  }
270  return -1;
271  }
272 
273  /* Clear the cached current_time (pselect(2) may block for
274  * some time so the cached value is likely to be old).
275  */
276  netio->have_current_time = 0;
277  if (rc == 0) {
278  ods_log_debug("[%s] no events before the minimum timeout "
279  "expired", netio_str);
280  /*
281  * No events before the minimum timeout expired.
282  * Dispatch to handler if interested.
283  */
284  if (timeout_handler &&
285  (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) {
286  timeout_handler->event_handler(netio, timeout_handler,
288  }
289  } else {
290  /*
291  * Dispatch all the events to interested handlers
292  * based on the fd_sets. Note that a handler might
293  * deinstall itself, so store the next handler before
294  * calling the current handler!
295  */
296  ods_log_assert(netio->dispatch_next == NULL);
297  for (l = netio->handlers; l && rc; ) {
298  netio_handler_type* handler = l->handler;
299  netio->dispatch_next = l->next;
300  if (handler->fd >= 0 && handler->fd < (int) FD_SETSIZE) {
301  netio_events_type event_types = NETIO_EVENT_NONE;
302  if (FD_ISSET(handler->fd, &readfds)) {
303  event_types |= NETIO_EVENT_READ;
304  FD_CLR(handler->fd, &readfds);
305  rc--;
306  }
307  if (FD_ISSET(handler->fd, &writefds)) {
308  event_types |= NETIO_EVENT_WRITE;
309  FD_CLR(handler->fd, &writefds);
310  rc--;
311  }
312  if (FD_ISSET(handler->fd, &exceptfds)) {
313  event_types |= NETIO_EVENT_EXCEPT;
314  FD_CLR(handler->fd, &exceptfds);
315  rc--;
316  }
317  if (event_types & handler->event_types) {
318  handler->event_handler(netio, handler,
319  event_types & handler->event_types);
320  ++result;
321  }
322  }
323  l = netio->dispatch_next;
324  }
325  netio->dispatch_next = NULL;
326  }
327  return result;
328 }
329 
330 
335 void
337 {
338  ods_log_assert(netio);
339  while (netio->handlers) {
340  netio_handler_list_type* handler = netio->handlers;
341  netio->handlers = handler->next;
342  if (handler->handler->free_handler) {
343  free(handler->handler->user_data);
344  free(handler->handler);
345  }
346  free(handler);
347  }
348  free(netio);
349 }
350 
354 void
356 {
357  ods_log_assert(netio);
358  free(netio->handlers);
359  free(netio);
360 }
361 
pselect
int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
netio_handler_struct
Definition: netio.h:102
netio_struct
Definition: netio.h:139
netio_add_handler
void netio_add_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:53
netio_struct::handlers
netio_handler_list_type * handlers
Definition: netio.h:140
netio_cleanup
void netio_cleanup(netio_type *netio)
Definition: netio.c:336
netio_current_time
const struct timespec * netio_current_time(netio_type *netio)
Definition: netio.c:163
netio.h
NANOSECONDS_PER_SECOND
#define NANOSECONDS_PER_SECOND
Definition: netio.c:28
NETIO_EVENT_NONE
@ NETIO_EVENT_NONE
Definition: netio.h:70
netio_handler_struct::free_handler
int free_handler
Definition: netio.h:132
netio_handler_list_struct::handler
netio_handler_type * handler
Definition: netio.h:95
netio_handler_list_struct
Definition: netio.h:93
NETIO_EVENT_WRITE
@ NETIO_EVENT_WRITE
Definition: netio.h:72
netio_struct::dispatch_next
netio_handler_list_type * dispatch_next
Definition: netio.h:156
netio_events_type
enum netio_events_enum netio_events_type
Definition: netio.h:76
netio_handler_struct::fd
int fd
Definition: netio.h:108
netio_struct::have_current_time
int have_current_time
Definition: netio.h:150
netio_handler_list_struct::next
netio_handler_list_type * next
Definition: netio.h:94
netio_handler_struct::user_data
void * user_data
Definition: netio.h:119
timespec_add
void timespec_add(struct timespec *left, const struct timespec *right)
Definition: netio.c:131
netio_create
netio_type * netio_create()
Definition: netio.c:39
netio_handler_struct::event_handler
netio_event_handler_type event_handler
Definition: netio.h:131
netio_cleanup_shallow
void netio_cleanup_shallow(netio_type *netio)
Definition: netio.c:355
NETIO_EVENT_READ
@ NETIO_EVENT_READ
Definition: netio.h:71
netio_dispatch
int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask)
Definition: netio.c:187
netio_handler_struct::event_types
netio_events_type event_types
Definition: netio.h:124
netio_remove_handler
void netio_remove_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:72
netio_struct::cached_current_time
struct timespec cached_current_time
Definition: netio.h:151
netio_handler_struct::timeout
struct timespec * timeout
Definition: netio.h:115
NETIO_EVENT_EXCEPT
@ NETIO_EVENT_EXCEPT
Definition: netio.h:73
NETIO_EVENT_TIMEOUT
@ NETIO_EVENT_TIMEOUT
Definition: netio.h:74