Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / omapip / dispatch.c
blobdf9dd631a39711ad8523607557467054fb5da471
1 /* dispatch.c
3 I/O dispatcher. */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
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.
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.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``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''.
35 #include <omapip/omapip_p.h>
37 static omapi_io_object_t omapi_io_states;
38 TIME cur_time;
40 OMAPI_OBJECT_ALLOC (omapi_io,
41 omapi_io_object_t, omapi_type_io_object)
42 OMAPI_OBJECT_ALLOC (omapi_waiter,
43 omapi_waiter_object_t, omapi_type_waiter)
45 /* Register an I/O handle so that we can do asynchronous I/O on it. */
47 isc_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 *))
57 isc_result_t status;
58 omapi_io_object_t *obj, *p;
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;
70 obj = (omapi_io_object_t *)0;
71 status = omapi_io_allocate (&obj, MDL);
72 if (status != ISC_R_SUCCESS)
73 return status;
75 status = omapi_object_reference (&obj -> inner, h, MDL);
76 if (status != ISC_R_SUCCESS) {
77 omapi_io_dereference (&obj, MDL);
78 return status;
81 status = omapi_object_reference (&h -> outer,
82 (omapi_object_t *)obj, MDL);
83 if (status != ISC_R_SUCCESS) {
84 omapi_io_dereference (&obj, MDL);
85 return status;
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)
92 if (p)
93 omapi_io_reference (&p -> next, obj, MDL);
94 else
95 omapi_io_reference (&omapi_io_states.next, obj, MDL);
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;
105 isc_result_t omapi_unregister_io_object (omapi_object_t *h)
107 omapi_io_object_t *p, *obj, *last, *ph;
109 if (!h -> outer || h -> outer -> type != omapi_type_io_object)
110 return ISC_R_INVALIDARG;
111 obj = (omapi_io_object_t *)h -> outer;
112 ph = (omapi_io_object_t *)0;
113 omapi_io_reference (&ph, obj, MDL);
115 /* remove from the list of I/O states */
116 last = &omapi_io_states;
117 for (p = omapi_io_states.next; p; p = p -> next) {
118 if (p == obj) {
119 omapi_io_dereference (&last -> next, MDL);
120 omapi_io_reference (&last -> next, p -> next, MDL);
121 break;
123 last = p;
125 if (obj -> next)
126 omapi_io_dereference (&obj -> next, MDL);
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);
134 omapi_object_dereference (&obj -> inner, MDL);
135 omapi_object_dereference (&h -> outer, MDL);
136 omapi_io_dereference (&ph, MDL);
137 return ISC_R_SUCCESS;
140 isc_result_t omapi_dispatch (struct timeval *t)
142 return omapi_wait_for_completion ((void *)&omapi_io_states,
146 isc_result_t omapi_wait_for_completion (omapi_object_t *object,
147 struct timeval *t)
149 isc_result_t status;
150 omapi_waiter_object_t *waiter;
151 omapi_object_t *inner;
153 if (object) {
154 waiter = (omapi_waiter_object_t *)0;
155 status = omapi_waiter_allocate (&waiter, MDL);
156 if (status != ISC_R_SUCCESS)
157 return status;
159 /* Paste the waiter object onto the inner object we're
160 waiting on. */
161 for (inner = object; inner -> inner; inner = inner -> inner)
164 status = omapi_object_reference (&waiter -> outer, inner, MDL);
165 if (status != ISC_R_SUCCESS) {
166 omapi_waiter_dereference (&waiter, MDL);
167 return status;
170 status = omapi_object_reference (&inner -> inner,
171 (omapi_object_t *)waiter,
172 MDL);
173 if (status != ISC_R_SUCCESS) {
174 omapi_waiter_dereference (&waiter, MDL);
175 return status;
177 } else
178 waiter = (omapi_waiter_object_t *)0;
180 do {
181 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
182 if (status != ISC_R_SUCCESS)
183 return status;
184 } while (!waiter || !waiter -> ready);
186 if (waiter -> outer) {
187 if (waiter -> outer -> inner) {
188 omapi_object_dereference (&waiter -> outer -> inner,
189 MDL);
190 if (waiter -> inner)
191 omapi_object_reference
192 (&waiter -> outer -> inner,
193 waiter -> inner, MDL);
195 omapi_object_dereference (&waiter -> outer, MDL);
197 if (waiter -> inner)
198 omapi_object_dereference (&waiter -> inner, MDL);
200 status = waiter -> waitstatus;
201 omapi_waiter_dereference (&waiter, MDL);
202 return status;
205 isc_result_t omapi_one_dispatch (omapi_object_t *wo,
206 struct timeval *t)
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;
214 omapi_waiter_object_t *waiter;
215 omapi_object_t *tmp = (omapi_object_t *)0;
217 if (!wo || wo -> type != omapi_type_waiter)
218 waiter = (omapi_waiter_object_t *)0;
219 else
220 waiter = (omapi_waiter_object_t *)wo;
222 FD_ZERO (&x);
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;
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--;
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;
249 /* If the object we're waiting on has reached completion,
250 return now. */
251 if (waiter && waiter -> ready)
252 return ISC_R_SUCCESS;
254 again:
255 /* If we have no I/O state, we can't proceed. */
256 if (!(io = omapi_io_states.next))
257 return ISC_R_NOMORE;
259 /* Set up the read and write masks. */
260 FD_ZERO (&r);
261 FD_ZERO (&w);
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. */
267 if (io -> readfd && io -> inner &&
268 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
269 FD_SET (desc, &r);
270 if (desc > max)
271 max = desc;
274 /* Same deal for write fdets. */
275 if (io -> writefd && io -> inner &&
276 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
277 FD_SET (desc, &w);
278 if (desc > max)
279 max = desc;
283 /* Wait for a packet or a timeout... XXX */
284 #if 0
285 #if defined (__linux__)
286 #define fds_bits __fds_bits
287 #endif
288 log_error ("dispatch: %d %lx %lx", max,
289 (unsigned long)r.fds_bits [0],
290 (unsigned long)w.fds_bits [0]);
291 #endif
292 count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0);
294 /* Get the current time... */
295 gettimeofday (&now, (struct timezone *)0);
296 cur_time = now.tv_sec;
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;
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);
308 while (io) {
309 omapi_object_t *obj;
310 FD_ZERO (&r);
311 FD_ZERO (&w);
312 t0.tv_sec = t0.tv_usec = 0;
314 if (io -> readfd && io -> inner &&
315 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
316 FD_SET (desc, &r);
317 #if 0
318 log_error ("read check: %d %lx %lx", max,
319 (unsigned long)r.fds_bits [0],
320 (unsigned long)w.fds_bits [0]);
321 #endif
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)
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;
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);
356 (*(io -> reaper)) (io -> inner);
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);
370 omapi_io_dereference (&io, MDL);
371 goto again;
375 FD_ZERO (&r);
376 FD_ZERO (&w);
377 t0.tv_sec = t0.tv_usec = 0;
379 /* Same deal for write fdets. */
380 if (io -> writefd && io -> inner &&
381 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
382 FD_SET (desc, &w);
383 count = select (desc + 1, &r, &w, &x, &t0);
384 if (count < 0)
385 goto bogon;
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);
394 if (prev)
395 omapi_io_dereference (&prev, MDL);
399 for (io = omapi_io_states.next; io; io = io -> next) {
400 if (!io -> inner)
401 continue;
402 omapi_object_reference (&tmp, io -> inner, MDL);
403 /* Check for a read descriptor, and if there is one,
404 see if we got input on that socket. */
405 if (io -> readfd &&
406 (desc = (*(io -> readfd)) (tmp)) >= 0) {
407 if (FD_ISSET (desc, &r))
408 ((*(io -> reader)) (tmp));
411 /* Same deal for write descriptors. */
412 if (io -> writefd &&
413 (desc = (*(io -> writefd)) (tmp)) >= 0)
415 if (FD_ISSET (desc, &w))
416 ((*(io -> writer)) (tmp));
418 omapi_object_dereference (&tmp, MDL);
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) {
426 if (!io -> inner ||
427 ((*(io -> reaper)) (io -> inner) !=
428 ISC_R_SUCCESS)) {
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)
434 omapi_io_reference (&tmp,
435 io -> next, MDL);
436 if (prev) {
437 omapi_io_dereference (&prev -> next,
438 MDL);
439 if (tmp)
440 omapi_io_reference
441 (&prev -> next,
442 tmp, MDL);
443 } else {
444 omapi_io_dereference
445 (&omapi_io_states.next, MDL);
446 if (tmp)
447 omapi_io_reference
448 (&omapi_io_states.next,
449 tmp, MDL);
450 else
451 omapi_signal_in
452 ((void *)
453 &omapi_io_states,
454 "ready");
456 if (tmp)
457 omapi_io_dereference (&tmp, MDL);
460 prev = io;
463 return ISC_R_SUCCESS;
466 isc_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)
471 if (h -> type != omapi_type_io_object)
472 return ISC_R_INVALIDARG;
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;
480 isc_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)
485 if (h -> type != omapi_type_io_object)
486 return ISC_R_INVALIDARG;
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;
494 /* omapi_io_destroy (object, MDL);
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.
502 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
504 omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
506 if (h -> type != omapi_type_io_object)
507 return ISC_R_INVALIDARG;
509 /* remove from the list of I/O states */
510 last = &omapi_io_states;
511 for (p = omapi_io_states.next; p; p = p -> next) {
512 if (p == (omapi_io_object_t *)h) {
513 omapi_io_reference (&obj, p, MDL);
515 if (last)
516 holder = &last -> next;
517 else
518 holder = &omapi_io_states.next;
520 omapi_io_dereference (holder, MDL);
522 if (obj -> next) {
523 omapi_io_reference (holder, obj -> next, MDL);
524 omapi_io_dereference (&obj -> next, MDL);
527 return omapi_io_dereference (&obj, MDL);
529 last = p;
532 return ISC_R_NOTFOUND;
535 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
536 const char *name, va_list ap)
538 if (h -> type != omapi_type_io_object)
539 return ISC_R_INVALIDARG;
541 if (h -> inner && h -> inner -> type -> signal_handler)
542 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
543 name, ap);
544 return ISC_R_NOTFOUND;
547 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
548 omapi_object_t *id,
549 omapi_object_t *i)
551 if (i -> type != omapi_type_io_object)
552 return ISC_R_INVALIDARG;
554 if (i -> inner && i -> inner -> type -> stuff_values)
555 return (*(i -> inner -> type -> stuff_values)) (c, id,
556 i -> inner);
557 return ISC_R_SUCCESS;
560 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
561 const char *name, va_list ap)
563 omapi_waiter_object_t *waiter;
565 if (h -> type != omapi_type_waiter)
566 return ISC_R_INVALIDARG;
568 if (!strcmp (name, "ready")) {
569 waiter = (omapi_waiter_object_t *)h;
570 waiter -> ready = 1;
571 waiter -> waitstatus = ISC_R_SUCCESS;
572 return ISC_R_SUCCESS;
575 if (!strcmp (name, "status")) {
576 waiter = (omapi_waiter_object_t *)h;
577 waiter -> ready = 1;
578 waiter -> waitstatus = va_arg (ap, isc_result_t);
579 return ISC_R_SUCCESS;
582 if (!strcmp (name, "disconnect")) {
583 waiter = (omapi_waiter_object_t *)h;
584 waiter -> ready = 1;
585 waiter -> waitstatus = ISC_R_CONNRESET;
586 return ISC_R_SUCCESS;
589 if (h -> inner && h -> inner -> type -> signal_handler)
590 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
591 name, ap);
592 return ISC_R_NOTFOUND;
595 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
596 void *),
597 void *p)
599 omapi_io_object_t *io;
600 isc_result_t status;
602 for (io = omapi_io_states.next; io; io = io -> next) {
603 if (io -> inner) {
604 status = (*func) (io -> inner, p);
605 if (status != ISC_R_SUCCESS)
606 return status;
609 return ISC_R_SUCCESS;