ISC DHCP  4.4.3-P1
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-2022 Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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  * PO Box 360
23  * Newmarket, NH 03857 USA
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; obj != NULL; obj = obj->next) {
138  if (obj == cbarg)
139  break;
140  }
141 
142  if (obj == NULL) {
143  return(0);
144  }
145 #else
146  /* Not much to be done if we have the wrong type of object. */
147  if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) {
148  log_fatal ("Incorrect object type, must be of type io_object");
149  }
150  obj = (omapi_io_object_t *)cbarg;
151 
152  /*
153  * If the object is marked as closed don't try and process
154  * anything just indicate that we don't want any more.
155  *
156  * This should be a temporary fix until we arrange to properly
157  * close the socket.
158  */
159  if (obj->closed == ISC_TRUE) {
160  return(0);
161  }
162 #endif
163 
164  if ((flags == ISC_SOCKFDWATCH_READ) &&
165  (obj->reader != NULL) &&
166  (obj->inner != NULL)) {
167  status = obj->reader(obj->inner);
168  /*
169  * If we are shutting down (basically tried to
170  * read and got no bytes) we don't need to try
171  * again.
172  */
173  if (status == ISC_R_SHUTTINGDOWN)
174  return (0);
175  /* Otherwise We always ask for more when reading */
176  return (1);
177  } else if ((flags == ISC_SOCKFDWATCH_WRITE) &&
178  (obj->writer != NULL) &&
179  (obj->inner != NULL)) {
180  status = obj->writer(obj->inner);
181  /* If the writer has more to write they should return
182  * ISC_R_INPROGRESS */
183  if (status == ISC_R_INPROGRESS) {
184  return (1);
185  }
186  }
187 
188  /*
189  * We get here if we either had an error (inconsistent
190  * structures etc) or no more to write, tell the socket
191  * lib we don't have more to do right now.
192  */
193  return (0);
194 }
195 
196 /* Register an I/O handle so that we can do asynchronous I/O on it. */
197 
199  int (*readfd) (omapi_object_t *),
200  int (*writefd) (omapi_object_t *),
201  isc_result_t (*reader)
202  (omapi_object_t *),
203  isc_result_t (*writer)
204  (omapi_object_t *),
205  isc_result_t (*reaper)
206  (omapi_object_t *))
207 {
208  isc_result_t status;
209  omapi_io_object_t *obj, *p;
210  int fd_flags = 0, fd = 0;
211 
212  /* omapi_io_states is a static object. If its reference count
213  is zero, this is the first I/O handle to be registered, so
214  we need to initialize it. Because there is no inner or outer
215  pointer on this object, and we're setting its refcnt to 1, it
216  will never be freed. */
217  if (!omapi_io_states.refcnt) {
218  omapi_io_states.refcnt = 1;
219  omapi_io_states.type = omapi_type_io_object;
220  }
221 
222  obj = (omapi_io_object_t *)0;
223  status = omapi_io_allocate (&obj, MDL);
224  if (status != ISC_R_SUCCESS)
225  return status;
226  obj->closed = ISC_FALSE; /* mark as open */
227 
228  status = omapi_object_reference (&obj -> inner, h, MDL);
229  if (status != ISC_R_SUCCESS) {
230  omapi_io_dereference (&obj, MDL);
231  return status;
232  }
233 
234  status = omapi_object_reference (&h -> outer,
235  (omapi_object_t *)obj, MDL);
236  if (status != ISC_R_SUCCESS) {
237  omapi_io_dereference (&obj, MDL);
238  return status;
239  }
240 
241  /*
242  * Attach the I/O object to the isc socket library via the
243  * fdwatch function. This allows the socket library to watch
244  * over a socket that we built. If there are both a read and
245  * a write socket we asssume they are the same socket.
246  */
247 
248  if (readfd) {
249  fd_flags |= ISC_SOCKFDWATCH_READ;
250  fd = readfd(h);
251  }
252 
253  if (writefd) {
254  fd_flags |= ISC_SOCKFDWATCH_WRITE;
255  fd = writefd(h);
256  }
257 
258  if (fd_flags != 0) {
259  status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr,
260  fd, fd_flags,
262  obj,
264  &obj->fd);
265  if (status != ISC_R_SUCCESS) {
266  log_error("Unable to register fd with library %s",
267  isc_result_totext(status));
268 
269  /*sar*/
270  /* is this the cleanup we need? */
271  omapi_object_dereference(&h->outer, MDL);
272  omapi_io_dereference (&obj, MDL);
273  return (status);
274  }
275  }
276 
277 
278  /* Find the last I/O state, if there are any. */
279  for (p = omapi_io_states.next;
280  p && p -> next; p = p -> next)
281  ;
282  if (p)
283  omapi_io_reference (&p -> next, obj, MDL);
284  else
285  omapi_io_reference (&omapi_io_states.next, obj, MDL);
286 
287  obj -> readfd = readfd;
288  obj -> writefd = writefd;
289  obj -> reader = reader;
290  obj -> writer = writer;
291  obj -> reaper = reaper;
292 
293  omapi_io_dereference(&obj, MDL);
294  return ISC_R_SUCCESS;
295 }
296 
297 /*
298  * ReRegister an I/O handle so that we can do asynchronous I/O on it.
299  * If the handle doesn't exist we call the register routine to build it.
300  * If it does exist we change the functions associated with it, and
301  * repoke the fd code to make it happy. Neither the objects nor the
302  * fd are allowed to have changed.
303  */
304 
306  int (*readfd) (omapi_object_t *),
307  int (*writefd) (omapi_object_t *),
308  isc_result_t (*reader)
309  (omapi_object_t *),
310  isc_result_t (*writer)
311  (omapi_object_t *),
312  isc_result_t (*reaper)
313  (omapi_object_t *))
314 {
315  omapi_io_object_t *obj;
316  int fd_flags = 0;
317 
318  if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
319  /*
320  * If we don't have an object or if the type isn't what
321  * we expect do the normal registration (which will overwrite
322  * an incorrect type, that's what we did historically, may
323  * want to change that)
324  */
325  return (omapi_register_io_object (h, readfd, writefd,
326  reader, writer, reaper));
327  }
328 
329  /* We have an io object of the correct type, try to update it */
330  /*sar*/
331  /* Should we validate that the fd matches the previous one?
332  * It's suppossed to, that's a requirement, don't bother yet */
333 
334  obj = (omapi_io_object_t *)h->outer;
335 
336  obj->readfd = readfd;
337  obj->writefd = writefd;
338  obj->reader = reader;
339  obj->writer = writer;
340  obj->reaper = reaper;
341 
342  if (readfd) {
343  fd_flags |= ISC_SOCKFDWATCH_READ;
344  }
345 
346  if (writefd) {
347  fd_flags |= ISC_SOCKFDWATCH_WRITE;
348  }
349 
350  isc_socket_fdwatchpoke(obj->fd, fd_flags);
351 
352  return (ISC_R_SUCCESS);
353 }
354 
356 {
357  omapi_io_object_t *obj, *ph;
358 #if SOCKDELETE
359  omapi_io_object_t *p, *last;
360 #endif
361 
362  if (!h -> outer || h -> outer -> type != omapi_type_io_object)
363  return DHCP_R_INVALIDARG;
364  obj = (omapi_io_object_t *)h -> outer;
365  ph = (omapi_io_object_t *)0;
366  omapi_io_reference (&ph, obj, MDL);
367 
368 #if SOCKDELETE
369  /*
370  * For now we leave this out. We can't clean up the isc socket
371  * structure cleanly yet so we need to leave the io object in place.
372  * By leaving it on the io states list we avoid it being freed.
373  * We also mark it as closed to avoid using it.
374  */
375 
376  /* remove from the list of I/O states */
377  last = &omapi_io_states;
378  for (p = omapi_io_states.next; p; p = p -> next) {
379  if (p == obj) {
380  omapi_io_dereference (&last -> next, MDL);
381  omapi_io_reference (&last -> next, p -> next, MDL);
382  break;
383  }
384  last = p;
385  }
386  if (obj -> next)
387  omapi_io_dereference (&obj -> next, MDL);
388 #endif
389 
390  if (obj -> outer) {
391  if (obj -> outer -> inner == (omapi_object_t *)obj)
392  omapi_object_dereference (&obj -> outer -> inner,
393  MDL);
394  omapi_object_dereference (&obj -> outer, MDL);
395  }
396  omapi_object_dereference (&obj -> inner, MDL);
397  omapi_object_dereference (&h -> outer, MDL);
398 
399 #if SOCKDELETE
400  /* remove isc socket associations */
401  if (obj->fd != NULL) {
402  isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
403  ISC_SOCKCANCEL_ALL);
404  isc_socket_detach(&obj->fd);
405  }
406 #else
407  obj->closed = ISC_TRUE;
408 #endif
409 
410  omapi_io_dereference (&ph, MDL);
411  return ISC_R_SUCCESS;
412 }
413 
414 isc_result_t omapi_dispatch (struct timeval *t)
415 {
416 #ifdef DEBUG_PROTOCOL
417  log_debug("omapi_dispatch()");
418 #endif
419  return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
420 
421  t);
422 }
423 
425  struct timeval *t)
426 {
427 #ifdef DEBUG_PROTOCOL
428  if (t) {
429  log_debug ("omapi_wait_for_completion(%u.%u secs)",
430  (unsigned int)(t->tv_sec),
431  (unsigned int)(t->tv_usec));
432  } else {
433  log_debug ("omapi_wait_for_completion(no timeout)");
434  }
435 #endif
436  isc_result_t status;
437  omapi_waiter_object_t *waiter;
438  omapi_object_t *inner;
439 
440  if (object) {
441  waiter = (omapi_waiter_object_t *)0;
442  status = omapi_waiter_allocate (&waiter, MDL);
443  if (status != ISC_R_SUCCESS)
444  return status;
445 
446  /* Paste the waiter object onto the inner object we're
447  waiting on. */
448  for (inner = object; inner -> inner; inner = inner -> inner)
449  ;
450 
451  status = omapi_object_reference (&waiter -> outer, inner, MDL);
452  if (status != ISC_R_SUCCESS) {
453  omapi_waiter_dereference (&waiter, MDL);
454  return status;
455  }
456 
457  status = omapi_object_reference (&inner -> inner,
458  (omapi_object_t *)waiter,
459  MDL);
460  if (status != ISC_R_SUCCESS) {
461  omapi_waiter_dereference (&waiter, MDL);
462  return status;
463  }
464  } else
465  waiter = (omapi_waiter_object_t *)0;
466 
467  do {
468  status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
469  if (status != ISC_R_SUCCESS) {
470 #ifdef DEBUG_PROTOCOL
471  log_debug ("- call to omapi_one_dispatch failed: %s",
472  isc_result_totext (status));
473 #endif
474  /* Break out on failure, to ensure we free up the waiter(s) */
475  break;
476  }
477  } while (!waiter || !waiter -> ready);
478 
479 
480  if (waiter -> outer) {
481  if (waiter -> outer -> inner) {
482  omapi_object_dereference (&waiter -> outer -> inner,
483  MDL);
484  if (waiter -> inner)
486  (&waiter -> outer -> inner,
487  waiter -> inner, MDL);
488  }
489  omapi_object_dereference (&waiter -> outer, MDL);
490  }
491  if (waiter -> inner)
492  omapi_object_dereference (&waiter -> inner, MDL);
493 
494  if (status == ISC_R_SUCCESS) {
495  /* If the invocation worked, return the server's
496  * execution status */
497  status = waiter -> waitstatus;
498  }
499 
500  omapi_waiter_dereference (&waiter, MDL);
501  return status;
502 }
503 
505  struct timeval *t)
506 {
507 #ifdef DEBUG_PROTOCOL
508  log_debug ("omapi_one_dispatch()");
509 #endif
510  fd_set r, w, x, rr, ww, xx;
511  int max = 0;
512  int count;
513  int desc;
514  struct timeval now, to;
515  omapi_io_object_t *io, *prev, *next;
516  omapi_waiter_object_t *waiter;
517  omapi_object_t *tmp = (omapi_object_t *)0;
518 
519  if (!wo || wo -> type != omapi_type_waiter)
520  waiter = (omapi_waiter_object_t *)0;
521  else
522  waiter = (omapi_waiter_object_t *)wo;
523 
524  FD_ZERO (&x);
525 
526  /* First, see if the timeout has expired, and if so return. */
527  if (t) {
528  gettimeofday (&now, (struct timezone *)0);
529  cur_tv.tv_sec = now.tv_sec;
530  cur_tv.tv_usec = now.tv_usec;
531  if (now.tv_sec > t -> tv_sec ||
532  (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
533  return ISC_R_TIMEDOUT;
534 
535  /* We didn't time out, so figure out how long until
536  we do. */
537  to.tv_sec = t -> tv_sec - now.tv_sec;
538  to.tv_usec = t -> tv_usec - now.tv_usec;
539  if (to.tv_usec < 0) {
540  to.tv_usec += 1000000;
541  to.tv_sec--;
542  }
543 
544  /* It is possible for the timeout to get set larger than
545  the largest time select() is willing to accept.
546  Restricting the timeout to a maximum of one day should
547  work around this. -DPN. (Ref: Bug #416) */
548  if (to.tv_sec > (60 * 60 * 24))
549  to.tv_sec = 60 * 60 * 24;
550  }
551 
552  /* If the object we're waiting on has reached completion,
553  return now. */
554  if (waiter && waiter -> ready)
555  return ISC_R_SUCCESS;
556 
557  again:
558  /* If we have no I/O state, we can't proceed. */
559  if (!(io = omapi_io_states.next))
560  return ISC_R_NOMORE;
561 
562  /* Set up the read and write masks. */
563  FD_ZERO (&r);
564  FD_ZERO (&w);
565 
566  for (; io; io = io -> next) {
567  /* Check for a read socket. If we shouldn't be
568  trying to read for this I/O object, either there
569  won't be a readfd function, or it'll return -1. */
570  if (io -> readfd && io -> inner &&
571  (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
572  FD_SET (desc, &r);
573  if (desc > max)
574  max = desc;
575  }
576 
577  /* Same deal for write fdets. */
578  if (io -> writefd && io -> inner &&
579  (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
580  /* This block avoids adding writefds that are already connected
581  * but that do not have data waiting to write. This avoids
582  * select() calls dropping immediately simply because the
583  * the writefd is ready to write. Without this synchronous
584  * waiting becomes CPU intensive polling */
585  if (io->inner && io->inner->type == omapi_type_connection) {
587  c = (omapi_connection_object_t *)(io->inner);
588  if (c->state == omapi_connection_connected && c->out_bytes == 0) {
589  /* We are already connected and have no data waiting to
590  * be written, so we avoid registering the fd. */
591 #ifdef DEBUG_PROTOCOL
592  log_debug ("--- Connected, nothing to write, skip writefd\n");
593 #endif
594  continue;
595  }
596  }
597 
598 
599  FD_SET (desc, &w);
600  if (desc > max)
601  max = desc;
602  }
603  }
604 
605  /* poll if all reader are dry */
606  now.tv_sec = 0;
607  now.tv_usec = 0;
608  rr=r;
609  ww=w;
610  xx=x;
611 
612  /* poll once */
613  count = select(max + 1, &r, &w, &x, &now);
614  if (!count) {
615  /* We are dry now */
617  /* Wait for a packet or a timeout... XXX */
618  r = rr;
619  w = ww;
620  x = xx;
621 
622 #ifdef DEBUG_PROTOCOL
623  if (t) {
624  log_debug (" calling select with timout: %u.%u secs",
625  (unsigned int)(to.tv_sec),
626  (unsigned int)(to.tv_usec));
627  }
628 #endif
629  count = select(max + 1, &r, &w, &x, t ? &to : NULL);
630  }
631 
632  /* Get the current time... */
633  gettimeofday (&cur_tv, (struct timezone *)0);
634 
635  /* We probably have a bad file descriptor. Figure out which one.
636  When we find it, call the reaper function on it, which will
637  maybe make it go away, and then try again. */
638  if (count < 0) {
639  struct timeval t0;
641  io = (omapi_io_object_t *)0;
642  if (omapi_io_states.next)
643  omapi_io_reference (&io, omapi_io_states.next, MDL);
644 
645  while (io) {
646  omapi_object_t *obj;
647  FD_ZERO (&r);
648  FD_ZERO (&w);
649  t0.tv_sec = t0.tv_usec = 0;
650 
651  if (io -> readfd && io -> inner &&
652  (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
653  FD_SET (desc, &r);
654  count = select (desc + 1, &r, &w, &x, &t0);
655  bogon:
656  if (count < 0) {
657  log_error ("Bad descriptor %d.", desc);
658  for (obj = (omapi_object_t *)io;
659  obj -> outer;
660  obj = obj -> outer)
661  ;
662  for (; obj; obj = obj -> inner) {
663  omapi_value_t *ov;
664  int len;
665  const char *s;
666  ov = (omapi_value_t *)0;
667  omapi_get_value_str (obj,
668  (omapi_object_t *)0,
669  "name", &ov);
670  if (ov && ov -> value &&
671  (ov -> value -> type ==
673  s = (char *)
674  ov -> value -> u.buffer.value;
675  len = ov -> value -> u.buffer.len;
676  } else {
677  s = "";
678  len = 0;
679  }
680  log_error ("Object %lx %s%s%.*s",
681  (unsigned long)obj,
682  obj -> type -> name,
683  len ? " " : "",
684  len, s);
685  if (len)
687  }
688  (*(io -> reaper)) (io -> inner);
689  if (prev) {
690  omapi_io_dereference (&prev -> next, MDL);
691  if (io -> next)
692  omapi_io_reference (&prev -> next,
693  io -> next, MDL);
694  } else {
695  omapi_io_dereference
696  (&omapi_io_states.next, MDL);
697  if (io -> next)
698  omapi_io_reference
699  (&omapi_io_states.next,
700  io -> next, MDL);
701  }
702  omapi_io_dereference (&io, MDL);
703  goto again;
704  }
705  }
706 
707  FD_ZERO (&r);
708  FD_ZERO (&w);
709  t0.tv_sec = t0.tv_usec = 0;
710 
711  /* Same deal for write fdets. */
712  if (io -> writefd && io -> inner &&
713  (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
714  FD_SET (desc, &w);
715  count = select (desc + 1, &r, &w, &x, &t0);
716  if (count < 0)
717  goto bogon;
718  }
719  if (prev)
720  omapi_io_dereference (&prev, MDL);
721  omapi_io_reference (&prev, io, MDL);
722  omapi_io_dereference (&io, MDL);
723  if (prev -> next)
724  omapi_io_reference (&io, prev -> next, MDL);
725  }
726  if (prev)
727  omapi_io_dereference (&prev, MDL);
728 
729  }
730 
731  for (io = omapi_io_states.next; io; io = io -> next) {
732  if (!io -> inner)
733  continue;
734  omapi_object_reference (&tmp, io -> inner, MDL);
735  /* Check for a read descriptor, and if there is one,
736  see if we got input on that socket. */
737  if (io -> readfd &&
738  (desc = (*(io -> readfd)) (tmp)) >= 0) {
739  if (FD_ISSET (desc, &r)) {
740  ((*(io -> reader)) (tmp));
741  }
742  }
743 
744  /* Same deal for write descriptors. */
745  if (io -> writefd &&
746  (desc = (*(io -> writefd)) (tmp)) >= 0)
747  {
748  if (FD_ISSET (desc, &w)) {
749  ((*(io -> writer)) (tmp));
750  }
751  }
753  }
754 
755  /* Now check for I/O handles that are no longer valid,
756  and remove them from the list. */
757  prev = NULL;
758  io = NULL;
759  if (omapi_io_states.next != NULL) {
760  omapi_io_reference(&io, omapi_io_states.next, MDL);
761  }
762  while (io != NULL) {
763  if ((io->inner == NULL) ||
764  ((io->reaper != NULL) &&
765  ((io->reaper)(io->inner) != ISC_R_SUCCESS)))
766  {
767 
768  omapi_io_object_t *tmp = NULL;
769  /* Save a reference to the next
770  pointer, if there is one. */
771  if (io->next != NULL) {
772  omapi_io_reference(&tmp, io->next, MDL);
773  omapi_io_dereference(&io->next, MDL);
774  }
775  if (prev != NULL) {
776  omapi_io_dereference(&prev->next, MDL);
777  if (tmp != NULL)
778  omapi_io_reference(&prev->next,
779  tmp, MDL);
780  } else {
781  omapi_io_dereference(&omapi_io_states.next,
782  MDL);
783  if (tmp != NULL)
784  omapi_io_reference
785  (&omapi_io_states.next,
786  tmp, MDL);
787  else
789  (omapi_object_t *)
790  &omapi_io_states,
791  "ready");
792  }
793  if (tmp != NULL)
794  omapi_io_dereference(&tmp, MDL);
795 
796  } else {
797 
798  if (prev != NULL) {
799  omapi_io_dereference(&prev, MDL);
800  }
801  omapi_io_reference(&prev, io, MDL);
802  }
803 
804  /*
805  * Equivalent to:
806  * io = io->next
807  * But using our reference counting voodoo.
808  */
809  next = NULL;
810  if (io->next != NULL) {
811  omapi_io_reference(&next, io->next, MDL);
812  }
813  omapi_io_dereference(&io, MDL);
814  if (next != NULL) {
815  omapi_io_reference(&io, next, MDL);
816  omapi_io_dereference(&next, MDL);
817  }
818  }
819  if (prev != NULL) {
820  omapi_io_dereference(&prev, MDL);
821  }
822 
823  return ISC_R_SUCCESS;
824 }
825 
827  omapi_object_t *id,
828  omapi_data_string_t *name,
830 {
831  if (h -> type != omapi_type_io_object)
832  return DHCP_R_INVALIDARG;
833 
834  if (h -> inner && h -> inner -> type -> set_value)
835  return (*(h -> inner -> type -> set_value))
836  (h -> inner, id, name, value);
837  return ISC_R_NOTFOUND;
838 }
839 
841  omapi_object_t *id,
842  omapi_data_string_t *name,
844 {
845  if (h -> type != omapi_type_io_object)
846  return DHCP_R_INVALIDARG;
847 
848  if (h -> inner && h -> inner -> type -> get_value)
849  return (*(h -> inner -> type -> get_value))
850  (h -> inner, id, name, value);
851  return ISC_R_NOTFOUND;
852 }
853 
854 /* omapi_io_destroy (object, MDL);
855  *
856  * Find the requested IO [object] and remove it from the list of io
857  * states, causing the cleanup functions to destroy it. Note that we must
858  * hold a reference on the object while moving its ->next reference and
859  * removing the reference in the chain to the target object...otherwise it
860  * may be cleaned up from under us.
861  */
862 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
863 {
864  omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
865 
866  if (h -> type != omapi_type_io_object)
867  return DHCP_R_INVALIDARG;
868 
869  /* remove from the list of I/O states */
870  for (p = omapi_io_states.next; p; p = p -> next) {
871  if (p == (omapi_io_object_t *)h) {
872  omapi_io_reference (&obj, p, MDL);
873 
874  if (last)
875  holder = &last -> next;
876  else
877  holder = &omapi_io_states.next;
878 
879  omapi_io_dereference (holder, MDL);
880 
881  if (obj -> next) {
882  omapi_io_reference (holder, obj -> next, MDL);
883  omapi_io_dereference (&obj -> next, MDL);
884  }
885 
886  return omapi_io_dereference (&obj, MDL);
887  }
888  last = p;
889  }
890 
891  return ISC_R_NOTFOUND;
892 }
893 
895  const char *name, va_list ap)
896 {
897 #ifdef DEBUG_PROTOCOL
898  log_debug ("omapi_io_signal_handler(%s)", name);
899 #endif
900  if (h -> type != omapi_type_io_object)
901  return DHCP_R_INVALIDARG;
902 
903  if (h -> inner && h -> inner -> type -> signal_handler)
904  return (*(h -> inner -> type -> signal_handler)) (h -> inner,
905  name, ap);
906  return ISC_R_NOTFOUND;
907 }
908 
910  omapi_object_t *id,
911  omapi_object_t *i)
912 {
913  if (i -> type != omapi_type_io_object)
914  return DHCP_R_INVALIDARG;
915 
916  if (i -> inner && i -> inner -> type -> stuff_values)
917  return (*(i -> inner -> type -> stuff_values)) (c, id,
918  i -> inner);
919  return ISC_R_SUCCESS;
920 }
921 
923  const char *name, va_list ap)
924 {
925  omapi_waiter_object_t *waiter;
926 
927 #ifdef DEBUG_PROTOCOL
928  log_debug ("omapi_waiter_signal_handler(%s)", name);
929 #endif
930  if (h -> type != omapi_type_waiter)
931  return DHCP_R_INVALIDARG;
932 
933  if (!strcmp (name, "ready")) {
934  waiter = (omapi_waiter_object_t *)h;
935  waiter -> ready = 1;
936  waiter -> waitstatus = ISC_R_SUCCESS;
937  return ISC_R_SUCCESS;
938  }
939 
940  if (!strcmp(name, "status")) {
941  waiter = (omapi_waiter_object_t *)h;
942  waiter->ready = 1;
943  waiter->waitstatus = va_arg(ap, isc_result_t);
944  return ISC_R_SUCCESS;
945  }
946 
947  if (!strcmp (name, "disconnect")) {
948  waiter = (omapi_waiter_object_t *)h;
949  waiter -> ready = 1;
950  waiter -> waitstatus = DHCP_R_CONNRESET;
951  return ISC_R_SUCCESS;
952  }
953 
954  if (h -> inner && h -> inner -> type -> signal_handler)
955  return (*(h -> inner -> type -> signal_handler)) (h -> inner,
956  name, ap);
957  return ISC_R_NOTFOUND;
958 }
959 
967 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
968  void *),
969  void *p)
970 {
971  omapi_io_object_t *io = NULL;
972  isc_result_t status;
973  omapi_io_object_t *next = NULL;
974 
975  /*
976  * This just calls func on every inner object on the list. It would
977  * be much simpler in general case, but one of the operations could be
978  * release of the objects. Therefore we need to ref count the io and
979  * io->next pointers.
980  */
981 
982  if (omapi_io_states.next) {
984  (omapi_object_t*)omapi_io_states.next,
985  MDL);
986  }
987 
988  while(io) {
989  /* If there's a next object, save it */
990  if (io->next) {
992  (omapi_object_t*)io->next, MDL);
993  }
994  if (io->inner) {
995  status = (*func) (io->inner, p);
996  if (status != ISC_R_SUCCESS) {
997  /* Something went wrong. Let's stop using io & next pointer
998  * and bail out */
1000  if (next) {
1002  }
1003  return status;
1004  }
1005  }
1006  /* Update the io pointer and free the next pointer */
1008  if (next) {
1010  (omapi_object_t*)next,
1011  MDL);
1013  }
1014  }
1015 
1016  /*
1017  * The only way to get here is when next is NULL. There's no need
1018  * to dereference it.
1019  */
1020  return ISC_R_SUCCESS;
1021 }
isc_boolean_t closed
Definition: omapip_p.h:214
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:198
const char int line
Definition: dhcpd.h:3802
Definition: data.h:205
omapi_object_type_t * omapi_type_connection
Definition: support.c:33
#define ISC_FALSE
Definition: data.h:152
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:208
#define MDL
Definition: omapip.h:567
omapi_connection_state_t state
Definition: omapip_p.h:184
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DHCP_R_INVALIDARG
Definition: result.h:49
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
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:967
isc_result_t omapi_signal_in(omapi_object_t *, const char *,...)
Definition: support.c:285
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:211
isc_result_t(* reader)(omapi_object_t *)
Definition: omapip_p.h:210
isc_socketmgr_t * socketmgr
Definition: isclib.h:101
int(* writefd)(omapi_object_t *)
Definition: omapip_p.h:209
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:840
#define ISC_TRUE
Definition: data.h:153
struct __omapi_io_object * next
Definition: omapip_p.h:207
isc_result_t omapi_dispatch(struct timeval *t)
Definition: dispatch.c:414
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition: support.c:482
struct eventqueue * next
Definition: dhcpd.h:1466
void(* handler)(void *)
Definition: dhcpd.h:1467
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:227
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
isc_socket_t * fd
Definition: omapip_p.h:213
isc_result_t omapi_unregister_io_object(omapi_object_t *h)
Definition: dispatch.c:355
#define ISC_R_SUCCESS
isc_result_t omapi_io_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *i)
Definition: dispatch.c:909
isc_result_t omapi_wait_for_completion(omapi_object_t *object, struct timeval *t)
Definition: dispatch.c:424
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:826
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:305
void register_eventhandler(struct eventqueue **, void(*handler)(void *))
isc_task_t * task
Definition: isclib.h:100
omapi_object_type_t * omapi_type_io_object
Definition: support.c:35
isc_result_t omapi_io_destroy(omapi_object_t *h, const char *file, int line)
Definition: dispatch.c:862
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:894
isc_result_t omapi_waiter_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: dispatch.c:922
const char * file
Definition: dhcpd.h:3802
omapi_object_type_t * omapi_type_waiter
Definition: support.c:40
isc_result_t omapi_one_dispatch(omapi_object_t *wo, struct timeval *t)
Definition: dispatch.c:504
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:212