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