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