]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/dispatch.c
MASSIVE merge from V3-RELEASE-BRANCH into HEAD. HEAD and V3-RELEASE are
[thirdparty/dhcp.git] / omapip / dispatch.c
CommitLineData
61b844bf
TL
1/* dispatch.c
2
3 I/O dispatcher. */
4
5/*
98311e4b
DH
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
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>
25 * http://www.isc.org/
49733f31 26 *
98311e4b 27 * This software has been written for Internet Systems Consortium
49733f31 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
98311e4b 29 * To learn more about Internet Systems Consortium, see
49733f31
TL
30 * ``http://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''.
61b844bf
TL
33 */
34
6a4c4be8 35#include <omapip/omapip_p.h>
61b844bf
TL
36
37static omapi_io_object_t omapi_io_states;
98311e4b 38TIME cur_time;
61b844bf 39
20916cae
TL
40OMAPI_OBJECT_ALLOC (omapi_io,
41 omapi_io_object_t, omapi_type_io_object)
42OMAPI_OBJECT_ALLOC (omapi_waiter,
43 omapi_waiter_object_t, omapi_type_waiter)
44
61b844bf
TL
45/* Register an I/O handle so that we can do asynchronous I/O on it. */
46
47isc_result_t omapi_register_io_object (omapi_object_t *h,
48 int (*readfd) (omapi_object_t *),
49 int (*writefd) (omapi_object_t *),
50 isc_result_t (*reader)
51 (omapi_object_t *),
52 isc_result_t (*writer)
53 (omapi_object_t *),
54 isc_result_t (*reaper)
55 (omapi_object_t *))
56{
57 isc_result_t status;
58 omapi_io_object_t *obj, *p;
59
60 /* omapi_io_states is a static object. If its reference count
61 is zero, this is the first I/O handle to be registered, so
62 we need to initialize it. Because there is no inner or outer
63 pointer on this object, and we're setting its refcnt to 1, it
64 will never be freed. */
65 if (!omapi_io_states.refcnt) {
66 omapi_io_states.refcnt = 1;
67 omapi_io_states.type = omapi_type_io_object;
68 }
69
20916cae
TL
70 obj = (omapi_io_object_t *)0;
71 status = omapi_io_allocate (&obj, MDL);
72 if (status != ISC_R_SUCCESS)
73 return status;
61b844bf 74
4bd8800e 75 status = omapi_object_reference (&obj -> inner, h, MDL);
61b844bf 76 if (status != ISC_R_SUCCESS) {
20916cae 77 omapi_io_dereference (&obj, MDL);
61b844bf
TL
78 return status;
79 }
80
4bd8800e
TL
81 status = omapi_object_reference (&h -> outer,
82 (omapi_object_t *)obj, MDL);
61b844bf 83 if (status != ISC_R_SUCCESS) {
20916cae 84 omapi_io_dereference (&obj, MDL);
61b844bf
TL
85 return status;
86 }
87
88 /* Find the last I/O state, if there are any. */
89 for (p = omapi_io_states.next;
90 p && p -> next; p = p -> next)
91 ;
92 if (p)
20916cae 93 omapi_io_reference (&p -> next, obj, MDL);
61b844bf 94 else
20916cae 95 omapi_io_reference (&omapi_io_states.next, obj, MDL);
61b844bf
TL
96
97 obj -> readfd = readfd;
98 obj -> writefd = writefd;
99 obj -> reader = reader;
100 obj -> writer = writer;
101 obj -> reaper = reaper;
102 return ISC_R_SUCCESS;
103}
104
b6237fb2
TL
105isc_result_t omapi_unregister_io_object (omapi_object_t *h)
106{
20916cae 107 omapi_io_object_t *p, *obj, *last, *ph;
b6237fb2 108
20916cae
TL
109 if (!h -> outer || h -> outer -> type != omapi_type_io_object)
110 return ISC_R_INVALIDARG;
b6237fb2 111 obj = (omapi_io_object_t *)h -> outer;
20916cae
TL
112 ph = (omapi_io_object_t *)0;
113 omapi_io_reference (&ph, obj, MDL);
b6237fb2
TL
114
115 /* remove from the list of I/O states */
c3064fe0 116 last = &omapi_io_states;
b6237fb2 117 for (p = omapi_io_states.next; p; p = p -> next) {
20916cae
TL
118 if (p == obj) {
119 omapi_io_dereference (&last -> next, MDL);
120 omapi_io_reference (&last -> next, p -> next, MDL);
b6237fb2
TL
121 break;
122 }
123 last = p;
124 }
125 if (obj -> next)
20916cae
TL
126 omapi_io_dereference (&obj -> next, MDL);
127
b6237fb2
TL
128 if (obj -> outer) {
129 if (obj -> outer -> inner == (omapi_object_t *)obj)
130 omapi_object_dereference (&obj -> outer -> inner,
131 MDL);
132 omapi_object_dereference (&obj -> outer, MDL);
133 }
134 omapi_object_dereference (&obj -> inner, MDL);
135 omapi_object_dereference (&h -> outer, MDL);
20916cae 136 omapi_io_dereference (&ph, MDL);
b6237fb2
TL
137 return ISC_R_SUCCESS;
138}
139
61b844bf
TL
140isc_result_t omapi_dispatch (struct timeval *t)
141{
142 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
143 t);
144}
145
146isc_result_t omapi_wait_for_completion (omapi_object_t *object,
147 struct timeval *t)
148{
149 isc_result_t status;
150 omapi_waiter_object_t *waiter;
151 omapi_object_t *inner;
152
153 if (object) {
20916cae
TL
154 waiter = (omapi_waiter_object_t *)0;
155 status = omapi_waiter_allocate (&waiter, MDL);
156 if (status != ISC_R_SUCCESS)
157 return status;
61b844bf
TL
158
159 /* Paste the waiter object onto the inner object we're
160 waiting on. */
161 for (inner = object; inner -> inner; inner = inner -> inner)
162 ;
163
4bd8800e 164 status = omapi_object_reference (&waiter -> outer, inner, MDL);
61b844bf 165 if (status != ISC_R_SUCCESS) {
20916cae 166 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
167 return status;
168 }
169
170 status = omapi_object_reference (&inner -> inner,
171 (omapi_object_t *)waiter,
4bd8800e 172 MDL);
61b844bf 173 if (status != ISC_R_SUCCESS) {
20916cae 174 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
175 return status;
176 }
177 } else
178 waiter = (omapi_waiter_object_t *)0;
179
180 do {
6a4c4be8 181 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
61b844bf
TL
182 if (status != ISC_R_SUCCESS)
183 return status;
184 } while (!waiter || !waiter -> ready);
185
727ebc3a
TL
186 if (waiter -> outer) {
187 if (waiter -> outer -> inner) {
188 omapi_object_dereference (&waiter -> outer -> inner,
4bd8800e 189 MDL);
727ebc3a
TL
190 if (waiter -> inner)
191 omapi_object_reference
192 (&waiter -> outer -> inner,
4bd8800e 193 waiter -> inner, MDL);
727ebc3a 194 }
4bd8800e 195 omapi_object_dereference (&waiter -> outer, MDL);
727ebc3a
TL
196 }
197 if (waiter -> inner)
4bd8800e 198 omapi_object_dereference (&waiter -> inner, MDL);
727ebc3a 199
49146f3c 200 status = waiter -> waitstatus;
20916cae 201 omapi_waiter_dereference (&waiter, MDL);
86a9cf83 202 return status;
61b844bf
TL
203}
204
6a4c4be8 205isc_result_t omapi_one_dispatch (omapi_object_t *wo,
61b844bf
TL
206 struct timeval *t)
207{
208 fd_set r, w, x;
209 int max = 0;
210 int count;
211 int desc;
212 struct timeval now, to;
213 omapi_io_object_t *io, *prev;
6a4c4be8 214 omapi_waiter_object_t *waiter;
b6237fb2 215 omapi_object_t *tmp = (omapi_object_t *)0;
6a4c4be8
TL
216
217 if (!wo || wo -> type != omapi_type_waiter)
218 waiter = (omapi_waiter_object_t *)0;
219 else
220 waiter = (omapi_waiter_object_t *)wo;
61b844bf
TL
221
222 FD_ZERO (&x);
223
224 /* First, see if the timeout has expired, and if so return. */
225 if (t) {
226 gettimeofday (&now, (struct timezone *)0);
227 cur_time = now.tv_sec;
228 if (now.tv_sec > t -> tv_sec ||
229 (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
230 return ISC_R_TIMEDOUT;
231
232 /* We didn't time out, so figure out how long until
233 we do. */
234 to.tv_sec = t -> tv_sec - now.tv_sec;
235 to.tv_usec = t -> tv_usec - now.tv_usec;
236 if (to.tv_usec < 0) {
237 to.tv_usec += 1000000;
238 to.tv_sec--;
239 }
d01dde76
DN
240
241 /* It is possible for the timeout to get set larger than
242 the largest time select() is willing to accept.
243 Restricting the timeout to a maximum of one day should
244 work around this. -DPN. (Ref: Bug #416) */
245 if (to.tv_sec > (60 * 60 * 24))
246 to.tv_sec = 60 * 60 * 24;
61b844bf
TL
247 }
248
249 /* If the object we're waiting on has reached completion,
250 return now. */
251 if (waiter && waiter -> ready)
252 return ISC_R_SUCCESS;
253
cfb3f45d 254 again:
61b844bf
TL
255 /* If we have no I/O state, we can't proceed. */
256 if (!(io = omapi_io_states.next))
257 return ISC_R_NOMORE;
258
259 /* Set up the read and write masks. */
260 FD_ZERO (&r);
261 FD_ZERO (&w);
262
263 for (; io; io = io -> next) {
264 /* Check for a read socket. If we shouldn't be
265 trying to read for this I/O object, either there
266 won't be a readfd function, or it'll return -1. */
d8c46740 267 if (io -> readfd && io -> inner &&
61b844bf
TL
268 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
269 FD_SET (desc, &r);
270 if (desc > max)
271 max = desc;
272 }
273
274 /* Same deal for write fdets. */
d8c46740 275 if (io -> writefd && io -> inner &&
61b844bf
TL
276 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
277 FD_SET (desc, &w);
278 if (desc > max)
279 max = desc;
280 }
281 }
282
283 /* Wait for a packet or a timeout... XXX */
edbb7667 284#if 0
cfb3f45d
TL
285#if defined (__linux__)
286#define fds_bits __fds_bits
287#endif
477e97dd
TL
288 log_error ("dispatch: %d %lx %lx", max,
289 (unsigned long)r.fds_bits [0],
290 (unsigned long)w.fds_bits [0]);
edbb7667 291#endif
61b844bf
TL
292 count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0);
293
294 /* Get the current time... */
295 gettimeofday (&now, (struct timezone *)0);
296 cur_time = now.tv_sec;
297
cfb3f45d
TL
298 /* We probably have a bad file descriptor. Figure out which one.
299 When we find it, call the reaper function on it, which will
300 maybe make it go away, and then try again. */
301 if (count < 0) {
302 struct timeval t0;
9bf59e83
TL
303 omapi_io_object_t *prev = (omapi_io_object_t *)0;
304 io = (omapi_io_object_t *)0;
305 if (omapi_io_states.next)
306 omapi_io_reference (&io, omapi_io_states.next, MDL);
cfb3f45d 307
9bf59e83 308 while (io) {
cfb3f45d
TL
309 omapi_object_t *obj;
310 FD_ZERO (&r);
311 FD_ZERO (&w);
312 t0.tv_sec = t0.tv_usec = 0;
313
314 if (io -> readfd && io -> inner &&
315 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
316 FD_SET (desc, &r);
edbb7667 317#if 0
477e97dd
TL
318 log_error ("read check: %d %lx %lx", max,
319 (unsigned long)r.fds_bits [0],
320 (unsigned long)w.fds_bits [0]);
edbb7667 321#endif
cfb3f45d
TL
322 count = select (desc + 1, &r, &w, &x, &t0);
323 bogon:
324 if (count < 0) {
325 log_error ("Bad descriptor %d.", desc);
326 for (obj = (omapi_object_t *)io;
327 obj -> outer;
328 obj = obj -> outer)
329 ;
645eab7b
TL
330 for (; obj; obj = obj -> inner) {
331 omapi_value_t *ov;
332 int len;
333 const char *s;
334 ov = (omapi_value_t *)0;
335 omapi_get_value_str (obj,
336 (omapi_object_t *)0,
337 "name", &ov);
338 if (ov && ov -> value &&
339 (ov -> value -> type ==
340 omapi_datatype_string)) {
341 s = (char *)
342 ov -> value -> u.buffer.value;
343 len = ov -> value -> u.buffer.len;
344 } else {
345 s = "";
346 len = 0;
347 }
348 log_error ("Object %lx %s%s%.*s",
349 (unsigned long)obj,
350 obj -> type -> name,
351 len ? " " : "",
352 len, s);
353 if (len)
354 omapi_value_dereference (&ov, MDL);
355 }
98311e4b 356 (*(io -> reaper)) (io -> inner);
9bf59e83
TL
357 if (prev) {
358 omapi_io_dereference (&prev -> next, MDL);
359 if (io -> next)
360 omapi_io_reference (&prev -> next,
361 io -> next, MDL);
362 } else {
363 omapi_io_dereference
364 (&omapi_io_states.next, MDL);
365 if (io -> next)
366 omapi_io_reference
367 (&omapi_io_states.next,
368 io -> next, MDL);
369 }
370 omapi_io_dereference (&io, MDL);
cfb3f45d
TL
371 goto again;
372 }
373 }
374
375 FD_ZERO (&r);
376 FD_ZERO (&w);
377 t0.tv_sec = t0.tv_usec = 0;
378
379 /* Same deal for write fdets. */
380 if (io -> writefd && io -> inner &&
381 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
382 FD_SET (desc, &w);
cfb3f45d
TL
383 count = select (desc + 1, &r, &w, &x, &t0);
384 if (count < 0)
385 goto bogon;
386 }
9bf59e83
TL
387 if (prev)
388 omapi_io_dereference (&prev, MDL);
389 omapi_io_reference (&prev, io, MDL);
390 omapi_io_dereference (&io, MDL);
391 if (prev -> next)
392 omapi_io_reference (&io, prev -> next, MDL);
cfb3f45d 393 }
9bf59e83
TL
394 if (prev)
395 omapi_io_dereference (&prev, MDL);
396
cfb3f45d 397 }
61b844bf
TL
398
399 for (io = omapi_io_states.next; io; io = io -> next) {
d8c46740
TL
400 if (!io -> inner)
401 continue;
b6237fb2 402 omapi_object_reference (&tmp, io -> inner, MDL);
61b844bf
TL
403 /* Check for a read descriptor, and if there is one,
404 see if we got input on that socket. */
405 if (io -> readfd &&
b6237fb2 406 (desc = (*(io -> readfd)) (tmp)) >= 0) {
61b844bf 407 if (FD_ISSET (desc, &r))
98311e4b 408 ((*(io -> reader)) (tmp));
61b844bf
TL
409 }
410
411 /* Same deal for write descriptors. */
412 if (io -> writefd &&
b6237fb2 413 (desc = (*(io -> writefd)) (tmp)) >= 0)
61b844bf
TL
414 {
415 if (FD_ISSET (desc, &w))
98311e4b 416 ((*(io -> writer)) (tmp));
61b844bf 417 }
b6237fb2 418 omapi_object_dereference (&tmp, MDL);
61b844bf
TL
419 }
420
421 /* Now check for I/O handles that are no longer valid,
422 and remove them from the list. */
423 prev = (omapi_io_object_t *)0;
424 for (io = omapi_io_states.next; io; io = io -> next) {
425 if (io -> reaper) {
98311e4b
DH
426 if (!io -> inner ||
427 ((*(io -> reaper)) (io -> inner) !=
428 ISC_R_SUCCESS)) {
61b844bf
TL
429 omapi_io_object_t *tmp =
430 (omapi_io_object_t *)0;
431 /* Save a reference to the next
432 pointer, if there is one. */
433 if (io -> next)
20916cae
TL
434 omapi_io_reference (&tmp,
435 io -> next, MDL);
61b844bf 436 if (prev) {
20916cae
TL
437 omapi_io_dereference (&prev -> next,
438 MDL);
61b844bf 439 if (tmp)
20916cae
TL
440 omapi_io_reference
441 (&prev -> next,
442 tmp, MDL);
61b844bf 443 } else {
20916cae
TL
444 omapi_io_dereference
445 (&omapi_io_states.next, MDL);
61b844bf 446 if (tmp)
20916cae
TL
447 omapi_io_reference
448 (&omapi_io_states.next,
449 tmp, MDL);
61b844bf
TL
450 else
451 omapi_signal_in
452 ((omapi_object_t *)
453 &omapi_io_states,
454 "ready");
455 }
456 if (tmp)
20916cae 457 omapi_io_dereference (&tmp, MDL);
61b844bf
TL
458 }
459 }
460 prev = io;
461 }
462
463 return ISC_R_SUCCESS;
464}
465
466isc_result_t omapi_io_set_value (omapi_object_t *h,
467 omapi_object_t *id,
468 omapi_data_string_t *name,
469 omapi_typed_data_t *value)
470{
471 if (h -> type != omapi_type_io_object)
472 return ISC_R_INVALIDARG;
473
474 if (h -> inner && h -> inner -> type -> set_value)
475 return (*(h -> inner -> type -> set_value))
476 (h -> inner, id, name, value);
477 return ISC_R_NOTFOUND;
478}
479
480isc_result_t omapi_io_get_value (omapi_object_t *h,
481 omapi_object_t *id,
482 omapi_data_string_t *name,
483 omapi_value_t **value)
484{
485 if (h -> type != omapi_type_io_object)
486 return ISC_R_INVALIDARG;
487
488 if (h -> inner && h -> inner -> type -> get_value)
489 return (*(h -> inner -> type -> get_value))
490 (h -> inner, id, name, value);
491 return ISC_R_NOTFOUND;
492}
493
98311e4b
DH
494/* omapi_io_destroy (object, MDL);
495 *
496 * Find the requsted IO [object] and remove it from the list of io
497 * states, causing the cleanup functions to destroy it. Note that we must
498 * hold a reference on the object while moving its ->next reference and
499 * removing the reference in the chain to the target object...otherwise it
500 * may be cleaned up from under us.
501 */
4bd8800e 502isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
61b844bf 503{
98311e4b 504 omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
bdcaf7b9 505
61b844bf
TL
506 if (h -> type != omapi_type_io_object)
507 return ISC_R_INVALIDARG;
bdcaf7b9 508
b6237fb2
TL
509 /* remove from the list of I/O states */
510 for (p = omapi_io_states.next; p; p = p -> next) {
98311e4b
DH
511 if (p == (omapi_io_object_t *)h) {
512 omapi_io_reference (&obj, p, MDL);
513
514 if (last)
515 holder = &last -> next;
516 else
517 holder = &omapi_io_states.next;
518
519 omapi_io_dereference (holder, MDL);
520
521 if (obj -> next) {
522 omapi_io_reference (holder, obj -> next, MDL);
523 omapi_io_dereference (&obj -> next, MDL);
524 }
525
526 return omapi_io_dereference (&obj, MDL);
bdcaf7b9 527 }
b6237fb2 528 last = p;
bdcaf7b9 529 }
98311e4b
DH
530
531 return ISC_R_NOTFOUND;
61b844bf
TL
532}
533
534isc_result_t omapi_io_signal_handler (omapi_object_t *h,
b1b7b521 535 const char *name, va_list ap)
61b844bf
TL
536{
537 if (h -> type != omapi_type_io_object)
538 return ISC_R_INVALIDARG;
539
540 if (h -> inner && h -> inner -> type -> signal_handler)
541 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
542 name, ap);
543 return ISC_R_NOTFOUND;
544}
545
546isc_result_t omapi_io_stuff_values (omapi_object_t *c,
547 omapi_object_t *id,
548 omapi_object_t *i)
549{
550 if (i -> type != omapi_type_io_object)
551 return ISC_R_INVALIDARG;
552
553 if (i -> inner && i -> inner -> type -> stuff_values)
554 return (*(i -> inner -> type -> stuff_values)) (c, id,
555 i -> inner);
556 return ISC_R_SUCCESS;
557}
558
559isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
b1b7b521 560 const char *name, va_list ap)
61b844bf
TL
561{
562 omapi_waiter_object_t *waiter;
563
564 if (h -> type != omapi_type_waiter)
565 return ISC_R_INVALIDARG;
566
567 if (!strcmp (name, "ready")) {
568 waiter = (omapi_waiter_object_t *)h;
569 waiter -> ready = 1;
49146f3c
DN
570 waiter -> waitstatus = ISC_R_SUCCESS;
571 return ISC_R_SUCCESS;
572 }
573
574 if (!strcmp (name, "status")) {
575 waiter = (omapi_waiter_object_t *)h;
576 waiter -> ready = 1;
577 waiter -> waitstatus = va_arg (ap, isc_result_t);
61b844bf
TL
578 return ISC_R_SUCCESS;
579 }
580
d758ad8c
TL
581 if (!strcmp (name, "disconnect")) {
582 waiter = (omapi_waiter_object_t *)h;
583 waiter -> ready = 1;
584 waiter -> waitstatus = ISC_R_CONNRESET;
585 return ISC_R_SUCCESS;
586 }
587
61b844bf
TL
588 if (h -> inner && h -> inner -> type -> signal_handler)
589 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
590 name, ap);
591 return ISC_R_NOTFOUND;
592}
593
d758ad8c
TL
594isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
595 void *),
596 void *p)
597{
598 omapi_io_object_t *io;
599 isc_result_t status;
600
601 for (io = omapi_io_states.next; io; io = io -> next) {
602 if (io -> inner) {
603 status = (*func) (io -> inner, p);
604 if (status != ISC_R_SUCCESS)
605 return status;
606 }
607 }
608 return ISC_R_SUCCESS;
609}