OpenDNSSEC-signer  2.0.3
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->deallocated = NULL;
45  netio->dispatch_next = NULL;
46  return netio;
47 }
48 
49 /*
50  * Add a new handler to netio.
51  *
52  */
53 void
55 {
56  netio_handler_list_type* l = NULL;
57  if (!netio || !handler) {
58  return;
59  }
60  if (netio->deallocated) {
61  l = netio->deallocated;
62  netio->deallocated = l->next;
63  } else {
64  CHECKALLOC(l = (netio_handler_list_type*) malloc(sizeof(netio_handler_list_type)));
65  }
66  l->next = netio->handlers;
67  l->handler = handler;
68  netio->handlers = l;
69  ods_log_debug("[%s] handler added", netio_str);
70 }
71 
72 /*
73  * Remove the handler from netio.
74  *
75  */
76 void
78 {
80  if (!netio || !handler) {
81  return;
82  }
83  for (lptr = &netio->handlers; *lptr; lptr = &(*lptr)->next) {
84  if ((*lptr)->handler == handler) {
85  netio_handler_list_type* next = (*lptr)->next;
86  if ((*lptr) == netio->dispatch_next) {
87  netio->dispatch_next = next;
88  }
89  (*lptr)->handler = NULL;
90  (*lptr)->next = netio->deallocated;
91  netio->deallocated = *lptr;
92  *lptr = next;
93  break;
94  }
95  }
96  ods_log_debug("[%s] handler removed", netio_str);
97 }
98 
99 
100 /*
101  * Convert timeval to timespec.
102  *
103  */
104 static void
105 timeval_to_timespec(struct timespec* left, const struct timeval* right)
106 {
107  left->tv_sec = right->tv_sec;
108  left->tv_nsec = 1000 * right->tv_usec;
109 }
110 
115 static int
116 timespec_compare(const struct timespec* left,
117  const struct timespec* right)
118 {
119  if (left->tv_sec < right->tv_sec) {
120  return -1;
121  } else if (left->tv_sec > right->tv_sec) {
122  return 1;
123  } else if (left->tv_nsec < right->tv_nsec) {
124  return -1;
125  } else if (left->tv_nsec > right->tv_nsec) {
126  return 1;
127  }
128  return 0;
129 }
130 
131 
136 void
137 timespec_add(struct timespec* left, const struct timespec* right)
138 {
139  left->tv_sec += right->tv_sec;
140  left->tv_nsec += right->tv_nsec;
141  if (left->tv_nsec >= NANOSECONDS_PER_SECOND) {
142  ++left->tv_sec;
143  left->tv_nsec -= NANOSECONDS_PER_SECOND;
144  }
145 }
146 
147 
152 static void
153 timespec_subtract(struct timespec* left, const struct timespec* right)
154 {
155  left->tv_sec -= right->tv_sec;
156  left->tv_nsec -= right->tv_nsec;
157  if (left->tv_nsec < 0L) {
158  --left->tv_sec;
159  left->tv_nsec += NANOSECONDS_PER_SECOND;
160  }
161 }
162 
163 
164 /*
165  * Retrieve the current time (using gettimeofday(2)).
166  *
167  */
168 const struct timespec*
170 {
171  struct timeval current_timeval;
172  ods_log_assert(netio);
173  if (!netio->have_current_time) {
174  if (gettimeofday(&current_timeval, NULL) == -1) {
175  ods_log_crit("[%s] unable to get current time: "
176  "gettimeofday() failed (%s)", netio_str,
177  strerror(errno));
178  abort();
179  }
180  timeval_to_timespec(&netio->cached_current_time,
181  &current_timeval);
182  netio->have_current_time = 1;
183  }
184  return &netio->cached_current_time;
185 }
186 
187 
188 /*
189  * Check for events and dispatch them to the handlers.
190  *
191  */
192 int
193 netio_dispatch(netio_type* netio, const struct timespec* timeout,
194  const sigset_t* sigmask)
195 {
196  fd_set readfds, writefds, exceptfds;
197  int max_fd;
198  int have_timeout = 0;
199  struct timespec minimum_timeout;
200  netio_handler_type* timeout_handler = NULL;
201  netio_handler_list_type* l = NULL;
202  int rc = 0;
203  int result = 0;
204 
205  if (!netio || !netio->handlers) {
206  return 0;
207  }
208  /* Clear the cached current time */
209  netio->have_current_time = 0;
210  /* Initialize the minimum timeout with the timeout parameter */
211  if (timeout) {
212  have_timeout = 1;
213  memcpy(&minimum_timeout, timeout, sizeof(struct timespec));
214  }
215  /* Initialize the fd_sets and timeout based on the handler
216  * information */
217  max_fd = -1;
218  FD_ZERO(&readfds);
219  FD_ZERO(&writefds);
220  FD_ZERO(&exceptfds);
221  for (l = netio->handlers; l; l = l->next) {
222  netio_handler_type* handler = l->handler;
223  if (handler->fd >= 0 && handler->fd < (int) FD_SETSIZE) {
224  if (handler->fd > max_fd) {
225  max_fd = handler->fd;
226  }
227  if (handler->event_types & NETIO_EVENT_READ) {
228  FD_SET(handler->fd, &readfds);
229  }
230  if (handler->event_types & NETIO_EVENT_WRITE) {
231  FD_SET(handler->fd, &writefds);
232  }
233  if (handler->event_types & NETIO_EVENT_EXCEPT) {
234  FD_SET(handler->fd, &exceptfds);
235  }
236  }
237  if (handler->timeout &&
238  (handler->event_types & NETIO_EVENT_TIMEOUT)) {
239  struct timespec relative;
240  relative.tv_sec = handler->timeout->tv_sec;
241  relative.tv_nsec = handler->timeout->tv_nsec;
242  timespec_subtract(&relative, netio_current_time(netio));
243 
244  if (!have_timeout ||
245  timespec_compare(&relative, &minimum_timeout) < 0) {
246  have_timeout = 1;
247  minimum_timeout.tv_sec = relative.tv_sec;
248  minimum_timeout.tv_nsec = relative.tv_nsec;
249  timeout_handler = handler;
250  }
251  }
252  }
253 
254  if (have_timeout && minimum_timeout.tv_sec < 0) {
255  /*
256  * On negative timeout for a handler, immediately
257  * dispatch the timeout event without checking for other events.
258  */
259  ods_log_debug("[%s] dispatch timeout event without checking for "
260  "other events", netio_str);
261  if (timeout_handler &&
262  (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) {
263  timeout_handler->event_handler(netio, timeout_handler,
265  }
266  return result;
267  }
268  /* Check for events. */
269  rc = pselect(max_fd + 1, &readfds, &writefds, &exceptfds,
270  have_timeout ? &minimum_timeout : NULL, sigmask);
271  if (rc == -1) {
272  if(errno == EINVAL || errno == EACCES || errno == EBADF) {
273  ods_fatal_exit("[%s] fatal error pselect: %s", netio_str,
274  strerror(errno));
275  }
276  return -1;
277  }
278 
279  /* Clear the cached current_time (pselect(2) may block for
280  * some time so the cached value is likely to be old).
281  */
282  netio->have_current_time = 0;
283  if (rc == 0) {
284  ods_log_debug("[%s] no events before the minimum timeout "
285  "expired", netio_str);
286  /*
287  * No events before the minimum timeout expired.
288  * Dispatch to handler if interested.
289  */
290  if (timeout_handler &&
291  (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) {
292  timeout_handler->event_handler(netio, timeout_handler,
294  }
295  } else {
296  /*
297  * Dispatch all the events to interested handlers
298  * based on the fd_sets. Note that a handler might
299  * deinstall itself, so store the next handler before
300  * calling the current handler!
301  */
302  ods_log_assert(netio->dispatch_next == NULL);
303  for (l = netio->handlers; l && rc; ) {
304  netio_handler_type* handler = l->handler;
305  netio->dispatch_next = l->next;
306  if (handler->fd >= 0 && handler->fd < (int) FD_SETSIZE) {
307  netio_events_type event_types = NETIO_EVENT_NONE;
308  if (FD_ISSET(handler->fd, &readfds)) {
309  event_types |= NETIO_EVENT_READ;
310  FD_CLR(handler->fd, &readfds);
311  rc--;
312  }
313  if (FD_ISSET(handler->fd, &writefds)) {
314  event_types |= NETIO_EVENT_WRITE;
315  FD_CLR(handler->fd, &writefds);
316  rc--;
317  }
318  if (FD_ISSET(handler->fd, &exceptfds)) {
319  event_types |= NETIO_EVENT_EXCEPT;
320  FD_CLR(handler->fd, &exceptfds);
321  rc--;
322  }
323  if (event_types & handler->event_types) {
324  handler->event_handler(netio, handler,
325  event_types & handler->event_types);
326  ++result;
327  }
328  }
329  l = netio->dispatch_next;
330  }
331  netio->dispatch_next = NULL;
332  }
333  return result;
334 }
335 
336 
341 void
343 {
344  if (!netio) {
345  return;
346  }
347  free(netio->handlers);
348  free(netio->deallocated);
349  free(netio);
350 }
351 
netio_handler_list_type * handlers
Definition: netio.h:139
void timespec_add(struct timespec *left, const struct timespec *right)
Definition: netio.c:137
netio_handler_type * handler
Definition: netio.h:95
enum netio_events_enum netio_events_type
Definition: netio.h:76
int have_current_time
Definition: netio.h:150
netio_handler_list_type * next
Definition: netio.h:94
struct timespec cached_current_time
Definition: netio.h:151
void netio_add_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:54
const struct timespec * netio_current_time(netio_type *netio)
Definition: netio.c:169
netio_event_handler_type event_handler
Definition: netio.h:131
#define NANOSECONDS_PER_SECOND
Definition: netio.c:28
void netio_remove_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:77
netio_handler_list_type * deallocated
Definition: netio.h:140
netio_events_type event_types
Definition: netio.h:124
netio_type * netio_create()
Definition: netio.c:39
struct timespec * timeout
Definition: netio.h:115
int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
netio_handler_list_type * dispatch_next
Definition: netio.h:156
int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask)
Definition: netio.c:193
void netio_cleanup(netio_type *netio)
Definition: netio.c:342