]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/dispatch.c
Added new files from libtool build to gitignore
[thirdparty/dhcp.git] / omapip / dispatch.c
CommitLineData
61b844bf
TL
1/* dispatch.c
2
3 I/O dispatcher. */
4
5/*
edad9be5 6 * Copyright (c) 2004,2007-2009,2013-2014 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1999-2003 by Internet Software Consortium
61b844bf 8 *
98311e4b
DH
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.
61b844bf 12 *
98311e4b
DH
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.
61b844bf 20 *
98311e4b
DH
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
2c85ac9b 25 * https://www.isc.org/
49733f31 26 *
61b844bf
TL
27 */
28
fe5b0fdd
DH
29#include "dhcpd.h"
30
6a4c4be8 31#include <omapip/omapip_p.h>
28868515 32#include <sys/time.h>
61b844bf
TL
33
34static omapi_io_object_t omapi_io_states;
be62cf06 35struct timeval cur_tv;
61b844bf 36
6368a1bd
DH
37struct eventqueue *rw_queue_empty;
38
20916cae
TL
39OMAPI_OBJECT_ALLOC (omapi_io,
40 omapi_io_object_t, omapi_type_io_object)
41OMAPI_OBJECT_ALLOC (omapi_waiter,
42 omapi_waiter_object_t, omapi_type_waiter)
43
6368a1bd
DH
44void
45register_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
69void
70unregister_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
90void
91trigger_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
98bf1607
SR
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 */
8fa0112d
SR
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
98bf1607
SR
119int
120omapi_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
8fa0112d
SR
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 */
9564b4f0 137 for (obj = omapi_io_states.next; obj != NULL; obj = obj->next) {
8fa0112d
SR
138 if (obj == cbarg)
139 break;
140 }
9564b4f0 141
8fa0112d
SR
142 if (obj == NULL) {
143 return(0);
144 }
145#else
98bf1607
SR
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
8fa0112d
SR
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
98bf1607
SR
164 if ((flags == ISC_SOCKFDWATCH_READ) &&
165 (obj->reader != NULL) &&
166 (obj->inner != NULL)) {
1e2a127b
SR
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 */
98bf1607
SR
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}
6368a1bd 195
61b844bf
TL
196/* Register an I/O handle so that we can do asynchronous I/O on it. */
197
198isc_result_t omapi_register_io_object (omapi_object_t *h,
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;
98bf1607 210 int fd_flags = 0, fd = 0;
61b844bf
TL
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
20916cae
TL
222 obj = (omapi_io_object_t *)0;
223 status = omapi_io_allocate (&obj, MDL);
224 if (status != ISC_R_SUCCESS)
225 return status;
8fa0112d 226 obj->closed = ISC_FALSE; /* mark as open */
61b844bf 227
4bd8800e 228 status = omapi_object_reference (&obj -> inner, h, MDL);
61b844bf 229 if (status != ISC_R_SUCCESS) {
20916cae 230 omapi_io_dereference (&obj, MDL);
61b844bf
TL
231 return status;
232 }
233
4bd8800e
TL
234 status = omapi_object_reference (&h -> outer,
235 (omapi_object_t *)obj, MDL);
61b844bf 236 if (status != ISC_R_SUCCESS) {
20916cae 237 omapi_io_dereference (&obj, MDL);
61b844bf
TL
238 return status;
239 }
240
98bf1607
SR
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,
261 omapi_iscsock_cb,
262 obj,
263 dhcp_gbl_ctx.task,
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
61b844bf
TL
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)
20916cae 283 omapi_io_reference (&p -> next, obj, MDL);
61b844bf 284 else
20916cae 285 omapi_io_reference (&omapi_io_states.next, obj, MDL);
61b844bf
TL
286
287 obj -> readfd = readfd;
288 obj -> writefd = writefd;
289 obj -> reader = reader;
290 obj -> writer = writer;
291 obj -> reaper = reaper;
4619c0a2
DH
292
293 omapi_io_dereference(&obj, MDL);
61b844bf
TL
294 return ISC_R_SUCCESS;
295}
296
8fa0112d
SR
297/*
298 * ReRegister an I/O handle so that we can do asynchronous I/O on it.
0493fdca 299 * If the handle doesn't exist we call the register routine to build it.
8fa0112d 300 * If it does exist we change the functions associated with it, and
0493fdca 301 * repoke the fd code to make it happy. Neither the objects nor the
8fa0112d
SR
302 * fd are allowed to have changed.
303 */
0493fdca
SR
304
305isc_result_t omapi_reregister_io_object (omapi_object_t *h,
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;
8fa0112d 316 int fd_flags = 0;
0493fdca
SR
317
318 if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
8fa0112d
SR
319 /*
320 * If we don't have an object or if the type isn't what
0493fdca
SR
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
8fa0112d
SR
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);
0493fdca
SR
351
352 return (ISC_R_SUCCESS);
353}
354
b6237fb2
TL
355isc_result_t omapi_unregister_io_object (omapi_object_t *h)
356{
8fa0112d
SR
357 omapi_io_object_t *obj, *ph;
358#if SOCKDELETE
359 omapi_io_object_t *p, *last;
360#endif
b6237fb2 361
20916cae 362 if (!h -> outer || h -> outer -> type != omapi_type_io_object)
98bf1607 363 return DHCP_R_INVALIDARG;
b6237fb2 364 obj = (omapi_io_object_t *)h -> outer;
20916cae
TL
365 ph = (omapi_io_object_t *)0;
366 omapi_io_reference (&ph, obj, MDL);
b6237fb2 367
8fa0112d
SR
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
b6237fb2 376 /* remove from the list of I/O states */
c3064fe0 377 last = &omapi_io_states;
b6237fb2 378 for (p = omapi_io_states.next; p; p = p -> next) {
20916cae
TL
379 if (p == obj) {
380 omapi_io_dereference (&last -> next, MDL);
381 omapi_io_reference (&last -> next, p -> next, MDL);
b6237fb2
TL
382 break;
383 }
384 last = p;
385 }
386 if (obj -> next)
20916cae 387 omapi_io_dereference (&obj -> next, MDL);
8fa0112d 388#endif
20916cae 389
b6237fb2
TL
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);
98bf1607 398
8fa0112d 399#if SOCKDELETE
98bf1607
SR
400 /* remove isc socket associations */
401 if (obj->fd != NULL) {
8fa0112d
SR
402 isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
403 ISC_SOCKCANCEL_ALL);
98bf1607
SR
404 isc_socket_detach(&obj->fd);
405 }
8fa0112d
SR
406#else
407 obj->closed = ISC_TRUE;
408#endif
98bf1607 409
20916cae 410 omapi_io_dereference (&ph, MDL);
b6237fb2
TL
411 return ISC_R_SUCCESS;
412}
413
61b844bf
TL
414isc_result_t omapi_dispatch (struct timeval *t)
415{
416 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
417 t);
418}
419
420isc_result_t omapi_wait_for_completion (omapi_object_t *object,
421 struct timeval *t)
422{
423 isc_result_t status;
424 omapi_waiter_object_t *waiter;
425 omapi_object_t *inner;
426
427 if (object) {
20916cae
TL
428 waiter = (omapi_waiter_object_t *)0;
429 status = omapi_waiter_allocate (&waiter, MDL);
430 if (status != ISC_R_SUCCESS)
431 return status;
61b844bf
TL
432
433 /* Paste the waiter object onto the inner object we're
434 waiting on. */
435 for (inner = object; inner -> inner; inner = inner -> inner)
436 ;
437
4bd8800e 438 status = omapi_object_reference (&waiter -> outer, inner, MDL);
61b844bf 439 if (status != ISC_R_SUCCESS) {
20916cae 440 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
441 return status;
442 }
443
444 status = omapi_object_reference (&inner -> inner,
445 (omapi_object_t *)waiter,
4bd8800e 446 MDL);
61b844bf 447 if (status != ISC_R_SUCCESS) {
20916cae 448 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
449 return status;
450 }
451 } else
452 waiter = (omapi_waiter_object_t *)0;
453
454 do {
6a4c4be8 455 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
61b844bf
TL
456 if (status != ISC_R_SUCCESS)
457 return status;
458 } while (!waiter || !waiter -> ready);
459
727ebc3a
TL
460 if (waiter -> outer) {
461 if (waiter -> outer -> inner) {
462 omapi_object_dereference (&waiter -> outer -> inner,
4bd8800e 463 MDL);
727ebc3a
TL
464 if (waiter -> inner)
465 omapi_object_reference
466 (&waiter -> outer -> inner,
4bd8800e 467 waiter -> inner, MDL);
727ebc3a 468 }
4bd8800e 469 omapi_object_dereference (&waiter -> outer, MDL);
727ebc3a
TL
470 }
471 if (waiter -> inner)
4bd8800e 472 omapi_object_dereference (&waiter -> inner, MDL);
727ebc3a 473
49146f3c 474 status = waiter -> waitstatus;
20916cae 475 omapi_waiter_dereference (&waiter, MDL);
86a9cf83 476 return status;
61b844bf
TL
477}
478
6a4c4be8 479isc_result_t omapi_one_dispatch (omapi_object_t *wo,
61b844bf
TL
480 struct timeval *t)
481{
6368a1bd 482 fd_set r, w, x, rr, ww, xx;
61b844bf
TL
483 int max = 0;
484 int count;
485 int desc;
486 struct timeval now, to;
4619c0a2 487 omapi_io_object_t *io, *prev, *next;
6a4c4be8 488 omapi_waiter_object_t *waiter;
b6237fb2 489 omapi_object_t *tmp = (omapi_object_t *)0;
6a4c4be8
TL
490
491 if (!wo || wo -> type != omapi_type_waiter)
492 waiter = (omapi_waiter_object_t *)0;
493 else
494 waiter = (omapi_waiter_object_t *)wo;
61b844bf
TL
495
496 FD_ZERO (&x);
497
498 /* First, see if the timeout has expired, and if so return. */
499 if (t) {
500 gettimeofday (&now, (struct timezone *)0);
be62cf06
FD
501 cur_tv.tv_sec = now.tv_sec;
502 cur_tv.tv_usec = now.tv_usec;
61b844bf
TL
503 if (now.tv_sec > t -> tv_sec ||
504 (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
505 return ISC_R_TIMEDOUT;
506
507 /* We didn't time out, so figure out how long until
508 we do. */
509 to.tv_sec = t -> tv_sec - now.tv_sec;
510 to.tv_usec = t -> tv_usec - now.tv_usec;
511 if (to.tv_usec < 0) {
512 to.tv_usec += 1000000;
513 to.tv_sec--;
514 }
d01dde76
DN
515
516 /* It is possible for the timeout to get set larger than
517 the largest time select() is willing to accept.
518 Restricting the timeout to a maximum of one day should
519 work around this. -DPN. (Ref: Bug #416) */
520 if (to.tv_sec > (60 * 60 * 24))
521 to.tv_sec = 60 * 60 * 24;
61b844bf
TL
522 }
523
524 /* If the object we're waiting on has reached completion,
525 return now. */
526 if (waiter && waiter -> ready)
527 return ISC_R_SUCCESS;
528
cfb3f45d 529 again:
61b844bf
TL
530 /* If we have no I/O state, we can't proceed. */
531 if (!(io = omapi_io_states.next))
532 return ISC_R_NOMORE;
533
534 /* Set up the read and write masks. */
535 FD_ZERO (&r);
536 FD_ZERO (&w);
537
538 for (; io; io = io -> next) {
539 /* Check for a read socket. If we shouldn't be
540 trying to read for this I/O object, either there
541 won't be a readfd function, or it'll return -1. */
d8c46740 542 if (io -> readfd && io -> inner &&
61b844bf
TL
543 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
544 FD_SET (desc, &r);
545 if (desc > max)
546 max = desc;
547 }
548
549 /* Same deal for write fdets. */
d8c46740 550 if (io -> writefd && io -> inner &&
61b844bf
TL
551 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
552 FD_SET (desc, &w);
553 if (desc > max)
554 max = desc;
555 }
556 }
557
6368a1bd
DH
558 /* poll if all reader are dry */
559 now.tv_sec = 0;
560 now.tv_usec = 0;
561 rr=r;
562 ww=w;
563 xx=x;
564
565 /* poll once */
566 count = select(max + 1, &r, &w, &x, &now);
567 if (!count) {
568 /* We are dry now */
569 trigger_event(&rw_queue_empty);
570 /* Wait for a packet or a timeout... XXX */
f9453d21
DH
571 r = rr;
572 w = ww;
573 x = xx;
574 count = select(max + 1, &r, &w, &x, t ? &to : NULL);
6368a1bd 575 }
61b844bf
TL
576
577 /* Get the current time... */
be62cf06 578 gettimeofday (&cur_tv, (struct timezone *)0);
61b844bf 579
cfb3f45d
TL
580 /* We probably have a bad file descriptor. Figure out which one.
581 When we find it, call the reaper function on it, which will
582 maybe make it go away, and then try again. */
583 if (count < 0) {
584 struct timeval t0;
9bf59e83
TL
585 omapi_io_object_t *prev = (omapi_io_object_t *)0;
586 io = (omapi_io_object_t *)0;
587 if (omapi_io_states.next)
588 omapi_io_reference (&io, omapi_io_states.next, MDL);
cfb3f45d 589
9bf59e83 590 while (io) {
cfb3f45d
TL
591 omapi_object_t *obj;
592 FD_ZERO (&r);
593 FD_ZERO (&w);
594 t0.tv_sec = t0.tv_usec = 0;
595
596 if (io -> readfd && io -> inner &&
597 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
598 FD_SET (desc, &r);
cfb3f45d
TL
599 count = select (desc + 1, &r, &w, &x, &t0);
600 bogon:
601 if (count < 0) {
602 log_error ("Bad descriptor %d.", desc);
603 for (obj = (omapi_object_t *)io;
604 obj -> outer;
605 obj = obj -> outer)
606 ;
645eab7b
TL
607 for (; obj; obj = obj -> inner) {
608 omapi_value_t *ov;
609 int len;
610 const char *s;
611 ov = (omapi_value_t *)0;
612 omapi_get_value_str (obj,
613 (omapi_object_t *)0,
614 "name", &ov);
615 if (ov && ov -> value &&
616 (ov -> value -> type ==
617 omapi_datatype_string)) {
618 s = (char *)
619 ov -> value -> u.buffer.value;
620 len = ov -> value -> u.buffer.len;
621 } else {
622 s = "";
623 len = 0;
624 }
625 log_error ("Object %lx %s%s%.*s",
626 (unsigned long)obj,
627 obj -> type -> name,
628 len ? " " : "",
629 len, s);
630 if (len)
631 omapi_value_dereference (&ov, MDL);
632 }
98311e4b 633 (*(io -> reaper)) (io -> inner);
9bf59e83
TL
634 if (prev) {
635 omapi_io_dereference (&prev -> next, MDL);
636 if (io -> next)
637 omapi_io_reference (&prev -> next,
638 io -> next, MDL);
639 } else {
640 omapi_io_dereference
641 (&omapi_io_states.next, MDL);
642 if (io -> next)
643 omapi_io_reference
644 (&omapi_io_states.next,
645 io -> next, MDL);
646 }
647 omapi_io_dereference (&io, MDL);
cfb3f45d
TL
648 goto again;
649 }
650 }
651
652 FD_ZERO (&r);
653 FD_ZERO (&w);
654 t0.tv_sec = t0.tv_usec = 0;
655
656 /* Same deal for write fdets. */
657 if (io -> writefd && io -> inner &&
658 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
659 FD_SET (desc, &w);
cfb3f45d
TL
660 count = select (desc + 1, &r, &w, &x, &t0);
661 if (count < 0)
662 goto bogon;
663 }
9bf59e83
TL
664 if (prev)
665 omapi_io_dereference (&prev, MDL);
666 omapi_io_reference (&prev, io, MDL);
667 omapi_io_dereference (&io, MDL);
668 if (prev -> next)
669 omapi_io_reference (&io, prev -> next, MDL);
cfb3f45d 670 }
9bf59e83
TL
671 if (prev)
672 omapi_io_dereference (&prev, MDL);
673
cfb3f45d 674 }
61b844bf
TL
675
676 for (io = omapi_io_states.next; io; io = io -> next) {
d8c46740
TL
677 if (!io -> inner)
678 continue;
b6237fb2 679 omapi_object_reference (&tmp, io -> inner, MDL);
61b844bf
TL
680 /* Check for a read descriptor, and if there is one,
681 see if we got input on that socket. */
682 if (io -> readfd &&
b6237fb2 683 (desc = (*(io -> readfd)) (tmp)) >= 0) {
61b844bf 684 if (FD_ISSET (desc, &r))
98311e4b 685 ((*(io -> reader)) (tmp));
61b844bf
TL
686 }
687
688 /* Same deal for write descriptors. */
689 if (io -> writefd &&
b6237fb2 690 (desc = (*(io -> writefd)) (tmp)) >= 0)
61b844bf
TL
691 {
692 if (FD_ISSET (desc, &w))
98311e4b 693 ((*(io -> writer)) (tmp));
61b844bf 694 }
b6237fb2 695 omapi_object_dereference (&tmp, MDL);
61b844bf
TL
696 }
697
698 /* Now check for I/O handles that are no longer valid,
699 and remove them from the list. */
4619c0a2
DH
700 prev = NULL;
701 io = NULL;
702 if (omapi_io_states.next != NULL) {
703 omapi_io_reference(&io, omapi_io_states.next, MDL);
704 }
705 while (io != NULL) {
706 if ((io->inner == NULL) ||
707 ((io->reaper != NULL) &&
708 ((io->reaper)(io->inner) != ISC_R_SUCCESS)))
709 {
710
711 omapi_io_object_t *tmp = NULL;
712 /* Save a reference to the next
713 pointer, if there is one. */
714 if (io->next != NULL) {
715 omapi_io_reference(&tmp, io->next, MDL);
716 omapi_io_dereference(&io->next, MDL);
61b844bf 717 }
4619c0a2
DH
718 if (prev != NULL) {
719 omapi_io_dereference(&prev->next, MDL);
720 if (tmp != NULL)
721 omapi_io_reference(&prev->next,
722 tmp, MDL);
723 } else {
724 omapi_io_dereference(&omapi_io_states.next,
725 MDL);
726 if (tmp != NULL)
727 omapi_io_reference
728 (&omapi_io_states.next,
729 tmp, MDL);
730 else
731 omapi_signal_in(
732 (omapi_object_t *)
733 &omapi_io_states,
734 "ready");
735 }
736 if (tmp != NULL)
737 omapi_io_dereference(&tmp, MDL);
738
739 } else {
740
741 if (prev != NULL) {
742 omapi_io_dereference(&prev, MDL);
743 }
744 omapi_io_reference(&prev, io, MDL);
61b844bf 745 }
4619c0a2
DH
746
747 /*
748 * Equivalent to:
749 * io = io->next
750 * But using our reference counting voodoo.
751 */
752 next = NULL;
753 if (io->next != NULL) {
754 omapi_io_reference(&next, io->next, MDL);
755 }
756 omapi_io_dereference(&io, MDL);
757 if (next != NULL) {
758 omapi_io_reference(&io, next, MDL);
759 omapi_io_dereference(&next, MDL);
760 }
761 }
762 if (prev != NULL) {
763 omapi_io_dereference(&prev, MDL);
61b844bf
TL
764 }
765
766 return ISC_R_SUCCESS;
767}
768
769isc_result_t omapi_io_set_value (omapi_object_t *h,
770 omapi_object_t *id,
771 omapi_data_string_t *name,
772 omapi_typed_data_t *value)
773{
774 if (h -> type != omapi_type_io_object)
98bf1607 775 return DHCP_R_INVALIDARG;
61b844bf
TL
776
777 if (h -> inner && h -> inner -> type -> set_value)
778 return (*(h -> inner -> type -> set_value))
779 (h -> inner, id, name, value);
780 return ISC_R_NOTFOUND;
781}
782
783isc_result_t omapi_io_get_value (omapi_object_t *h,
784 omapi_object_t *id,
785 omapi_data_string_t *name,
786 omapi_value_t **value)
787{
788 if (h -> type != omapi_type_io_object)
98bf1607 789 return DHCP_R_INVALIDARG;
61b844bf
TL
790
791 if (h -> inner && h -> inner -> type -> get_value)
792 return (*(h -> inner -> type -> get_value))
793 (h -> inner, id, name, value);
794 return ISC_R_NOTFOUND;
795}
796
98311e4b
DH
797/* omapi_io_destroy (object, MDL);
798 *
20ae1aff 799 * Find the requested IO [object] and remove it from the list of io
98311e4b
DH
800 * states, causing the cleanup functions to destroy it. Note that we must
801 * hold a reference on the object while moving its ->next reference and
802 * removing the reference in the chain to the target object...otherwise it
803 * may be cleaned up from under us.
804 */
4bd8800e 805isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
61b844bf 806{
98311e4b 807 omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
bdcaf7b9 808
61b844bf 809 if (h -> type != omapi_type_io_object)
98bf1607 810 return DHCP_R_INVALIDARG;
bdcaf7b9 811
b6237fb2
TL
812 /* remove from the list of I/O states */
813 for (p = omapi_io_states.next; p; p = p -> next) {
98311e4b
DH
814 if (p == (omapi_io_object_t *)h) {
815 omapi_io_reference (&obj, p, MDL);
816
817 if (last)
818 holder = &last -> next;
819 else
820 holder = &omapi_io_states.next;
821
822 omapi_io_dereference (holder, MDL);
823
824 if (obj -> next) {
825 omapi_io_reference (holder, obj -> next, MDL);
826 omapi_io_dereference (&obj -> next, MDL);
827 }
828
829 return omapi_io_dereference (&obj, MDL);
bdcaf7b9 830 }
b6237fb2 831 last = p;
bdcaf7b9 832 }
98311e4b
DH
833
834 return ISC_R_NOTFOUND;
61b844bf
TL
835}
836
837isc_result_t omapi_io_signal_handler (omapi_object_t *h,
b1b7b521 838 const char *name, va_list ap)
61b844bf
TL
839{
840 if (h -> type != omapi_type_io_object)
98bf1607 841 return DHCP_R_INVALIDARG;
61b844bf
TL
842
843 if (h -> inner && h -> inner -> type -> signal_handler)
844 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
845 name, ap);
846 return ISC_R_NOTFOUND;
847}
848
849isc_result_t omapi_io_stuff_values (omapi_object_t *c,
850 omapi_object_t *id,
851 omapi_object_t *i)
852{
853 if (i -> type != omapi_type_io_object)
98bf1607 854 return DHCP_R_INVALIDARG;
61b844bf
TL
855
856 if (i -> inner && i -> inner -> type -> stuff_values)
857 return (*(i -> inner -> type -> stuff_values)) (c, id,
858 i -> inner);
859 return ISC_R_SUCCESS;
860}
861
862isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
b1b7b521 863 const char *name, va_list ap)
61b844bf
TL
864{
865 omapi_waiter_object_t *waiter;
866
867 if (h -> type != omapi_type_waiter)
98bf1607 868 return DHCP_R_INVALIDARG;
61b844bf
TL
869
870 if (!strcmp (name, "ready")) {
871 waiter = (omapi_waiter_object_t *)h;
872 waiter -> ready = 1;
49146f3c
DN
873 waiter -> waitstatus = ISC_R_SUCCESS;
874 return ISC_R_SUCCESS;
875 }
876
98bf1607 877 if (!strcmp(name, "status")) {
49146f3c 878 waiter = (omapi_waiter_object_t *)h;
98bf1607
SR
879 waiter->ready = 1;
880 waiter->waitstatus = va_arg(ap, isc_result_t);
61b844bf
TL
881 return ISC_R_SUCCESS;
882 }
883
d758ad8c
TL
884 if (!strcmp (name, "disconnect")) {
885 waiter = (omapi_waiter_object_t *)h;
886 waiter -> ready = 1;
98bf1607 887 waiter -> waitstatus = DHCP_R_CONNRESET;
d758ad8c
TL
888 return ISC_R_SUCCESS;
889 }
890
61b844bf
TL
891 if (h -> inner && h -> inner -> type -> signal_handler)
892 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
893 name, ap);
894 return ISC_R_NOTFOUND;
895}
896
47e8308d
SR
897/** @brief calls a given function on every object
898 *
899 * @param func function to be called
900 * @param p parameter to be passed to each function instance
901 *
902 * @return result (ISC_R_SUCCESS if successful, error code otherwise)
903 */
d758ad8c
TL
904isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
905 void *),
906 void *p)
907{
47e8308d 908 omapi_io_object_t *io = NULL;
d758ad8c 909 isc_result_t status;
47e8308d 910 omapi_io_object_t *next = NULL;
d758ad8c 911
47e8308d
SR
912 /*
913 * This just calls func on every inner object on the list. It would
914 * be much simpler in general case, but one of the operations could be
915 * release of the objects. Therefore we need to ref count the io and
916 * io->next pointers.
917 */
918
919 if (omapi_io_states.next) {
920 omapi_object_reference((omapi_object_t**)&io,
921 (omapi_object_t*)omapi_io_states.next,
922 MDL);
923 }
924
925 while(io) {
926 /* If there's a next object, save it */
927 if (io->next) {
928 omapi_object_reference((omapi_object_t**)&next,
929 (omapi_object_t*)io->next, MDL);
930 }
931 if (io->inner) {
932 status = (*func) (io->inner, p);
933 if (status != ISC_R_SUCCESS) {
934 /* Something went wrong. Let's stop using io & next pointer
935 * and bail out */
936 omapi_object_dereference((omapi_object_t**)&io, MDL);
937 if (next) {
938 omapi_object_dereference((omapi_object_t**)&next, MDL);
939 }
940 return status;
d758ad8c 941 }
47e8308d
SR
942 }
943 /* Update the io pointer and free the next pointer */
944 omapi_object_dereference((omapi_object_t**)&io, MDL);
945 if (next) {
946 omapi_object_reference((omapi_object_t**)&io,
947 (omapi_object_t*)next,
948 MDL);
949 omapi_object_dereference((omapi_object_t**)&next, MDL);
950 }
d758ad8c 951 }
47e8308d
SR
952
953 /*
954 * The only way to get here is when next is NULL. There's no need
955 * to dereference it.
956 */
d758ad8c
TL
957 return ISC_R_SUCCESS;
958}