revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / omapip / dispatch.c
blobaf391eae1f0658de56c788ae8774052923aa89e1
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 ((omapi_object_t *)&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);
293 #ifdef HAVE_CHKABORT
294 __chkabort();
295 #else
296 if (Errno() == EINTR)
297 exit(0);
298 #endif
300 /* Get the current time... */
301 gettimeofday (&now, (struct timezone *)0);
302 cur_time = now.tv_sec;
304 /* We probably have a bad file descriptor. Figure out which one.
305 When we find it, call the reaper function on it, which will
306 maybe make it go away, and then try again. */
307 if (count < 0) {
308 struct timeval t0;
309 omapi_io_object_t *prev = (omapi_io_object_t *)0;
310 io = (omapi_io_object_t *)0;
311 if (omapi_io_states.next)
312 omapi_io_reference (&io, omapi_io_states.next, MDL);
314 while (io) {
315 omapi_object_t *obj;
316 FD_ZERO (&r);
317 FD_ZERO (&w);
318 t0.tv_sec = t0.tv_usec = 0;
320 if (io -> readfd && io -> inner &&
321 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
322 FD_SET (desc, &r);
323 #if 0
324 log_error ("read check: %d %lx %lx", max,
325 (unsigned long)r.fds_bits [0],
326 (unsigned long)w.fds_bits [0]);
327 #endif
328 count = select (desc + 1, &r, &w, &x, &t0);
329 bogon:
330 if (count < 0) {
331 log_error ("Bad descriptor %d.", desc);
332 for (obj = (omapi_object_t *)io;
333 obj -> outer;
334 obj = obj -> outer)
336 for (; obj; obj = obj -> inner) {
337 omapi_value_t *ov;
338 int len;
339 const char *s;
340 ov = (omapi_value_t *)0;
341 omapi_get_value_str (obj,
342 (omapi_object_t *)0,
343 "name", &ov);
344 if (ov && ov -> value &&
345 (ov -> value -> type ==
346 omapi_datatype_string)) {
347 s = (char *)
348 ov -> value -> u.buffer.value;
349 len = ov -> value -> u.buffer.len;
350 } else {
351 s = "";
352 len = 0;
354 log_error ("Object %lx %s%s%.*s",
355 (unsigned long)obj,
356 obj -> type -> name,
357 len ? " " : "",
358 len, s);
359 if (len)
360 omapi_value_dereference (&ov, MDL);
362 (*(io -> reaper)) (io -> inner);
363 if (prev) {
364 omapi_io_dereference (&prev -> next, MDL);
365 if (io -> next)
366 omapi_io_reference (&prev -> next,
367 io -> next, MDL);
368 } else {
369 omapi_io_dereference
370 (&omapi_io_states.next, MDL);
371 if (io -> next)
372 omapi_io_reference
373 (&omapi_io_states.next,
374 io -> next, MDL);
376 omapi_io_dereference (&io, MDL);
377 goto again;
381 FD_ZERO (&r);
382 FD_ZERO (&w);
383 t0.tv_sec = t0.tv_usec = 0;
385 /* Same deal for write fdets. */
386 if (io -> writefd && io -> inner &&
387 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
388 FD_SET (desc, &w);
389 count = select (desc + 1, &r, &w, &x, &t0);
390 if (count < 0)
391 goto bogon;
393 if (prev)
394 omapi_io_dereference (&prev, MDL);
395 omapi_io_reference (&prev, io, MDL);
396 omapi_io_dereference (&io, MDL);
397 if (prev -> next)
398 omapi_io_reference (&io, prev -> next, MDL);
400 if (prev)
401 omapi_io_dereference (&prev, MDL);
405 for (io = omapi_io_states.next; io; io = io -> next) {
406 if (!io -> inner)
407 continue;
408 omapi_object_reference (&tmp, io -> inner, MDL);
409 /* Check for a read descriptor, and if there is one,
410 see if we got input on that socket. */
411 if (io -> readfd &&
412 (desc = (*(io -> readfd)) (tmp)) >= 0) {
413 if (FD_ISSET (desc, &r))
414 ((*(io -> reader)) (tmp));
417 /* Same deal for write descriptors. */
418 if (io -> writefd &&
419 (desc = (*(io -> writefd)) (tmp)) >= 0)
421 if (FD_ISSET (desc, &w))
422 ((*(io -> writer)) (tmp));
424 omapi_object_dereference (&tmp, MDL);
427 /* Now check for I/O handles that are no longer valid,
428 and remove them from the list. */
429 prev = (omapi_io_object_t *)0;
430 for (io = omapi_io_states.next; io; io = io -> next) {
431 if (io -> reaper) {
432 if (!io -> inner ||
433 ((*(io -> reaper)) (io -> inner) !=
434 ISC_R_SUCCESS)) {
435 omapi_io_object_t *tmp =
436 (omapi_io_object_t *)0;
437 /* Save a reference to the next
438 pointer, if there is one. */
439 if (io -> next)
440 omapi_io_reference (&tmp,
441 io -> next, MDL);
442 if (prev) {
443 omapi_io_dereference (&prev -> next,
444 MDL);
445 if (tmp)
446 omapi_io_reference
447 (&prev -> next,
448 tmp, MDL);
449 } else {
450 omapi_io_dereference
451 (&omapi_io_states.next, MDL);
452 if (tmp)
453 omapi_io_reference
454 (&omapi_io_states.next,
455 tmp, MDL);
456 else
457 omapi_signal_in
458 ((omapi_object_t *)
459 &omapi_io_states,
460 "ready");
462 if (tmp)
463 omapi_io_dereference (&tmp, MDL);
466 prev = io;
469 return ISC_R_SUCCESS;
472 isc_result_t omapi_io_set_value (omapi_object_t *h,
473 omapi_object_t *id,
474 omapi_data_string_t *name,
475 omapi_typed_data_t *value)
477 if (h -> type != omapi_type_io_object)
478 return ISC_R_INVALIDARG;
480 if (h -> inner && h -> inner -> type -> set_value)
481 return (*(h -> inner -> type -> set_value))
482 (h -> inner, id, name, value);
483 return ISC_R_NOTFOUND;
486 isc_result_t omapi_io_get_value (omapi_object_t *h,
487 omapi_object_t *id,
488 omapi_data_string_t *name,
489 omapi_value_t **value)
491 if (h -> type != omapi_type_io_object)
492 return ISC_R_INVALIDARG;
494 if (h -> inner && h -> inner -> type -> get_value)
495 return (*(h -> inner -> type -> get_value))
496 (h -> inner, id, name, value);
497 return ISC_R_NOTFOUND;
500 /* omapi_io_destroy (object, MDL);
502 * Find the requsted IO [object] and remove it from the list of io
503 * states, causing the cleanup functions to destroy it. Note that we must
504 * hold a reference on the object while moving its ->next reference and
505 * removing the reference in the chain to the target object...otherwise it
506 * may be cleaned up from under us.
508 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
510 omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
512 if (h -> type != omapi_type_io_object)
513 return ISC_R_INVALIDARG;
515 /* remove from the list of I/O states */
516 for (p = omapi_io_states.next; p; p = p -> next) {
517 if (p == (omapi_io_object_t *)h) {
518 omapi_io_reference (&obj, p, MDL);
520 if (last)
521 holder = &last -> next;
522 else
523 holder = &omapi_io_states.next;
525 omapi_io_dereference (holder, MDL);
527 if (obj -> next) {
528 omapi_io_reference (holder, obj -> next, MDL);
529 omapi_io_dereference (&obj -> next, MDL);
532 return omapi_io_dereference (&obj, MDL);
534 last = p;
537 return ISC_R_NOTFOUND;
540 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
541 const char *name, va_list ap)
543 if (h -> type != omapi_type_io_object)
544 return ISC_R_INVALIDARG;
546 if (h -> inner && h -> inner -> type -> signal_handler)
547 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
548 name, ap);
549 return ISC_R_NOTFOUND;
552 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
553 omapi_object_t *id,
554 omapi_object_t *i)
556 if (i -> type != omapi_type_io_object)
557 return ISC_R_INVALIDARG;
559 if (i -> inner && i -> inner -> type -> stuff_values)
560 return (*(i -> inner -> type -> stuff_values)) (c, id,
561 i -> inner);
562 return ISC_R_SUCCESS;
565 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
566 const char *name, va_list ap)
568 omapi_waiter_object_t *waiter;
570 if (h -> type != omapi_type_waiter)
571 return ISC_R_INVALIDARG;
573 if (!strcmp (name, "ready")) {
574 waiter = (omapi_waiter_object_t *)h;
575 waiter -> ready = 1;
576 waiter -> waitstatus = ISC_R_SUCCESS;
577 return ISC_R_SUCCESS;
580 if (!strcmp (name, "status")) {
581 waiter = (omapi_waiter_object_t *)h;
582 waiter -> ready = 1;
583 waiter -> waitstatus = va_arg (ap, isc_result_t);
584 return ISC_R_SUCCESS;
587 if (!strcmp (name, "disconnect")) {
588 waiter = (omapi_waiter_object_t *)h;
589 waiter -> ready = 1;
590 waiter -> waitstatus = ISC_R_CONNRESET;
591 return ISC_R_SUCCESS;
594 if (h -> inner && h -> inner -> type -> signal_handler)
595 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
596 name, ap);
597 return ISC_R_NOTFOUND;
600 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
601 void *),
602 void *p)
604 omapi_io_object_t *io;
605 isc_result_t status;
607 for (io = omapi_io_states.next; io; io = io -> next) {
608 if (io -> inner) {
609 status = (*func) (io -> inner, p);
610 if (status != ISC_R_SUCCESS)
611 return status;
614 return ISC_R_SUCCESS;