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