6
* Copyright (c) 2004,2007-2008 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.
23
* Redwood City, CA 94063
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''.
37
#include <omapip/omapip_p.h>
40
static omapi_io_object_t omapi_io_states;
41
struct timeval cur_tv;
43
struct eventqueue *rw_queue_empty;
45
OMAPI_OBJECT_ALLOC (omapi_io,
46
omapi_io_object_t, omapi_type_io_object)
47
OMAPI_OBJECT_ALLOC (omapi_waiter,
48
omapi_waiter_object_t, omapi_type_waiter)
51
register_eventhandler(struct eventqueue **queue, void (*handler)(void *))
53
struct eventqueue *t, *q;
55
/* traverse to end of list */
57
for (q = *queue ; q ; q = q->next) {
58
if (q->handler == handler)
59
return; /* handler already registered */
63
q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL));
65
log_fatal("register_eventhandler: no memory!");
66
memset(q, 0, sizeof *q);
76
unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *))
78
struct eventqueue *t, *q;
80
/* traverse to end of list */
82
for (q = *queue ; q ; q = q->next) {
83
if (q->handler == handler) {
88
dfree(q, MDL); /* Don't access q after this!*/
97
trigger_event(struct eventqueue **queue)
101
for (q=*queue ; q ; q=q->next) {
108
/* Register an I/O handle so that we can do asynchronous I/O on it. */
110
isc_result_t omapi_register_io_object (omapi_object_t *h,
111
int (*readfd) (omapi_object_t *),
112
int (*writefd) (omapi_object_t *),
113
isc_result_t (*reader)
115
isc_result_t (*writer)
117
isc_result_t (*reaper)
121
omapi_io_object_t *obj, *p;
123
/* omapi_io_states is a static object. If its reference count
124
is zero, this is the first I/O handle to be registered, so
125
we need to initialize it. Because there is no inner or outer
126
pointer on this object, and we're setting its refcnt to 1, it
127
will never be freed. */
128
if (!omapi_io_states.refcnt) {
129
omapi_io_states.refcnt = 1;
130
omapi_io_states.type = omapi_type_io_object;
133
obj = (omapi_io_object_t *)0;
134
status = omapi_io_allocate (&obj, MDL);
135
if (status != ISC_R_SUCCESS)
138
status = omapi_object_reference (&obj -> inner, h, MDL);
139
if (status != ISC_R_SUCCESS) {
140
omapi_io_dereference (&obj, MDL);
144
status = omapi_object_reference (&h -> outer,
145
(omapi_object_t *)obj, MDL);
146
if (status != ISC_R_SUCCESS) {
147
omapi_io_dereference (&obj, MDL);
151
/* Find the last I/O state, if there are any. */
152
for (p = omapi_io_states.next;
153
p && p -> next; p = p -> next)
156
omapi_io_reference (&p -> next, obj, MDL);
158
omapi_io_reference (&omapi_io_states.next, obj, MDL);
160
obj -> readfd = readfd;
161
obj -> writefd = writefd;
162
obj -> reader = reader;
163
obj -> writer = writer;
164
obj -> reaper = reaper;
166
omapi_io_dereference(&obj, MDL);
167
return ISC_R_SUCCESS;
170
isc_result_t omapi_unregister_io_object (omapi_object_t *h)
172
omapi_io_object_t *p, *obj, *last, *ph;
174
if (!h -> outer || h -> outer -> type != omapi_type_io_object)
175
return ISC_R_INVALIDARG;
176
obj = (omapi_io_object_t *)h -> outer;
177
ph = (omapi_io_object_t *)0;
178
omapi_io_reference (&ph, obj, MDL);
180
/* remove from the list of I/O states */
181
last = &omapi_io_states;
182
for (p = omapi_io_states.next; p; p = p -> next) {
184
omapi_io_dereference (&last -> next, MDL);
185
omapi_io_reference (&last -> next, p -> next, MDL);
191
omapi_io_dereference (&obj -> next, MDL);
194
if (obj -> outer -> inner == (omapi_object_t *)obj)
195
omapi_object_dereference (&obj -> outer -> inner,
197
omapi_object_dereference (&obj -> outer, MDL);
199
omapi_object_dereference (&obj -> inner, MDL);
200
omapi_object_dereference (&h -> outer, MDL);
201
omapi_io_dereference (&ph, MDL);
202
return ISC_R_SUCCESS;
205
isc_result_t omapi_dispatch (struct timeval *t)
207
return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
211
isc_result_t omapi_wait_for_completion (omapi_object_t *object,
215
omapi_waiter_object_t *waiter;
216
omapi_object_t *inner;
219
waiter = (omapi_waiter_object_t *)0;
220
status = omapi_waiter_allocate (&waiter, MDL);
221
if (status != ISC_R_SUCCESS)
224
/* Paste the waiter object onto the inner object we're
226
for (inner = object; inner -> inner; inner = inner -> inner)
229
status = omapi_object_reference (&waiter -> outer, inner, MDL);
230
if (status != ISC_R_SUCCESS) {
231
omapi_waiter_dereference (&waiter, MDL);
235
status = omapi_object_reference (&inner -> inner,
236
(omapi_object_t *)waiter,
238
if (status != ISC_R_SUCCESS) {
239
omapi_waiter_dereference (&waiter, MDL);
243
waiter = (omapi_waiter_object_t *)0;
246
status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
247
if (status != ISC_R_SUCCESS)
249
} while (!waiter || !waiter -> ready);
251
if (waiter -> outer) {
252
if (waiter -> outer -> inner) {
253
omapi_object_dereference (&waiter -> outer -> inner,
256
omapi_object_reference
257
(&waiter -> outer -> inner,
258
waiter -> inner, MDL);
260
omapi_object_dereference (&waiter -> outer, MDL);
263
omapi_object_dereference (&waiter -> inner, MDL);
265
status = waiter -> waitstatus;
266
omapi_waiter_dereference (&waiter, MDL);
270
isc_result_t omapi_one_dispatch (omapi_object_t *wo,
273
fd_set r, w, x, rr, ww, xx;
277
struct timeval now, to;
278
omapi_io_object_t *io, *prev, *next;
279
omapi_waiter_object_t *waiter;
280
omapi_object_t *tmp = (omapi_object_t *)0;
282
if (!wo || wo -> type != omapi_type_waiter)
283
waiter = (omapi_waiter_object_t *)0;
285
waiter = (omapi_waiter_object_t *)wo;
289
/* First, see if the timeout has expired, and if so return. */
291
gettimeofday (&now, (struct timezone *)0);
292
cur_tv.tv_sec = now.tv_sec;
293
cur_tv.tv_usec = now.tv_usec;
294
if (now.tv_sec > t -> tv_sec ||
295
(now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
296
return ISC_R_TIMEDOUT;
298
/* We didn't time out, so figure out how long until
300
to.tv_sec = t -> tv_sec - now.tv_sec;
301
to.tv_usec = t -> tv_usec - now.tv_usec;
302
if (to.tv_usec < 0) {
303
to.tv_usec += 1000000;
307
/* It is possible for the timeout to get set larger than
308
the largest time select() is willing to accept.
309
Restricting the timeout to a maximum of one day should
310
work around this. -DPN. (Ref: Bug #416) */
311
if (to.tv_sec > (60 * 60 * 24))
312
to.tv_sec = 60 * 60 * 24;
315
/* If the object we're waiting on has reached completion,
317
if (waiter && waiter -> ready)
318
return ISC_R_SUCCESS;
321
/* If we have no I/O state, we can't proceed. */
322
if (!(io = omapi_io_states.next))
325
/* Set up the read and write masks. */
329
for (; io; io = io -> next) {
330
/* Check for a read socket. If we shouldn't be
331
trying to read for this I/O object, either there
332
won't be a readfd function, or it'll return -1. */
333
if (io -> readfd && io -> inner &&
334
(desc = (*(io -> readfd)) (io -> inner)) >= 0) {
340
/* Same deal for write fdets. */
341
if (io -> writefd && io -> inner &&
342
(desc = (*(io -> writefd)) (io -> inner)) >= 0) {
349
/* poll if all reader are dry */
357
count = select(max + 1, &r, &w, &x, &now);
360
trigger_event(&rw_queue_empty);
361
/* Wait for a packet or a timeout... XXX */
362
count = select(max + 1, &rr, &ww, &xx, t ? &to : NULL);
365
/* Get the current time... */
366
gettimeofday (&cur_tv, (struct timezone *)0);
368
/* We probably have a bad file descriptor. Figure out which one.
369
When we find it, call the reaper function on it, which will
370
maybe make it go away, and then try again. */
373
omapi_io_object_t *prev = (omapi_io_object_t *)0;
374
io = (omapi_io_object_t *)0;
375
if (omapi_io_states.next)
376
omapi_io_reference (&io, omapi_io_states.next, MDL);
382
t0.tv_sec = t0.tv_usec = 0;
384
if (io -> readfd && io -> inner &&
385
(desc = (*(io -> readfd)) (io -> inner)) >= 0) {
387
count = select (desc + 1, &r, &w, &x, &t0);
390
log_error ("Bad descriptor %d.", desc);
391
for (obj = (omapi_object_t *)io;
395
for (; obj; obj = obj -> inner) {
399
ov = (omapi_value_t *)0;
400
omapi_get_value_str (obj,
403
if (ov && ov -> value &&
404
(ov -> value -> type ==
405
omapi_datatype_string)) {
407
ov -> value -> u.buffer.value;
408
len = ov -> value -> u.buffer.len;
413
log_error ("Object %lx %s%s%.*s",
419
omapi_value_dereference (&ov, MDL);
421
(*(io -> reaper)) (io -> inner);
423
omapi_io_dereference (&prev -> next, MDL);
425
omapi_io_reference (&prev -> next,
429
(&omapi_io_states.next, MDL);
432
(&omapi_io_states.next,
435
omapi_io_dereference (&io, MDL);
442
t0.tv_sec = t0.tv_usec = 0;
444
/* Same deal for write fdets. */
445
if (io -> writefd && io -> inner &&
446
(desc = (*(io -> writefd)) (io -> inner)) >= 0) {
448
count = select (desc + 1, &r, &w, &x, &t0);
453
omapi_io_dereference (&prev, MDL);
454
omapi_io_reference (&prev, io, MDL);
455
omapi_io_dereference (&io, MDL);
457
omapi_io_reference (&io, prev -> next, MDL);
460
omapi_io_dereference (&prev, MDL);
464
for (io = omapi_io_states.next; io; io = io -> next) {
467
omapi_object_reference (&tmp, io -> inner, MDL);
468
/* Check for a read descriptor, and if there is one,
469
see if we got input on that socket. */
471
(desc = (*(io -> readfd)) (tmp)) >= 0) {
472
if (FD_ISSET (desc, &r))
473
((*(io -> reader)) (tmp));
476
/* Same deal for write descriptors. */
478
(desc = (*(io -> writefd)) (tmp)) >= 0)
480
if (FD_ISSET (desc, &w))
481
((*(io -> writer)) (tmp));
483
omapi_object_dereference (&tmp, MDL);
486
/* Now check for I/O handles that are no longer valid,
487
and remove them from the list. */
490
if (omapi_io_states.next != NULL) {
491
omapi_io_reference(&io, omapi_io_states.next, MDL);
494
if ((io->inner == NULL) ||
495
((io->reaper != NULL) &&
496
((io->reaper)(io->inner) != ISC_R_SUCCESS)))
499
omapi_io_object_t *tmp = NULL;
500
/* Save a reference to the next
501
pointer, if there is one. */
502
if (io->next != NULL) {
503
omapi_io_reference(&tmp, io->next, MDL);
504
omapi_io_dereference(&io->next, MDL);
507
omapi_io_dereference(&prev->next, MDL);
509
omapi_io_reference(&prev->next,
512
omapi_io_dereference(&omapi_io_states.next,
516
(&omapi_io_states.next,
525
omapi_io_dereference(&tmp, MDL);
530
omapi_io_dereference(&prev, MDL);
532
omapi_io_reference(&prev, io, MDL);
539
* But using our reference counting voodoo.
542
if (io->next != NULL) {
543
omapi_io_reference(&next, io->next, MDL);
545
omapi_io_dereference(&io, MDL);
547
omapi_io_reference(&io, next, MDL);
548
omapi_io_dereference(&next, MDL);
552
omapi_io_dereference(&prev, MDL);
555
return ISC_R_SUCCESS;
558
isc_result_t omapi_io_set_value (omapi_object_t *h,
560
omapi_data_string_t *name,
561
omapi_typed_data_t *value)
563
if (h -> type != omapi_type_io_object)
564
return ISC_R_INVALIDARG;
566
if (h -> inner && h -> inner -> type -> set_value)
567
return (*(h -> inner -> type -> set_value))
568
(h -> inner, id, name, value);
569
return ISC_R_NOTFOUND;
572
isc_result_t omapi_io_get_value (omapi_object_t *h,
574
omapi_data_string_t *name,
575
omapi_value_t **value)
577
if (h -> type != omapi_type_io_object)
578
return ISC_R_INVALIDARG;
580
if (h -> inner && h -> inner -> type -> get_value)
581
return (*(h -> inner -> type -> get_value))
582
(h -> inner, id, name, value);
583
return ISC_R_NOTFOUND;
586
/* omapi_io_destroy (object, MDL);
588
* Find the requested IO [object] and remove it from the list of io
589
* states, causing the cleanup functions to destroy it. Note that we must
590
* hold a reference on the object while moving its ->next reference and
591
* removing the reference in the chain to the target object...otherwise it
592
* may be cleaned up from under us.
594
isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
596
omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
598
if (h -> type != omapi_type_io_object)
599
return ISC_R_INVALIDARG;
601
/* remove from the list of I/O states */
602
for (p = omapi_io_states.next; p; p = p -> next) {
603
if (p == (omapi_io_object_t *)h) {
604
omapi_io_reference (&obj, p, MDL);
607
holder = &last -> next;
609
holder = &omapi_io_states.next;
611
omapi_io_dereference (holder, MDL);
614
omapi_io_reference (holder, obj -> next, MDL);
615
omapi_io_dereference (&obj -> next, MDL);
618
return omapi_io_dereference (&obj, MDL);
623
return ISC_R_NOTFOUND;
626
isc_result_t omapi_io_signal_handler (omapi_object_t *h,
627
const char *name, va_list ap)
629
if (h -> type != omapi_type_io_object)
630
return ISC_R_INVALIDARG;
632
if (h -> inner && h -> inner -> type -> signal_handler)
633
return (*(h -> inner -> type -> signal_handler)) (h -> inner,
635
return ISC_R_NOTFOUND;
638
isc_result_t omapi_io_stuff_values (omapi_object_t *c,
642
if (i -> type != omapi_type_io_object)
643
return ISC_R_INVALIDARG;
645
if (i -> inner && i -> inner -> type -> stuff_values)
646
return (*(i -> inner -> type -> stuff_values)) (c, id,
648
return ISC_R_SUCCESS;
651
isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
652
const char *name, va_list ap)
654
omapi_waiter_object_t *waiter;
656
if (h -> type != omapi_type_waiter)
657
return ISC_R_INVALIDARG;
659
if (!strcmp (name, "ready")) {
660
waiter = (omapi_waiter_object_t *)h;
662
waiter -> waitstatus = ISC_R_SUCCESS;
663
return ISC_R_SUCCESS;
666
if (!strcmp (name, "status")) {
667
waiter = (omapi_waiter_object_t *)h;
669
waiter -> waitstatus = va_arg (ap, isc_result_t);
670
return ISC_R_SUCCESS;
673
if (!strcmp (name, "disconnect")) {
674
waiter = (omapi_waiter_object_t *)h;
676
waiter -> waitstatus = ISC_R_CONNRESET;
677
return ISC_R_SUCCESS;
680
if (h -> inner && h -> inner -> type -> signal_handler)
681
return (*(h -> inner -> type -> signal_handler)) (h -> inner,
683
return ISC_R_NOTFOUND;
686
isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
690
omapi_io_object_t *io;
693
for (io = omapi_io_states.next; io; io = io -> next) {
695
status = (*func) (io -> inner, p);
696
if (status != ISC_R_SUCCESS)
700
return ISC_R_SUCCESS;