]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/dispatch.c
Moved hash.c from libdhcp to libomapi, in anticipation of moving the
[thirdparty/dhcp.git] / omapip / dispatch.c
CommitLineData
61b844bf
TL
1/* dispatch.c
2
3 I/O dispatcher. */
4
5/*
49733f31
TL
6 * Copyright (c) 1999-2000 Internet Software Consortium.
7 * All rights reserved.
61b844bf 8 *
49733f31
TL
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
61b844bf 12 *
49733f31
TL
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.
61b844bf 21 *
49733f31
TL
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
34 * SUCH DAMAGE.
35 *
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''.
61b844bf
TL
42 */
43
6a4c4be8 44#include <omapip/omapip_p.h>
61b844bf
TL
45
46static omapi_io_object_t omapi_io_states;
47u_int32_t cur_time;
48
20916cae
TL
49OMAPI_OBJECT_ALLOC (omapi_io,
50 omapi_io_object_t, omapi_type_io_object)
51OMAPI_OBJECT_ALLOC (omapi_waiter,
52 omapi_waiter_object_t, omapi_type_waiter)
53
61b844bf
TL
54/* Register an I/O handle so that we can do asynchronous I/O on it. */
55
56isc_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)
60 (omapi_object_t *),
61 isc_result_t (*writer)
62 (omapi_object_t *),
63 isc_result_t (*reaper)
64 (omapi_object_t *))
65{
66 isc_result_t status;
67 omapi_io_object_t *obj, *p;
68
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;
77 }
78
20916cae
TL
79 obj = (omapi_io_object_t *)0;
80 status = omapi_io_allocate (&obj, MDL);
81 if (status != ISC_R_SUCCESS)
82 return status;
61b844bf 83
4bd8800e 84 status = omapi_object_reference (&obj -> inner, h, MDL);
61b844bf 85 if (status != ISC_R_SUCCESS) {
20916cae 86 omapi_io_dereference (&obj, MDL);
61b844bf
TL
87 return status;
88 }
89
4bd8800e
TL
90 status = omapi_object_reference (&h -> outer,
91 (omapi_object_t *)obj, MDL);
61b844bf 92 if (status != ISC_R_SUCCESS) {
20916cae 93 omapi_io_dereference (&obj, MDL);
61b844bf
TL
94 return status;
95 }
96
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)
100 ;
101 if (p)
20916cae 102 omapi_io_reference (&p -> next, obj, MDL);
61b844bf 103 else
20916cae 104 omapi_io_reference (&omapi_io_states.next, obj, MDL);
61b844bf
TL
105
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;
112}
113
b6237fb2
TL
114isc_result_t omapi_unregister_io_object (omapi_object_t *h)
115{
20916cae 116 omapi_io_object_t *p, *obj, *last, *ph;
b6237fb2 117
20916cae
TL
118 if (!h -> outer || h -> outer -> type != omapi_type_io_object)
119 return ISC_R_INVALIDARG;
b6237fb2 120 obj = (omapi_io_object_t *)h -> outer;
20916cae
TL
121 ph = (omapi_io_object_t *)0;
122 omapi_io_reference (&ph, obj, MDL);
b6237fb2
TL
123
124 /* remove from the list of I/O states */
c3064fe0 125 last = &omapi_io_states;
b6237fb2 126 for (p = omapi_io_states.next; p; p = p -> next) {
20916cae
TL
127 if (p == obj) {
128 omapi_io_dereference (&last -> next, MDL);
129 omapi_io_reference (&last -> next, p -> next, MDL);
b6237fb2
TL
130 break;
131 }
132 last = p;
133 }
134 if (obj -> next)
20916cae
TL
135 omapi_io_dereference (&obj -> next, MDL);
136
b6237fb2
TL
137 if (obj -> outer) {
138 if (obj -> outer -> inner == (omapi_object_t *)obj)
139 omapi_object_dereference (&obj -> outer -> inner,
140 MDL);
141 omapi_object_dereference (&obj -> outer, MDL);
142 }
143 omapi_object_dereference (&obj -> inner, MDL);
144 omapi_object_dereference (&h -> outer, MDL);
20916cae 145 omapi_io_dereference (&ph, MDL);
b6237fb2
TL
146 return ISC_R_SUCCESS;
147}
148
61b844bf
TL
149isc_result_t omapi_dispatch (struct timeval *t)
150{
151 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
152 t);
153}
154
155isc_result_t omapi_wait_for_completion (omapi_object_t *object,
156 struct timeval *t)
157{
158 isc_result_t status;
159 omapi_waiter_object_t *waiter;
160 omapi_object_t *inner;
161
162 if (object) {
20916cae
TL
163 waiter = (omapi_waiter_object_t *)0;
164 status = omapi_waiter_allocate (&waiter, MDL);
165 if (status != ISC_R_SUCCESS)
166 return status;
61b844bf
TL
167
168 /* Paste the waiter object onto the inner object we're
169 waiting on. */
170 for (inner = object; inner -> inner; inner = inner -> inner)
171 ;
172
4bd8800e 173 status = omapi_object_reference (&waiter -> outer, inner, MDL);
61b844bf 174 if (status != ISC_R_SUCCESS) {
20916cae 175 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
176 return status;
177 }
178
179 status = omapi_object_reference (&inner -> inner,
180 (omapi_object_t *)waiter,
4bd8800e 181 MDL);
61b844bf 182 if (status != ISC_R_SUCCESS) {
20916cae 183 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
184 return status;
185 }
186 } else
187 waiter = (omapi_waiter_object_t *)0;
188
189 do {
6a4c4be8 190 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
61b844bf
TL
191 if (status != ISC_R_SUCCESS)
192 return status;
193 } while (!waiter || !waiter -> ready);
194
727ebc3a
TL
195 if (waiter -> outer) {
196 if (waiter -> outer -> inner) {
197 omapi_object_dereference (&waiter -> outer -> inner,
4bd8800e 198 MDL);
727ebc3a
TL
199 if (waiter -> inner)
200 omapi_object_reference
201 (&waiter -> outer -> inner,
4bd8800e 202 waiter -> inner, MDL);
727ebc3a 203 }
4bd8800e 204 omapi_object_dereference (&waiter -> outer, MDL);
727ebc3a
TL
205 }
206 if (waiter -> inner)
4bd8800e 207 omapi_object_dereference (&waiter -> inner, MDL);
727ebc3a 208
20916cae 209 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
210 return ISC_R_SUCCESS;
211}
212
6a4c4be8 213isc_result_t omapi_one_dispatch (omapi_object_t *wo,
61b844bf
TL
214 struct timeval *t)
215{
216 fd_set r, w, x;
217 int max = 0;
218 int count;
219 int desc;
220 struct timeval now, to;
221 omapi_io_object_t *io, *prev;
222 isc_result_t status;
6a4c4be8 223 omapi_waiter_object_t *waiter;
b6237fb2 224 omapi_object_t *tmp = (omapi_object_t *)0;
6a4c4be8
TL
225
226 if (!wo || wo -> type != omapi_type_waiter)
227 waiter = (omapi_waiter_object_t *)0;
228 else
229 waiter = (omapi_waiter_object_t *)wo;
61b844bf
TL
230
231 FD_ZERO (&x);
232
233 /* First, see if the timeout has expired, and if so return. */
234 if (t) {
235 gettimeofday (&now, (struct timezone *)0);
236 cur_time = now.tv_sec;
237 if (now.tv_sec > t -> tv_sec ||
238 (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
239 return ISC_R_TIMEDOUT;
240
241 /* We didn't time out, so figure out how long until
242 we do. */
243 to.tv_sec = t -> tv_sec - now.tv_sec;
244 to.tv_usec = t -> tv_usec - now.tv_usec;
245 if (to.tv_usec < 0) {
246 to.tv_usec += 1000000;
247 to.tv_sec--;
248 }
249 }
250
251 /* If the object we're waiting on has reached completion,
252 return now. */
253 if (waiter && waiter -> ready)
254 return ISC_R_SUCCESS;
255
cfb3f45d 256 again:
61b844bf
TL
257 /* If we have no I/O state, we can't proceed. */
258 if (!(io = omapi_io_states.next))
259 return ISC_R_NOMORE;
260
261 /* Set up the read and write masks. */
262 FD_ZERO (&r);
263 FD_ZERO (&w);
264
265 for (; io; io = io -> next) {
266 /* Check for a read socket. If we shouldn't be
267 trying to read for this I/O object, either there
268 won't be a readfd function, or it'll return -1. */
d8c46740 269 if (io -> readfd && io -> inner &&
61b844bf
TL
270 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
271 FD_SET (desc, &r);
272 if (desc > max)
273 max = desc;
274 }
275
276 /* Same deal for write fdets. */
d8c46740 277 if (io -> writefd && io -> inner &&
61b844bf
TL
278 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
279 FD_SET (desc, &w);
280 if (desc > max)
281 max = desc;
282 }
283 }
284
285 /* Wait for a packet or a timeout... XXX */
edbb7667 286#if 0
cfb3f45d
TL
287#if defined (__linux__)
288#define fds_bits __fds_bits
289#endif
477e97dd
TL
290 log_error ("dispatch: %d %lx %lx", max,
291 (unsigned long)r.fds_bits [0],
292 (unsigned long)w.fds_bits [0]);
edbb7667 293#endif
61b844bf
TL
294 count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0);
295
296 /* Get the current time... */
297 gettimeofday (&now, (struct timezone *)0);
298 cur_time = now.tv_sec;
299
cfb3f45d
TL
300 /* We probably have a bad file descriptor. Figure out which one.
301 When we find it, call the reaper function on it, which will
302 maybe make it go away, and then try again. */
303 if (count < 0) {
304 struct timeval t0;
305
306 for (io = omapi_io_states.next; io; io = io -> next) {
307 omapi_object_t *obj;
308 FD_ZERO (&r);
309 FD_ZERO (&w);
310 t0.tv_sec = t0.tv_usec = 0;
311
312 if (io -> readfd && io -> inner &&
313 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
314 FD_SET (desc, &r);
edbb7667 315#if 0
477e97dd
TL
316 log_error ("read check: %d %lx %lx", max,
317 (unsigned long)r.fds_bits [0],
318 (unsigned long)w.fds_bits [0]);
edbb7667 319#endif
cfb3f45d
TL
320 count = select (desc + 1, &r, &w, &x, &t0);
321 bogon:
322 if (count < 0) {
323 log_error ("Bad descriptor %d.", desc);
324 for (obj = (omapi_object_t *)io;
325 obj -> outer;
326 obj = obj -> outer)
327 ;
328 for (; obj; obj = obj -> inner)
329 log_error ("Object %lx %s",
330 (unsigned long)obj,
331 obj -> type -> name);
332 status = (*(io -> reaper)) (io -> inner);
333 goto again;
334 }
335 }
336
337 FD_ZERO (&r);
338 FD_ZERO (&w);
339 t0.tv_sec = t0.tv_usec = 0;
340
341 /* Same deal for write fdets. */
342 if (io -> writefd && io -> inner &&
343 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
344 FD_SET (desc, &w);
edbb7667 345#if 0
477e97dd
TL
346 log_error ("write check: %d %lx %lx", max,
347 (unsigned long)r.fds_bits [0],
348 (unsigned long)w.fds_bits [0]);
edbb7667 349#endif
cfb3f45d
TL
350 count = select (desc + 1, &r, &w, &x, &t0);
351 if (count < 0)
352 goto bogon;
353 }
354 }
355 }
61b844bf
TL
356
357 for (io = omapi_io_states.next; io; io = io -> next) {
d8c46740
TL
358 if (!io -> inner)
359 continue;
b6237fb2 360 omapi_object_reference (&tmp, io -> inner, MDL);
61b844bf
TL
361 /* Check for a read descriptor, and if there is one,
362 see if we got input on that socket. */
363 if (io -> readfd &&
b6237fb2 364 (desc = (*(io -> readfd)) (tmp)) >= 0) {
61b844bf 365 if (FD_ISSET (desc, &r))
b6237fb2 366 status = ((*(io -> reader)) (tmp));
61b844bf
TL
367 /* XXX what to do with status? */
368 }
369
370 /* Same deal for write descriptors. */
371 if (io -> writefd &&
b6237fb2 372 (desc = (*(io -> writefd)) (tmp)) >= 0)
61b844bf
TL
373 {
374 if (FD_ISSET (desc, &w))
b6237fb2 375 status = ((*(io -> writer)) (tmp));
61b844bf
TL
376 /* XXX what to do with status? */
377 }
b6237fb2 378 omapi_object_dereference (&tmp, MDL);
61b844bf
TL
379 }
380
381 /* Now check for I/O handles that are no longer valid,
382 and remove them from the list. */
383 prev = (omapi_io_object_t *)0;
384 for (io = omapi_io_states.next; io; io = io -> next) {
385 if (io -> reaper) {
d8c46740
TL
386 if (io -> inner)
387 status = (*(io -> reaper)) (io -> inner);
388 if (!io -> inner || status != ISC_R_SUCCESS) {
61b844bf
TL
389 omapi_io_object_t *tmp =
390 (omapi_io_object_t *)0;
391 /* Save a reference to the next
392 pointer, if there is one. */
393 if (io -> next)
20916cae
TL
394 omapi_io_reference (&tmp,
395 io -> next, MDL);
61b844bf 396 if (prev) {
20916cae
TL
397 omapi_io_dereference (&prev -> next,
398 MDL);
61b844bf 399 if (tmp)
20916cae
TL
400 omapi_io_reference
401 (&prev -> next,
402 tmp, MDL);
61b844bf 403 } else {
20916cae
TL
404 omapi_io_dereference
405 (&omapi_io_states.next, MDL);
61b844bf 406 if (tmp)
20916cae
TL
407 omapi_io_reference
408 (&omapi_io_states.next,
409 tmp, MDL);
61b844bf
TL
410 else
411 omapi_signal_in
412 ((omapi_object_t *)
413 &omapi_io_states,
414 "ready");
415 }
416 if (tmp)
20916cae 417 omapi_io_dereference (&tmp, MDL);
61b844bf
TL
418 }
419 }
420 prev = io;
421 }
422
423 return ISC_R_SUCCESS;
424}
425
426isc_result_t omapi_io_set_value (omapi_object_t *h,
427 omapi_object_t *id,
428 omapi_data_string_t *name,
429 omapi_typed_data_t *value)
430{
431 if (h -> type != omapi_type_io_object)
432 return ISC_R_INVALIDARG;
433
434 if (h -> inner && h -> inner -> type -> set_value)
435 return (*(h -> inner -> type -> set_value))
436 (h -> inner, id, name, value);
437 return ISC_R_NOTFOUND;
438}
439
440isc_result_t omapi_io_get_value (omapi_object_t *h,
441 omapi_object_t *id,
442 omapi_data_string_t *name,
443 omapi_value_t **value)
444{
445 if (h -> type != omapi_type_io_object)
446 return ISC_R_INVALIDARG;
447
448 if (h -> inner && h -> inner -> type -> get_value)
449 return (*(h -> inner -> type -> get_value))
450 (h -> inner, id, name, value);
451 return ISC_R_NOTFOUND;
452}
453
4bd8800e 454isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
61b844bf 455{
bdcaf7b9
TL
456 omapi_io_object_t *obj, *p, *last;
457
61b844bf
TL
458 if (h -> type != omapi_type_io_object)
459 return ISC_R_INVALIDARG;
bdcaf7b9
TL
460
461 obj = (omapi_io_object_t *)h;
462
b6237fb2
TL
463 /* remove from the list of I/O states */
464 for (p = omapi_io_states.next; p; p = p -> next) {
465 if (p == obj) {
20916cae
TL
466 omapi_io_dereference (&last -> next, MDL);
467 omapi_io_reference (&last -> next, p -> next, MDL);
468 omapi_io_dereference (&p, MDL);
b6237fb2 469 break;
bdcaf7b9 470 }
b6237fb2 471 last = p;
bdcaf7b9 472 }
b6237fb2 473
61b844bf
TL
474 return ISC_R_SUCCESS;
475}
476
477isc_result_t omapi_io_signal_handler (omapi_object_t *h,
b1b7b521 478 const char *name, va_list ap)
61b844bf
TL
479{
480 if (h -> type != omapi_type_io_object)
481 return ISC_R_INVALIDARG;
482
483 if (h -> inner && h -> inner -> type -> signal_handler)
484 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
485 name, ap);
486 return ISC_R_NOTFOUND;
487}
488
489isc_result_t omapi_io_stuff_values (omapi_object_t *c,
490 omapi_object_t *id,
491 omapi_object_t *i)
492{
493 if (i -> type != omapi_type_io_object)
494 return ISC_R_INVALIDARG;
495
496 if (i -> inner && i -> inner -> type -> stuff_values)
497 return (*(i -> inner -> type -> stuff_values)) (c, id,
498 i -> inner);
499 return ISC_R_SUCCESS;
500}
501
502isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
b1b7b521 503 const char *name, va_list ap)
61b844bf
TL
504{
505 omapi_waiter_object_t *waiter;
506
507 if (h -> type != omapi_type_waiter)
508 return ISC_R_INVALIDARG;
509
510 if (!strcmp (name, "ready")) {
511 waiter = (omapi_waiter_object_t *)h;
512 waiter -> ready = 1;
513 return ISC_R_SUCCESS;
514 }
515
516 if (h -> inner && h -> inner -> type -> signal_handler)
517 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
518 name, ap);
519 return ISC_R_NOTFOUND;
520}
521