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