6 * Copyright (c) 1999-2000 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
44 #include <omapip/omapip_p.h>
46 static omapi_io_object_t omapi_io_states;
49 OMAPI_OBJECT_ALLOC (omapi_io,
50 omapi_io_object_t, omapi_type_io_object)
51 OMAPI_OBJECT_ALLOC (omapi_waiter,
52 omapi_waiter_object_t, omapi_type_waiter)
54 /* Register an I/O handle so that we can do asynchronous I/O on it. */
56 isc_result_t omapi_register_io_object (omapi_object_t *h,
57 int (*readfd) (omapi_object_t *),
58 int (*writefd) (omapi_object_t *),
59 isc_result_t (*reader)
61 isc_result_t (*writer)
63 isc_result_t (*reaper)
67 omapi_io_object_t *obj, *p;
69 /* omapi_io_states is a static object. If its reference count
70 is zero, this is the first I/O handle to be registered, so
71 we need to initialize it. Because there is no inner or outer
72 pointer on this object, and we're setting its refcnt to 1, it
73 will never be freed. */
74 if (!omapi_io_states.refcnt) {
75 omapi_io_states.refcnt = 1;
76 omapi_io_states.type = omapi_type_io_object;
79 obj = (omapi_io_object_t *)0;
80 status = omapi_io_allocate (&obj, MDL);
81 if (status != ISC_R_SUCCESS)
84 status = omapi_object_reference (&obj -> inner, h, MDL);
85 if (status != ISC_R_SUCCESS) {
86 omapi_io_dereference (&obj, MDL);
90 status = omapi_object_reference (&h -> outer,
91 (omapi_object_t *)obj, MDL);
92 if (status != ISC_R_SUCCESS) {
93 omapi_io_dereference (&obj, MDL);
97 /* Find the last I/O state, if there are any. */
98 for (p = omapi_io_states.next;
99 p && p -> next; p = p -> next)
102 omapi_io_reference (&p -> next, obj, MDL);
104 omapi_io_reference (&omapi_io_states.next, obj, MDL);
106 obj -> readfd = readfd;
107 obj -> writefd = writefd;
108 obj -> reader = reader;
109 obj -> writer = writer;
110 obj -> reaper = reaper;
111 return ISC_R_SUCCESS;
114 isc_result_t omapi_unregister_io_object (omapi_object_t *h)
116 omapi_io_object_t *p, *obj, *last, *ph;
118 if (!h -> outer || h -> outer -> type != omapi_type_io_object)
119 return ISC_R_INVALIDARG;
120 obj = (omapi_io_object_t *)h -> outer;
121 ph = (omapi_io_object_t *)0;
122 omapi_io_reference (&ph, obj, MDL);
124 /* remove from the list of I/O states */
125 last = &omapi_io_states;
126 for (p = omapi_io_states.next; p; p = p -> next) {
128 omapi_io_dereference (&last -> next, MDL);
129 omapi_io_reference (&last -> next, p -> next, MDL);
135 omapi_io_dereference (&obj -> next, MDL);
138 if (obj -> outer -> inner == (omapi_object_t *)obj)
139 omapi_object_dereference (&obj -> outer -> inner,
141 omapi_object_dereference (&obj -> outer, MDL);
143 omapi_object_dereference (&obj -> inner, MDL);
144 omapi_object_dereference (&h -> outer, MDL);
145 omapi_io_dereference (&ph, MDL);
146 return ISC_R_SUCCESS;
149 isc_result_t omapi_dispatch (struct timeval *t)
151 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
155 isc_result_t omapi_wait_for_completion (omapi_object_t *object,
159 omapi_waiter_object_t *waiter;
160 omapi_object_t *inner;
163 waiter = (omapi_waiter_object_t *)0;
164 status = omapi_waiter_allocate (&waiter, MDL);
165 if (status != ISC_R_SUCCESS)
168 /* Paste the waiter object onto the inner object we're
170 for (inner = object; inner -> inner; inner = inner -> inner)
173 status = omapi_object_reference (&waiter -> outer, inner, MDL);
174 if (status != ISC_R_SUCCESS) {
175 omapi_waiter_dereference (&waiter, MDL);
179 status = omapi_object_reference (&inner -> inner,
180 (omapi_object_t *)waiter,
182 if (status != ISC_R_SUCCESS) {
183 omapi_waiter_dereference (&waiter, MDL);
187 waiter = (omapi_waiter_object_t *)0;
190 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
191 if (status != ISC_R_SUCCESS)
193 } while (!waiter || !waiter -> ready);
195 if (waiter -> outer) {
196 if (waiter -> outer -> inner) {
197 omapi_object_dereference (&waiter -> outer -> inner,
200 omapi_object_reference
201 (&waiter -> outer -> inner,
202 waiter -> inner, MDL);
204 omapi_object_dereference (&waiter -> outer, MDL);
207 omapi_object_dereference (&waiter -> inner, MDL);
209 status = waiter -> waitstatus;
210 omapi_waiter_dereference (&waiter, MDL);
214 isc_result_t omapi_one_dispatch (omapi_object_t *wo,
221 struct timeval now, to;
222 omapi_io_object_t *io, *prev;
224 omapi_waiter_object_t *waiter;
225 omapi_object_t *tmp = (omapi_object_t *)0;
227 if (!wo || wo -> type != omapi_type_waiter)
228 waiter = (omapi_waiter_object_t *)0;
230 waiter = (omapi_waiter_object_t *)wo;
234 /* First, see if the timeout has expired, and if so return. */
236 gettimeofday (&now, (struct timezone *)0);
237 cur_time = now.tv_sec;
238 if (now.tv_sec > t -> tv_sec ||
239 (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
240 return ISC_R_TIMEDOUT;
242 /* We didn't time out, so figure out how long until
244 to.tv_sec = t -> tv_sec - now.tv_sec;
245 to.tv_usec = t -> tv_usec - now.tv_usec;
246 if (to.tv_usec < 0) {
247 to.tv_usec += 1000000;
251 /* It is possible for the timeout to get set larger than
252 the largest time select() is willing to accept.
253 Restricting the timeout to a maximum of one day should
254 work around this. -DPN. (Ref: Bug #416) */
255 if (to.tv_sec > (60 * 60 * 24))
256 to.tv_sec = 60 * 60 * 24;
259 /* If the object we're waiting on has reached completion,
261 if (waiter && waiter -> ready)
262 return ISC_R_SUCCESS;
265 /* If we have no I/O state, we can't proceed. */
266 if (!(io = omapi_io_states.next))
269 /* Set up the read and write masks. */
273 for (; io; io = io -> next) {
274 /* Check for a read socket. If we shouldn't be
275 trying to read for this I/O object, either there
276 won't be a readfd function, or it'll return -1. */
277 if (io -> readfd && io -> inner &&
278 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
284 /* Same deal for write fdets. */
285 if (io -> writefd && io -> inner &&
286 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
293 /* Wait for a packet or a timeout... XXX */
295 #if defined (__linux__)
296 #define fds_bits __fds_bits
298 log_error ("dispatch: %d %lx %lx", max,
299 (unsigned long)r.fds_bits [0],
300 (unsigned long)w.fds_bits [0]);
302 count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0);
304 /* Get the current time... */
305 gettimeofday (&now, (struct timezone *)0);
306 cur_time = now.tv_sec;
308 /* We probably have a bad file descriptor. Figure out which one.
309 When we find it, call the reaper function on it, which will
310 maybe make it go away, and then try again. */
313 omapi_io_object_t *prev = (omapi_io_object_t *)0;
314 io = (omapi_io_object_t *)0;
315 if (omapi_io_states.next)
316 omapi_io_reference (&io, omapi_io_states.next, MDL);
322 t0.tv_sec = t0.tv_usec = 0;
324 if (io -> readfd && io -> inner &&
325 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
328 log_error ("read check: %d %lx %lx", max,
329 (unsigned long)r.fds_bits [0],
330 (unsigned long)w.fds_bits [0]);
332 count = select (desc + 1, &r, &w, &x, &t0);
335 log_error ("Bad descriptor %d.", desc);
336 for (obj = (omapi_object_t *)io;
340 for (; obj; obj = obj -> inner) {
344 ov = (omapi_value_t *)0;
345 omapi_get_value_str (obj,
348 if (ov && ov -> value &&
349 (ov -> value -> type ==
350 omapi_datatype_string)) {
352 ov -> value -> u.buffer.value;
353 len = ov -> value -> u.buffer.len;
358 log_error ("Object %lx %s%s%.*s",
364 omapi_value_dereference (&ov, MDL);
366 status = (*(io -> reaper)) (io -> inner);
368 omapi_io_dereference (&prev -> next, MDL);
370 omapi_io_reference (&prev -> next,
374 (&omapi_io_states.next, MDL);
377 (&omapi_io_states.next,
380 omapi_io_dereference (&io, MDL);
387 t0.tv_sec = t0.tv_usec = 0;
389 /* Same deal for write fdets. */
390 if (io -> writefd && io -> inner &&
391 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
393 count = select (desc + 1, &r, &w, &x, &t0);
398 omapi_io_dereference (&prev, MDL);
399 omapi_io_reference (&prev, io, MDL);
400 omapi_io_dereference (&io, MDL);
402 omapi_io_reference (&io, prev -> next, MDL);
405 omapi_io_dereference (&prev, MDL);
409 for (io = omapi_io_states.next; io; io = io -> next) {
412 omapi_object_reference (&tmp, io -> inner, MDL);
413 /* Check for a read descriptor, and if there is one,
414 see if we got input on that socket. */
416 (desc = (*(io -> readfd)) (tmp)) >= 0) {
417 if (FD_ISSET (desc, &r))
418 status = ((*(io -> reader)) (tmp));
419 /* XXX what to do with status? */
422 /* Same deal for write descriptors. */
424 (desc = (*(io -> writefd)) (tmp)) >= 0)
426 if (FD_ISSET (desc, &w))
427 status = ((*(io -> writer)) (tmp));
428 /* XXX what to do with status? */
430 omapi_object_dereference (&tmp, MDL);
433 /* Now check for I/O handles that are no longer valid,
434 and remove them from the list. */
435 prev = (omapi_io_object_t *)0;
436 for (io = omapi_io_states.next; io; io = io -> next) {
439 status = (*(io -> reaper)) (io -> inner);
440 if (!io -> inner || status != ISC_R_SUCCESS) {
441 omapi_io_object_t *tmp =
442 (omapi_io_object_t *)0;
443 /* Save a reference to the next
444 pointer, if there is one. */
446 omapi_io_reference (&tmp,
449 omapi_io_dereference (&prev -> next,
457 (&omapi_io_states.next, MDL);
460 (&omapi_io_states.next,
469 omapi_io_dereference (&tmp, MDL);
475 return ISC_R_SUCCESS;
478 isc_result_t omapi_io_set_value (omapi_object_t *h,
480 omapi_data_string_t *name,
481 omapi_typed_data_t *value)
483 if (h -> type != omapi_type_io_object)
484 return ISC_R_INVALIDARG;
486 if (h -> inner && h -> inner -> type -> set_value)
487 return (*(h -> inner -> type -> set_value))
488 (h -> inner, id, name, value);
489 return ISC_R_NOTFOUND;
492 isc_result_t omapi_io_get_value (omapi_object_t *h,
494 omapi_data_string_t *name,
495 omapi_value_t **value)
497 if (h -> type != omapi_type_io_object)
498 return ISC_R_INVALIDARG;
500 if (h -> inner && h -> inner -> type -> get_value)
501 return (*(h -> inner -> type -> get_value))
502 (h -> inner, id, name, value);
503 return ISC_R_NOTFOUND;
506 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
508 omapi_io_object_t *obj, *p, *last;
510 if (h -> type != omapi_type_io_object)
511 return ISC_R_INVALIDARG;
513 obj = (omapi_io_object_t *)h;
515 /* remove from the list of I/O states */
516 for (p = omapi_io_states.next; p; p = p -> next) {
518 omapi_io_dereference (&last -> next, MDL);
519 omapi_io_reference (&last -> next, p -> next, MDL);
520 omapi_io_dereference (&p, MDL);
526 return ISC_R_SUCCESS;
529 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
530 const char *name, va_list ap)
532 if (h -> type != omapi_type_io_object)
533 return ISC_R_INVALIDARG;
535 if (h -> inner && h -> inner -> type -> signal_handler)
536 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
538 return ISC_R_NOTFOUND;
541 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
545 if (i -> type != omapi_type_io_object)
546 return ISC_R_INVALIDARG;
548 if (i -> inner && i -> inner -> type -> stuff_values)
549 return (*(i -> inner -> type -> stuff_values)) (c, id,
551 return ISC_R_SUCCESS;
554 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
555 const char *name, va_list ap)
557 omapi_waiter_object_t *waiter;
559 if (h -> type != omapi_type_waiter)
560 return ISC_R_INVALIDARG;
562 if (!strcmp (name, "ready")) {
563 waiter = (omapi_waiter_object_t *)h;
565 waiter -> waitstatus = ISC_R_SUCCESS;
566 return ISC_R_SUCCESS;
569 if (!strcmp (name, "status")) {
570 waiter = (omapi_waiter_object_t *)h;
572 waiter -> waitstatus = va_arg (ap, isc_result_t);
573 return ISC_R_SUCCESS;
576 if (!strcmp (name, "disconnect")) {
577 waiter = (omapi_waiter_object_t *)h;
579 waiter -> waitstatus = ISC_R_CONNRESET;
580 return ISC_R_SUCCESS;
583 if (h -> inner && h -> inner -> type -> signal_handler)
584 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
586 return ISC_R_NOTFOUND;
589 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
593 omapi_io_object_t *io;
596 for (io = omapi_io_states.next; io; io = io -> next) {
598 status = (*func) (io -> inner, p);
599 if (status != ISC_R_SUCCESS)
603 return ISC_R_SUCCESS;