ISC DHCP  4.3.6
A reference DHCPv4 and DHCPv6 implementation
dispatch.c
Go to the documentation of this file.
1 /* dispatch.c
2 
3  I/O dispatcher. */
4 
5 /*
6  * Copyright (c) 2004,2007-2009,2013-2014 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Internet Systems Consortium, Inc.
22  * 950 Charter Street
23  * Redwood City, CA 94063
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
27  */
28 
29 #include "dhcpd.h"
30 
31 #include <omapip/omapip_p.h>
32 #include <sys/time.h>
33 
34 static omapi_io_object_t omapi_io_states;
35 struct timeval cur_tv;
36 
38 
41 OMAPI_OBJECT_ALLOC (omapi_waiter,
43 
44 void
45 register_eventhandler(struct eventqueue **queue, void (*handler)(void *))
46 {
47  struct eventqueue *t, *q;
48 
49  /* traverse to end of list */
50  t = NULL;
51  for (q = *queue ; q ; q = q->next) {
52  if (q->handler == handler)
53  return; /* handler already registered */
54  t = q;
55  }
56 
57  q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL));
58  if (!q)
59  log_fatal("register_eventhandler: no memory!");
60  memset(q, 0, sizeof *q);
61  if (t)
62  t->next = q;
63  else
64  *queue = q;
65  q->handler = handler;
66  return;
67 }
68 
69 void
70 unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *))
71 {
72  struct eventqueue *t, *q;
73 
74  /* traverse to end of list */
75  t= NULL;
76  for (q = *queue ; q ; q = q->next) {
77  if (q->handler == handler) {
78  if (t)
79  t->next = q->next;
80  else
81  *queue = q->next;
82  dfree(q, MDL); /* Don't access q after this!*/
83  break;
84  }
85  t = q;
86  }
87  return;
88 }
89 
90 void
91 trigger_event(struct eventqueue **queue)
92 {
93  struct eventqueue *q;
94 
95  for (q=*queue ; q ; q=q->next) {
96  if (q->handler)
97  (*q->handler)(NULL);
98  }
99 }
100 
101 /*
102  * Callback routine to connect the omapi I/O object and socket with
103  * the isc socket code. The isc socket code will call this routine
104  * which will then call the correct local routine to process the bytes.
105  *
106  * Currently we are always willing to read more data, this should be modified
107  * so that on connections we don't read more if we already have enough.
108  *
109  * If we have more bytes to write we ask the library to call us when
110  * we can write more. If we indicate we don't have more to write we need
111  * to poke the library via isc_socket_fdwatchpoke.
112  */
113 
114 /*
115  * sockdelete indicates if we are deleting the socket or leaving it in place
116  * 1 is delete, 0 is leave in place
117  */
118 #define SOCKDELETE 1
119 int
120 omapi_iscsock_cb(isc_task_t *task,
121  isc_socket_t *socket,
122  void *cbarg,
123  int flags)
124 {
125  omapi_io_object_t *obj;
126  isc_result_t status;
127 
128  /* Get the current time... */
129  gettimeofday (&cur_tv, (struct timezone *)0);
130 
131  /* isc socket stuff */
132 #if SOCKDELETE
133  /*
134  * walk through the io states list, if our object is on there
135  * service it. if not ignore it.
136  */
137  for (obj = omapi_io_states.next;
138  (obj != NULL) && (obj->next != NULL);
139  obj = obj->next) {
140  if (obj == cbarg)
141  break;
142  }
143  if (obj == NULL) {
144  return(0);
145  }
146 #else
147  /* Not much to be done if we have the wrong type of object. */
148  if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) {
149  log_fatal ("Incorrect object type, must be of type io_object");
150  }
151  obj = (omapi_io_object_t *)cbarg;
152 
153  /*
154  * If the object is marked as closed don't try and process
155  * anything just indicate that we don't want any more.
156  *
157  * This should be a temporary fix until we arrange to properly
158  * close the socket.
159  */
160  if (obj->closed == ISC_TRUE) {
161  return(0);
162  }
163 #endif
164 
165  if ((flags == ISC_SOCKFDWATCH_READ) &&
166  (obj->reader != NULL) &&
167  (obj->inner != NULL)) {
168  status = obj->reader(obj->inner);
169  /*
170  * If we are shutting down (basically tried to
171  * read and got no bytes) we don't need to try
172  * again.
173  */
174  if (status == ISC_R_SHUTTINGDOWN)
175  return (0);
176  /* Otherwise We always ask for more when reading */
177  return (1);
178  } else if ((flags == ISC_SOCKFDWATCH_WRITE) &&
179  (obj->writer != NULL) &&
180  (obj->inner != NULL)) {
181  status = obj->writer(obj->inner);
182  /* If the writer has more to write they should return
183  * ISC_R_INPROGRESS */
184  if (status == ISC_R_INPROGRESS) {
185  return (1);
186  }
187  }
188 
189  /*
190  * We get here if we either had an error (inconsistent
191  * structures etc) or no more to write, tell the socket
192  * lib we don't have more to do right now.
193  */
194  return (0);
195 }
196 
197 /* Register an I/O handle so that we can do asynchronous I/O on it. */
198 
200  int (*readfd) (omapi_object_t *),
201  int (*writefd) (omapi_object_t *),
202  isc_result_t (*reader)
203  (omapi_object_t *),
204  isc_result_t (*writer)
205  (omapi_object_t *),
206  isc_result_t (*reaper)
207  (omapi_object_t *))
208 {
209  isc_result_t status;
210  omapi_io_object_t *obj, *p;
211  int fd_flags = 0, fd = 0;
212 
213  /* omapi_io_states is a static object. If its reference count
214  is zero, this is the first I/O handle to be registered, so
215  we need to initialize it. Because there is no inner or outer
216  pointer on this object, and we're setting its refcnt to 1, it
217  will never be freed. */
218  if (!omapi_io_states.refcnt) {
219  omapi_io_states.refcnt = 1;
220  omapi_io_states.type = omapi_type_io_object;
221  }
222 
223  obj = (omapi_io_object_t *)0;
224  status = omapi_io_allocate (&obj, MDL);
225  if (status != ISC_R_SUCCESS)
226  return status;
227  obj->closed = ISC_FALSE; /* mark as open */
228 
229  status = omapi_object_reference (&obj -> inner, h, MDL);
230  if (status != ISC_R_SUCCESS) {
231  omapi_io_dereference (&obj, MDL);
232  return status;
233  }
234 
235  status = omapi_object_reference (&h -> outer,
236  (omapi_object_t *)obj, MDL);
237  if (status != ISC_R_SUCCESS) {
238  omapi_io_dereference (&obj, MDL);
239  return status;
240  }
241 
242  /*
243  * Attach the I/O object to the isc socket library via the
244  * fdwatch function. This allows the socket library to watch
245  * over a socket that we built. If there are both a read and
246  * a write socket we asssume they are the same socket.
247  */
248 
249  if (readfd) {
250  fd_flags |= ISC_SOCKFDWATCH_READ;
251  fd = readfd(h);
252  }
253 
254  if (writefd) {
255  fd_flags |= ISC_SOCKFDWATCH_WRITE;
256  fd = writefd(h);
257  }
258 
259  if (fd_flags != 0) {
260  status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr,
261  fd, fd_flags,
263  obj,
265  &obj->fd);
266  if (status != ISC_R_SUCCESS) {
267  log_error("Unable to register fd with library %s",
268  isc_result_totext(status));
269 
270  /*sar*/
271  /* is this the cleanup we need? */
272  omapi_object_dereference(&h->outer, MDL);
273  omapi_io_dereference (&obj, MDL);
274  return (status);
275  }
276  }
277 
278 
279  /* Find the last I/O state, if there are any. */
280  for (p = omapi_io_states.next;
281  p && p -> next; p = p -> next)
282  ;
283  if (p)
284  omapi_io_reference (&p -> next, obj, MDL);
285  else
286  omapi_io_reference (&omapi_io_states.next, obj, MDL);
287 
288  obj -> readfd = readfd;
289  obj -> writefd = writefd;
290  obj -> reader = reader;
291  obj -> writer = writer;
292  obj -> reaper = reaper;
293 
294  omapi_io_dereference(&obj, MDL);
295  return ISC_R_SUCCESS;
296 }
297 
298 /*
299  * ReRegister an I/O handle so that we can do asynchronous I/O on it.
300  * If the handle doesn't exist we call the register routine to build it.
301  * If it does exist we change the functions associated with it, and
302  * repoke the fd code to make it happy. Neither the objects nor the
303  * fd are allowed to have changed.
304  */
305 
307  int (*readfd) (omapi_object_t *),
308  int (*writefd) (omapi_object_t *),
309  isc_result_t (*reader)
310  (omapi_object_t *),
311  isc_result_t (*writer)
312  (omapi_object_t *),
313  isc_result_t (*reaper)
314  (omapi_object_t *))
315 {
316  omapi_io_object_t *obj;
317  int fd_flags = 0;
318 
319  if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
320  /*
321  * If we don't have an object or if the type isn't what
322  * we expect do the normal registration (which will overwrite
323  * an incorrect type, that's what we did historically, may
324  * want to change that)
325  */
326  return (omapi_register_io_object (h, readfd, writefd,
327  reader, writer, reaper));
328  }
329 
330  /* We have an io object of the correct type, try to update it */
331  /*sar*/
332  /* Should we validate that the fd matches the previous one?
333  * It's suppossed to, that's a requirement, don't bother yet */
334 
335  obj = (omapi_io_object_t *)h->outer;
336 
337  obj->readfd = readfd;
338  obj->writefd = writefd;
339  obj->reader = reader;
340  obj->writer = writer;
341  obj->reaper = reaper;
342 
343  if (readfd) {
344  fd_flags |= ISC_SOCKFDWATCH_READ;
345  }
346 
347  if (writefd) {
348  fd_flags |= ISC_SOCKFDWATCH_WRITE;
349  }
350 
351  isc_socket_fdwatchpoke(obj->fd, fd_flags);
352 
353  return (ISC_R_SUCCESS);
354 }
355 
357 {
358  omapi_io_object_t *obj, *ph;
359 #if SOCKDELETE
360  omapi_io_object_t *p, *last;
361 #endif
362 
363  if (!h -> outer || h -> outer -> type != omapi_type_io_object)
364  return DHCP_R_INVALIDARG;
365  obj = (omapi_io_object_t *)h -> outer;
366  ph = (omapi_io_object_t *)0;
367  omapi_io_reference (&ph, obj, MDL);
368 
369 #if SOCKDELETE
370  /*
371  * For now we leave this out. We can't clean up the isc socket
372  * structure cleanly yet so we need to leave the io object in place.
373  * By leaving it on the io states list we avoid it being freed.
374  * We also mark it as closed to avoid using it.
375  */
376 
377  /* remove from the list of I/O states */
378  last = &omapi_io_states;
379  for (p = omapi_io_states.next; p; p = p -> next) {
380  if (p == obj) {
381  omapi_io_dereference (&last -> next, MDL);
382  omapi_io_reference (&last -> next, p -> next, MDL);
383  break;
384  }
385  last = p;
386  }
387  if (obj -> next)
388  omapi_io_dereference (&obj -> next, MDL);
389 #endif
390 
391  if (obj -> outer) {
392  if (obj -> outer -> inner == (omapi_object_t *)obj)
393  omapi_object_dereference (&obj -> outer -> inner,
394  MDL);
395  omapi_object_dereference (&obj -> outer, MDL);
396  }
397  omapi_object_dereference (&obj -> inner, MDL);
398  omapi_object_dereference (&h -> outer, MDL);
399 
400 #if SOCKDELETE
401  /* remove isc socket associations */
402  if (obj->fd != NULL) {
403  isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
404  ISC_SOCKCANCEL_ALL);
405  isc_socket_detach(&obj->fd);
406  }
407 #else
408  obj->closed = ISC_TRUE;
409 #endif
410 
411  omapi_io_dereference (&ph, MDL);
412  return ISC_R_SUCCESS;
413 }
414 
415 isc_result_t omapi_dispatch (struct timeval *t)
416 {
417  return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
418  t);
419 }
420 
422  struct timeval *t)
423 {
424  isc_result_t status;
425  omapi_waiter_object_t *waiter;
426  omapi_object_t *inner;
427 
428  if (object) {
429  waiter = (omapi_waiter_object_t *)0;
430  status = omapi_waiter_allocate (&waiter, MDL);
431  if (status != ISC_R_SUCCESS)
432  return status;
433 
434  /* Paste the waiter object onto the inner object we're
435  waiting on. */
436  for (inner = object; inner -> inner; inner = inner -> inner)
437  ;
438 
439  status = omapi_object_reference (&waiter -> outer, inner, MDL);
440  if (status != ISC_R_SUCCESS) {
441  omapi_waiter_dereference (&waiter, MDL);
442  return status;
443  }
444 
445  status = omapi_object_reference (&inner -> inner,
446  (omapi_object_t *)waiter,
447  MDL);
448  if (status != ISC_R_SUCCESS) {
449  omapi_waiter_dereference (&waiter, MDL);
450  return status;
451  }
452  } else
453  waiter = (omapi_waiter_object_t *)0;
454 
455  do {
456  status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
457  if (status != ISC_R_SUCCESS)
458  return status;
459  } while (!waiter || !waiter -> ready);
460 
461  if (waiter -> outer) {
462  if (waiter -> outer -> inner) {
463  omapi_object_dereference (&waiter -> outer -> inner,
464  MDL);
465  if (waiter -> inner)
467  (&waiter -> outer -> inner,
468  waiter -> inner, MDL);
469  }
470  omapi_object_dereference (&waiter -> outer, MDL);
471  }
472  if (waiter -> inner)
473  omapi_object_dereference (&waiter -> inner, MDL);
474 
475  status = waiter -> waitstatus;
476  omapi_waiter_dereference (&waiter, MDL);
477  return status;
478 }
479 
481  struct timeval *t)
482 {
483  fd_set r, w, x, rr, ww, xx;
484  int max = 0;
485  int count;
486  int desc;
487  struct timeval now, to;
488  omapi_io_object_t *io, *prev, *next;
489  omapi_waiter_object_t *waiter;
490  omapi_object_t *tmp = (omapi_object_t *)0;
491 
492  if (!wo || wo -> type != omapi_type_waiter)
493  waiter = (omapi_waiter_object_t *)0;
494  else
495  waiter = (omapi_waiter_object_t *)wo;
496 
497  FD_ZERO (&x);
498 
499  /* First, see if the timeout has expired, and if so return. */
500  if (t) {
501  gettimeofday (&now, (struct timezone *)0);
502  cur_tv.tv_sec = now.tv_sec;
503  cur_tv.tv_usec = now.tv_usec;
504  if (now.tv_sec > t -> tv_sec ||
505  (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
506  return ISC_R_TIMEDOUT;
507 
508  /* We didn't time out, so figure out how long until
509  we do. */
510  to.tv_sec = t -> tv_sec - now.tv_sec;
511  to.tv_usec = t -> tv_usec - now.tv_usec;
512  if (to.tv_usec < 0) {
513  to.tv_usec += 1000000;
514  to.tv_sec--;
515  }
516 
517  /* It is possible for the timeout to get set larger than
518  the largest time select() is willing to accept.
519  Restricting the timeout to a maximum of one day should
520  work around this. -DPN. (Ref: Bug #416) */
521  if (to.tv_sec > (60 * 60 * 24))
522  to.tv_sec = 60 * 60 * 24;
523  }
524 
525  /* If the object we're waiting on has reached completion,
526  return now. */
527  if (waiter && waiter -> ready)
528  return ISC_R_SUCCESS;
529 
530  again:
531  /* If we have no I/O state, we can't proceed. */
532  if (!(io = omapi_io_states.next))
533  return ISC_R_NOMORE;
534 
535  /* Set up the read and write masks. */
536  FD_ZERO (&r);
537  FD_ZERO (&w);
538 
539  for (; io; io = io -> next) {
540  /* Check for a read socket. If we shouldn't be
541  trying to read for this I/O object, either there
542  won't be a readfd function, or it'll return -1. */
543  if (io -> readfd && io -> inner &&
544  (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
545  FD_SET (desc, &r);
546  if (desc > max)
547  max = desc;
548  }
549 
550  /* Same deal for write fdets. */
551  if (io -> writefd && io -> inner &&
552  (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
553  FD_SET (desc, &w);
554  if (desc > max)
555  max = desc;
556  }
557  }
558 
559  /* poll if all reader are dry */
560  now.tv_sec = 0;
561  now.tv_usec = 0;
562  rr=r;
563  ww=w;
564  xx=x;
565 
566  /* poll once */
567  count = select(max + 1, &r, &w, &x, &now);
568  if (!count) {
569  /* We are dry now */
571  /* Wait for a packet or a timeout... XXX */
572  r = rr;
573  w = ww;
574  x = xx;
575  count = select(max + 1, &r, &w, &x, t ? &to : NULL);
576  }
577 
578  /* Get the current time... */
579  gettimeofday (&cur_tv, (struct timezone *)0);
580 
581  /* We probably have a bad file descriptor. Figure out which one.
582  When we find it, call the reaper function on it, which will
583  maybe make it go away, and then try again. */
584  if (count < 0) {
585  struct timeval t0;
587  io = (omapi_io_object_t *)0;
588  if (omapi_io_states.next)
589  omapi_io_reference (&io, omapi_io_states.next, MDL);
590 
591  while (io) {
592  omapi_object_t *obj;
593  FD_ZERO (&r);
594  FD_ZERO (&w);
595  t0.tv_sec = t0.tv_usec = 0;
596 
597  if (io -> readfd && io -> inner &&
598  (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
599  FD_SET (desc, &r);
600  count = select (desc + 1, &r, &w, &x, &t0);
601  bogon:
602  if (count < 0) {
603  log_error ("Bad descriptor %d.", desc);
604  for (obj = (omapi_object_t *)io;
605  obj -> outer;
606  obj = obj -> outer)
607  ;
608  for (; obj; obj = obj -> inner) {
609  omapi_value_t *ov;
610  int len;
611  const char *s;
612  ov = (omapi_value_t *)0;
613  omapi_get_value_str (obj,
614  (omapi_object_t *)0,
615  "name", &ov);
616  if (ov && ov -> value &&
617  (ov -> value -> type ==
619  s = (char *)
620  ov -> value -> u.buffer.value;
621  len = ov -> value -> u.buffer.len;
622  } else {
623  s = "";
624  len = 0;
625  }
626  log_error ("Object %lx %s%s%.*s",
627  (unsigned long)obj,
628  obj -> type -> name,
629  len ? " " : "",
630  len, s);
631  if (len)
633  }
634  (*(io -> reaper)) (io -> inner);
635  if (prev) {
636  omapi_io_dereference (&prev -> next, MDL);
637  if (io -> next)
638  omapi_io_reference (&prev -> next,
639  io -> next, MDL);
640  } else {
641  omapi_io_dereference
642  (&omapi_io_states.next, MDL);
643  if (io -> next)
644  omapi_io_reference
645  (&omapi_io_states.next,
646  io -> next, MDL);
647  }
648  omapi_io_dereference (&io, MDL);
649  goto again;
650  }
651  }
652 
653  FD_ZERO (&r);
654  FD_ZERO (&w);
655  t0.tv_sec = t0.tv_usec = 0;
656 
657  /* Same deal for write fdets. */
658  if (io -> writefd && io -> inner &&
659  (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
660  FD_SET (desc, &w);
661  count = select (desc + 1, &r, &w, &x, &t0);
662  if (count < 0)
663  goto bogon;
664  }
665  if (prev)
666  omapi_io_dereference (&prev, MDL);
667  omapi_io_reference (&prev, io, MDL);
668  omapi_io_dereference (&io, MDL);
669  if (prev -> next)
670  omapi_io_reference (&io, prev -> next, MDL);
671  }
672  if (prev)
673  omapi_io_dereference (&prev, MDL);
674 
675  }
676 
677  for (io = omapi_io_states.next; io; io = io -> next) {
678  if (!io -> inner)
679  continue;
680  omapi_object_reference (&tmp, io -> inner, MDL);
681  /* Check for a read descriptor, and if there is one,
682  see if we got input on that socket. */
683  if (io -> readfd &&
684  (desc = (*(io -> readfd)) (tmp)) >= 0) {
685  if (FD_ISSET (desc, &r))
686  ((*(io -> reader)) (tmp));
687  }
688 
689  /* Same deal for write descriptors. */
690  if (io -> writefd &&
691  (desc = (*(io -> writefd)) (tmp)) >= 0)
692  {
693  if (FD_ISSET (desc, &w))
694  ((*(io -> writer)) (tmp));
695  }
697  }
698 
699  /* Now check for I/O handles that are no longer valid,
700  and remove them from the list. */
701  prev = NULL;
702  io = NULL;
703  if (omapi_io_states.next != NULL) {
704  omapi_io_reference(&io, omapi_io_states.next, MDL);
705  }
706  while (io != NULL) {
707  if ((io->inner == NULL) ||
708  ((io->reaper != NULL) &&
709  ((io->reaper)(io->inner) != ISC_R_SUCCESS)))
710  {
711 
712  omapi_io_object_t *tmp = NULL;
713  /* Save a reference to the next
714  pointer, if there is one. */
715  if (io->next != NULL) {
716  omapi_io_reference(&tmp, io->next, MDL);
717  omapi_io_dereference(&io->next, MDL);
718  }
719  if (prev != NULL) {
720  omapi_io_dereference(&prev->next, MDL);
721  if (tmp != NULL)
722  omapi_io_reference(&prev->next,
723  tmp, MDL);
724  } else {
725  omapi_io_dereference(&omapi_io_states.next,
726  MDL);
727  if (tmp != NULL)
728  omapi_io_reference
729  (&omapi_io_states.next,
730  tmp, MDL);
731  else
733  (omapi_object_t *)
734  &omapi_io_states,
735  "ready");
736  }
737  if (tmp != NULL)
738  omapi_io_dereference(&tmp, MDL);
739 
740  } else {
741 
742  if (prev != NULL) {
743  omapi_io_dereference(&prev, MDL);
744  }
745  omapi_io_reference(&prev, io, MDL);
746  }
747 
748  /*
749  * Equivalent to:
750  * io = io->next
751  * But using our reference counting voodoo.
752  */
753  next = NULL;
754  if (io->next != NULL) {
755  omapi_io_reference(&next, io->next, MDL);
756  }
757  omapi_io_dereference(&io, MDL);
758  if (next != NULL) {
759  omapi_io_reference(&io, next, MDL);
760  omapi_io_dereference(&next, MDL);
761  }
762  }
763  if (prev != NULL) {
764  omapi_io_dereference(&prev, MDL);
765  }
766 
767  return ISC_R_SUCCESS;
768 }
769 
771  omapi_object_t *id,
772  omapi_data_string_t *name,
773  omapi_typed_data_t *value)
774 {
775  if (h -> type != omapi_type_io_object)
776  return DHCP_R_INVALIDARG;
777 
778  if (h -> inner && h -> inner -> type -> set_value)
779  return (*(h -> inner -> type -> set_value))
780  (h -> inner, id, name, value);
781  return ISC_R_NOTFOUND;
782 }
783 
785  omapi_object_t *id,
786  omapi_data_string_t *name,
787  omapi_value_t **value)
788 {
789  if (h -> type != omapi_type_io_object)
790  return DHCP_R_INVALIDARG;
791 
792  if (h -> inner && h -> inner -> type -> get_value)
793  return (*(h -> inner -> type -> get_value))
794  (h -> inner, id, name, value);
795  return ISC_R_NOTFOUND;
796 }
797 
798 /* omapi_io_destroy (object, MDL);
799  *
800  * Find the requested IO [object] and remove it from the list of io
801  * states, causing the cleanup functions to destroy it. Note that we must
802  * hold a reference on the object while moving its ->next reference and
803  * removing the reference in the chain to the target object...otherwise it
804  * may be cleaned up from under us.
805  */
806 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
807 {
808  omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
809 
810  if (h -> type != omapi_type_io_object)
811  return DHCP_R_INVALIDARG;
812 
813  /* remove from the list of I/O states */
814  for (p = omapi_io_states.next; p; p = p -> next) {
815  if (p == (omapi_io_object_t *)h) {
816  omapi_io_reference (&obj, p, MDL);
817 
818  if (last)
819  holder = &last -> next;
820  else
821  holder = &omapi_io_states.next;
822 
823  omapi_io_dereference (holder, MDL);
824 
825  if (obj -> next) {
826  omapi_io_reference (holder, obj -> next, MDL);
827  omapi_io_dereference (&obj -> next, MDL);
828  }
829 
830  return omapi_io_dereference (&obj, MDL);
831  }
832  last = p;
833  }
834 
835  return ISC_R_NOTFOUND;
836 }
837 
839  const char *name, va_list ap)
840 {
841  if (h -> type != omapi_type_io_object)
842  return DHCP_R_INVALIDARG;
843 
844  if (h -> inner && h -> inner -> type -> signal_handler)
845  return (*(h -> inner -> type -> signal_handler)) (h -> inner,
846  name, ap);
847  return ISC_R_NOTFOUND;
848 }
849 
851  omapi_object_t *id,
852  omapi_object_t *i)
853 {
854  if (i -> type != omapi_type_io_object)
855  return DHCP_R_INVALIDARG;
856 
857  if (i -> inner && i -> inner -> type -> stuff_values)
858  return (*(i -> inner -> type -> stuff_values)) (c, id,
859  i -> inner);
860  return ISC_R_SUCCESS;
861 }
862 
864  const char *name, va_list ap)
865 {
866  omapi_waiter_object_t *waiter;
867 
868  if (h -> type != omapi_type_waiter)
869  return DHCP_R_INVALIDARG;
870 
871  if (!strcmp (name, "ready")) {
872  waiter = (omapi_waiter_object_t *)h;
873  waiter -> ready = 1;
874  waiter -> waitstatus = ISC_R_SUCCESS;
875  return ISC_R_SUCCESS;
876  }
877 
878  if (!strcmp(name, "status")) {
879  waiter = (omapi_waiter_object_t *)h;
880  waiter->ready = 1;
881  waiter->waitstatus = va_arg(ap, isc_result_t);
882  return ISC_R_SUCCESS;
883  }
884 
885  if (!strcmp (name, "disconnect")) {
886  waiter = (omapi_waiter_object_t *)h;
887  waiter -> ready = 1;
888  waiter -> waitstatus = DHCP_R_CONNRESET;
889  return ISC_R_SUCCESS;
890  }
891 
892  if (h -> inner && h -> inner -> type -> signal_handler)
893  return (*(h -> inner -> type -> signal_handler)) (h -> inner,
894  name, ap);
895  return ISC_R_NOTFOUND;
896 }
897 
905 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
906  void *),
907  void *p)
908 {
909  omapi_io_object_t *io = NULL;
910  isc_result_t status;
911  omapi_io_object_t *next = NULL;
912 
913  /*
914  * This just calls func on every inner object on the list. It would
915  * be much simpler in general case, but one of the operations could be
916  * release of the objects. Therefore we need to ref count the io and
917  * io->next pointers.
918  */
919 
920  if (omapi_io_states.next) {
922  (omapi_object_t*)omapi_io_states.next,
923  MDL);
924  }
925 
926  while(io) {
927  /* If there's a next object, save it */
928  if (io->next) {
930  (omapi_object_t*)io->next, MDL);
931  }
932  if (io->inner) {
933  status = (*func) (io->inner, p);
934  if (status != ISC_R_SUCCESS) {
935  /* Something went wrong. Let's stop using io & next pointer
936  * and bail out */
938  if (next) {
940  }
941  return status;
942  }
943  }
944  /* Update the io pointer and free the next pointer */
946  if (next) {
948  (omapi_object_t*)next,
949  MDL);
951  }
952  }
953 
954  /*
955  * The only way to get here is when next is NULL. There's no need
956  * to dereference it.
957  */
958  return ISC_R_SUCCESS;
959 }
isc_boolean_t closed
Definition: omapip_p.h:213
isc_result_t omapi_register_io_object(omapi_object_t *h, int(*readfd)(omapi_object_t *), int(*writefd)(omapi_object_t *), isc_result_t(*reader)(omapi_object_t *), isc_result_t(*writer)(omapi_object_t *), isc_result_t(*reaper)(omapi_object_t *))
Definition: dispatch.c:199
const char int line
Definition: dhcpd.h:3725
struct timeval cur_tv
Definition: dispatch.c:35
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition: alloc.c:571
int(* readfd)(omapi_object_t *)
Definition: omapip_p.h:207
#define MDL
Definition: omapip.h:568
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DHCP_R_INVALIDARG
Definition: result.h:49
omapi_typed_data_t * value
Definition: omapip.h:91
isc_result_t omapi_io_state_foreach(isc_result_t(*func)(omapi_object_t *, void *), void *p)
calls a given function on every object
Definition: dispatch.c:905
isc_result_t omapi_signal_in(omapi_object_t *, const char *,...)
Definition: support.c:286
void unregister_eventhandler(struct eventqueue **queue, void(*handler)(void *))
Definition: dispatch.c:70
int log_error(const char *,...) __attribute__((__format__(__printf__
isc_result_t(* writer)(omapi_object_t *)
Definition: omapip_p.h:210
isc_result_t(* reader)(omapi_object_t *)
Definition: omapip_p.h:209
isc_socketmgr_t * socketmgr
Definition: isclib.h:100
int(* writefd)(omapi_object_t *)
Definition: omapip_p.h:208
void log_fatal(const char *,...) __attribute__((__format__(__printf__
isc_result_t omapi_io_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value)
Definition: dispatch.c:784
struct __omapi_io_object * next
Definition: omapip_p.h:206
isc_result_t omapi_dispatch(struct timeval *t)
Definition: dispatch.c:415
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition: support.c:483
struct eventqueue * next
Definition: dhcpd.h:1433
void(* handler)(void *)
Definition: dhcpd.h:1434
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
Definition: alloc.c:593
void trigger_event(struct eventqueue **queue)
Definition: dispatch.c:91
void dfree(void *, const char *, int)
Definition: alloc.c:145
isc_result_t waitstatus
Definition: omapip_p.h:226
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
isc_socket_t * fd
Definition: omapip_p.h:212
isc_result_t omapi_unregister_io_object(omapi_object_t *h)
Definition: dispatch.c:356
isc_result_t omapi_io_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *i)
Definition: dispatch.c:850
isc_result_t omapi_wait_for_completion(omapi_object_t *object, struct timeval *t)
Definition: dispatch.c:421
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition: alloc.c:1060
isc_result_t omapi_io_set_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value)
Definition: dispatch.c:770
isc_result_t omapi_reregister_io_object(omapi_object_t *h, int(*readfd)(omapi_object_t *), int(*writefd)(omapi_object_t *), isc_result_t(*reader)(omapi_object_t *), isc_result_t(*writer)(omapi_object_t *), isc_result_t(*reaper)(omapi_object_t *))
Definition: dispatch.c:306
void register_eventhandler(struct eventqueue **, void(*handler)(void *))
isc_task_t * task
Definition: isclib.h:99
omapi_object_type_t * omapi_type_io_object
Definition: support.c:36
isc_result_t omapi_io_destroy(omapi_object_t *h, const char *file, int line)
Definition: dispatch.c:806
int omapi_iscsock_cb(isc_task_t *task, isc_socket_t *socket, void *cbarg, int flags)
Definition: dispatch.c:120
#define DHCP_R_CONNRESET
Definition: result.h:77
struct eventqueue * rw_queue_empty
Definition: dispatch.c:37
isc_result_t omapi_io_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: dispatch.c:838
isc_result_t omapi_waiter_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: dispatch.c:863
const char * file
Definition: dhcpd.h:3725
omapi_object_type_t * omapi_type_waiter
Definition: support.c:41
isc_result_t omapi_one_dispatch(omapi_object_t *wo, struct timeval *t)
Definition: dispatch.c:480
OMAPI_OBJECT_ALLOC(omapi_io, omapi_io_object_t, omapi_type_io_object)
Definition: dispatch.c:39
isc_result_t(* reaper)(omapi_object_t *)
Definition: omapip_p.h:211