]> git.ipfire.org Git - thirdparty/dhcp.git/blob - omapip/dispatch.c
[master] Addes addtional HMAC TSIG algorithms to DDNS
[thirdparty/dhcp.git] / omapip / dispatch.c
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
37 struct eventqueue *rw_queue_empty;
38
39 OMAPI_OBJECT_ALLOC (omapi_io,
40 omapi_io_object_t, omapi_type_io_object)
41 OMAPI_OBJECT_ALLOC (omapi_waiter,
42 omapi_waiter_object_t, omapi_type_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
199 isc_result_t omapi_register_io_object (omapi_object_t *h,
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,
262 omapi_iscsock_cb,
263 obj,
264 dhcp_gbl_ctx.task,
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
306 isc_result_t omapi_reregister_io_object (omapi_object_t *h,
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
356 isc_result_t omapi_unregister_io_object (omapi_object_t *h)
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
421 isc_result_t omapi_wait_for_completion (omapi_object_t *object,
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)
466 omapi_object_reference
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
480 isc_result_t omapi_one_dispatch (omapi_object_t *wo,
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 */
570 trigger_event(&rw_queue_empty);
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;
586 omapi_io_object_t *prev = (omapi_io_object_t *)0;
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 ==
618 omapi_datatype_string)) {
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)
632 omapi_value_dereference (&ov, MDL);
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 }
696 omapi_object_dereference (&tmp, MDL);
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
732 omapi_signal_in(
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
770 isc_result_t omapi_io_set_value (omapi_object_t *h,
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
784 isc_result_t omapi_io_get_value (omapi_object_t *h,
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
838 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
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
850 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
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
863 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
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
898 /** @brief calls a given function on every object
899 *
900 * @param func function to be called
901 * @param p parameter to be passed to each function instance
902 *
903 * @return result (ISC_R_SUCCESS if successful, error code otherwise)
904 */
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) {
921 omapi_object_reference((omapi_object_t**)&io,
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) {
929 omapi_object_reference((omapi_object_t**)&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 */
937 omapi_object_dereference((omapi_object_t**)&io, MDL);
938 if (next) {
939 omapi_object_dereference((omapi_object_t**)&next, MDL);
940 }
941 return status;
942 }
943 }
944 /* Update the io pointer and free the next pointer */
945 omapi_object_dereference((omapi_object_t**)&io, MDL);
946 if (next) {
947 omapi_object_reference((omapi_object_t**)&io,
948 (omapi_object_t*)next,
949 MDL);
950 omapi_object_dereference((omapi_object_t**)&next, 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 }