]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/dispatch.c
[#182] Corrected CVE: CVE-2021-25217
[thirdparty/dhcp.git] / omapip / dispatch.c
CommitLineData
61b844bf
TL
1/* dispatch.c
2
3 I/O dispatcher. */
4
5/*
49a7fb58 6 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1999-2003 by Internet Software Consortium
61b844bf 8 *
7512d88b
TM
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
61b844bf 12 *
98311e4b
DH
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.
61b844bf 20 *
98311e4b 21 * Internet Systems Consortium, Inc.
429a56d7
TM
22 * PO Box 360
23 * Newmarket, NH 03857 USA
98311e4b 24 * <info@isc.org>
2c85ac9b 25 * https://www.isc.org/
49733f31 26 *
61b844bf
TL
27 */
28
fe5b0fdd
DH
29#include "dhcpd.h"
30
6a4c4be8 31#include <omapip/omapip_p.h>
28868515 32#include <sys/time.h>
61b844bf
TL
33
34static omapi_io_object_t omapi_io_states;
be62cf06 35struct timeval cur_tv;
61b844bf 36
6368a1bd
DH
37struct eventqueue *rw_queue_empty;
38
20916cae
TL
39OMAPI_OBJECT_ALLOC (omapi_io,
40 omapi_io_object_t, omapi_type_io_object)
41OMAPI_OBJECT_ALLOC (omapi_waiter,
42 omapi_waiter_object_t, omapi_type_waiter)
43
6368a1bd
DH
44void
45register_eventhandler(struct eventqueue **queue, void (*handler)(void *))
46{
47 struct eventqueue *t, *q;
48
49 /* traverse to end of list */
50 t = NULL;
51 for (q = *queue ; q ; q = q->next) {
52 if (q->handler == handler)
53 return; /* handler already registered */
54 t = q;
55 }
f6b8f48d 56
6368a1bd
DH
57 q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL));
58 if (!q)
59 log_fatal("register_eventhandler: no memory!");
60 memset(q, 0, sizeof *q);
61 if (t)
62 t->next = q;
f6b8f48d 63 else
6368a1bd
DH
64 *queue = q;
65 q->handler = handler;
66 return;
67}
68
69void
70unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *))
71{
72 struct eventqueue *t, *q;
f6b8f48d 73
6368a1bd
DH
74 /* traverse to end of list */
75 t= NULL;
76 for (q = *queue ; q ; q = q->next) {
77 if (q->handler == handler) {
78 if (t)
79 t->next = q->next;
80 else
81 *queue = q->next;
82 dfree(q, MDL); /* Don't access q after this!*/
83 break;
84 }
85 t = q;
86 }
87 return;
88}
89
90void
91trigger_event(struct eventqueue **queue)
92{
93 struct eventqueue *q;
94
95 for (q=*queue ; q ; q=q->next) {
f6b8f48d 96 if (q->handler)
6368a1bd
DH
97 (*q->handler)(NULL);
98 }
99}
100
98bf1607
SR
101/*
102 * Callback routine to connect the omapi I/O object and socket with
103 * the isc socket code. The isc socket code will call this routine
104 * which will then call the correct local routine to process the bytes.
f6b8f48d 105 *
98bf1607
SR
106 * Currently we are always willing to read more data, this should be modified
107 * so that on connections we don't read more if we already have enough.
108 *
109 * If we have more bytes to write we ask the library to call us when
110 * we can write more. If we indicate we don't have more to write we need
111 * to poke the library via isc_socket_fdwatchpoke.
112 */
8fa0112d
SR
113
114/*
115 * sockdelete indicates if we are deleting the socket or leaving it in place
116 * 1 is delete, 0 is leave in place
117 */
118#define SOCKDELETE 1
98bf1607
SR
119int
120omapi_iscsock_cb(isc_task_t *task,
121 isc_socket_t *socket,
122 void *cbarg,
123 int flags)
124{
125 omapi_io_object_t *obj;
126 isc_result_t status;
127
128 /* Get the current time... */
129 gettimeofday (&cur_tv, (struct timezone *)0);
130
8fa0112d
SR
131 /* isc socket stuff */
132#if SOCKDELETE
133 /*
134 * walk through the io states list, if our object is on there
135 * service it. if not ignore it.
136 */
9564b4f0 137 for (obj = omapi_io_states.next; obj != NULL; obj = obj->next) {
8fa0112d
SR
138 if (obj == cbarg)
139 break;
140 }
9564b4f0 141
8fa0112d
SR
142 if (obj == NULL) {
143 return(0);
144 }
145#else
98bf1607
SR
146 /* Not much to be done if we have the wrong type of object. */
147 if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) {
148 log_fatal ("Incorrect object type, must be of type io_object");
149 }
150 obj = (omapi_io_object_t *)cbarg;
151
8fa0112d
SR
152 /*
153 * If the object is marked as closed don't try and process
154 * anything just indicate that we don't want any more.
155 *
156 * This should be a temporary fix until we arrange to properly
157 * close the socket.
158 */
159 if (obj->closed == ISC_TRUE) {
160 return(0);
161 }
f6b8f48d 162#endif
8fa0112d 163
98bf1607
SR
164 if ((flags == ISC_SOCKFDWATCH_READ) &&
165 (obj->reader != NULL) &&
166 (obj->inner != NULL)) {
1e2a127b 167 status = obj->reader(obj->inner);
f6b8f48d 168 /*
1e2a127b
SR
169 * If we are shutting down (basically tried to
170 * read and got no bytes) we don't need to try
171 * again.
172 */
173 if (status == ISC_R_SHUTTINGDOWN)
174 return (0);
175 /* Otherwise We always ask for more when reading */
98bf1607
SR
176 return (1);
177 } else if ((flags == ISC_SOCKFDWATCH_WRITE) &&
178 (obj->writer != NULL) &&
179 (obj->inner != NULL)) {
180 status = obj->writer(obj->inner);
181 /* If the writer has more to write they should return
182 * ISC_R_INPROGRESS */
183 if (status == ISC_R_INPROGRESS) {
184 return (1);
185 }
186 }
187
188 /*
189 * We get here if we either had an error (inconsistent
190 * structures etc) or no more to write, tell the socket
191 * lib we don't have more to do right now.
192 */
193 return (0);
194}
6368a1bd 195
61b844bf
TL
196/* Register an I/O handle so that we can do asynchronous I/O on it. */
197
198isc_result_t omapi_register_io_object (omapi_object_t *h,
199 int (*readfd) (omapi_object_t *),
200 int (*writefd) (omapi_object_t *),
201 isc_result_t (*reader)
202 (omapi_object_t *),
203 isc_result_t (*writer)
204 (omapi_object_t *),
205 isc_result_t (*reaper)
206 (omapi_object_t *))
207{
208 isc_result_t status;
209 omapi_io_object_t *obj, *p;
98bf1607 210 int fd_flags = 0, fd = 0;
61b844bf
TL
211
212 /* omapi_io_states is a static object. If its reference count
213 is zero, this is the first I/O handle to be registered, so
214 we need to initialize it. Because there is no inner or outer
215 pointer on this object, and we're setting its refcnt to 1, it
216 will never be freed. */
217 if (!omapi_io_states.refcnt) {
218 omapi_io_states.refcnt = 1;
219 omapi_io_states.type = omapi_type_io_object;
220 }
f6b8f48d 221
20916cae
TL
222 obj = (omapi_io_object_t *)0;
223 status = omapi_io_allocate (&obj, MDL);
224 if (status != ISC_R_SUCCESS)
225 return status;
8fa0112d 226 obj->closed = ISC_FALSE; /* mark as open */
61b844bf 227
4bd8800e 228 status = omapi_object_reference (&obj -> inner, h, MDL);
61b844bf 229 if (status != ISC_R_SUCCESS) {
20916cae 230 omapi_io_dereference (&obj, MDL);
61b844bf
TL
231 return status;
232 }
233
4bd8800e
TL
234 status = omapi_object_reference (&h -> outer,
235 (omapi_object_t *)obj, MDL);
61b844bf 236 if (status != ISC_R_SUCCESS) {
20916cae 237 omapi_io_dereference (&obj, MDL);
61b844bf
TL
238 return status;
239 }
240
98bf1607 241 /*
f6b8f48d 242 * Attach the I/O object to the isc socket library via the
98bf1607
SR
243 * fdwatch function. This allows the socket library to watch
244 * over a socket that we built. If there are both a read and
245 * a write socket we asssume they are the same socket.
246 */
247
248 if (readfd) {
249 fd_flags |= ISC_SOCKFDWATCH_READ;
250 fd = readfd(h);
251 }
252
253 if (writefd) {
254 fd_flags |= ISC_SOCKFDWATCH_WRITE;
255 fd = writefd(h);
256 }
257
258 if (fd_flags != 0) {
259 status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr,
260 fd, fd_flags,
261 omapi_iscsock_cb,
262 obj,
263 dhcp_gbl_ctx.task,
264 &obj->fd);
265 if (status != ISC_R_SUCCESS) {
266 log_error("Unable to register fd with library %s",
267 isc_result_totext(status));
268
269 /*sar*/
270 /* is this the cleanup we need? */
271 omapi_object_dereference(&h->outer, MDL);
272 omapi_io_dereference (&obj, MDL);
273 return (status);
274 }
275 }
276
277
61b844bf
TL
278 /* Find the last I/O state, if there are any. */
279 for (p = omapi_io_states.next;
280 p && p -> next; p = p -> next)
281 ;
282 if (p)
20916cae 283 omapi_io_reference (&p -> next, obj, MDL);
61b844bf 284 else
20916cae 285 omapi_io_reference (&omapi_io_states.next, obj, MDL);
61b844bf
TL
286
287 obj -> readfd = readfd;
288 obj -> writefd = writefd;
289 obj -> reader = reader;
290 obj -> writer = writer;
291 obj -> reaper = reaper;
4619c0a2
DH
292
293 omapi_io_dereference(&obj, MDL);
61b844bf
TL
294 return ISC_R_SUCCESS;
295}
296
8fa0112d
SR
297/*
298 * ReRegister an I/O handle so that we can do asynchronous I/O on it.
0493fdca 299 * If the handle doesn't exist we call the register routine to build it.
8fa0112d 300 * If it does exist we change the functions associated with it, and
0493fdca 301 * repoke the fd code to make it happy. Neither the objects nor the
8fa0112d
SR
302 * fd are allowed to have changed.
303 */
0493fdca
SR
304
305isc_result_t omapi_reregister_io_object (omapi_object_t *h,
306 int (*readfd) (omapi_object_t *),
307 int (*writefd) (omapi_object_t *),
308 isc_result_t (*reader)
309 (omapi_object_t *),
310 isc_result_t (*writer)
311 (omapi_object_t *),
312 isc_result_t (*reaper)
313 (omapi_object_t *))
314{
315 omapi_io_object_t *obj;
8fa0112d 316 int fd_flags = 0;
0493fdca
SR
317
318 if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
8fa0112d 319 /*
f6b8f48d 320 * If we don't have an object or if the type isn't what
0493fdca
SR
321 * we expect do the normal registration (which will overwrite
322 * an incorrect type, that's what we did historically, may
323 * want to change that)
324 */
325 return (omapi_register_io_object (h, readfd, writefd,
326 reader, writer, reaper));
327 }
328
329 /* We have an io object of the correct type, try to update it */
330 /*sar*/
331 /* Should we validate that the fd matches the previous one?
332 * It's suppossed to, that's a requirement, don't bother yet */
333
334 obj = (omapi_io_object_t *)h->outer;
335
8fa0112d
SR
336 obj->readfd = readfd;
337 obj->writefd = writefd;
338 obj->reader = reader;
339 obj->writer = writer;
340 obj->reaper = reaper;
341
342 if (readfd) {
343 fd_flags |= ISC_SOCKFDWATCH_READ;
344 }
345
346 if (writefd) {
347 fd_flags |= ISC_SOCKFDWATCH_WRITE;
348 }
349
350 isc_socket_fdwatchpoke(obj->fd, fd_flags);
f6b8f48d 351
0493fdca
SR
352 return (ISC_R_SUCCESS);
353}
354
b6237fb2
TL
355isc_result_t omapi_unregister_io_object (omapi_object_t *h)
356{
8fa0112d
SR
357 omapi_io_object_t *obj, *ph;
358#if SOCKDELETE
f6b8f48d 359 omapi_io_object_t *p, *last;
8fa0112d 360#endif
b6237fb2 361
20916cae 362 if (!h -> outer || h -> outer -> type != omapi_type_io_object)
98bf1607 363 return DHCP_R_INVALIDARG;
b6237fb2 364 obj = (omapi_io_object_t *)h -> outer;
20916cae
TL
365 ph = (omapi_io_object_t *)0;
366 omapi_io_reference (&ph, obj, MDL);
b6237fb2 367
8fa0112d
SR
368#if SOCKDELETE
369 /*
370 * For now we leave this out. We can't clean up the isc socket
371 * structure cleanly yet so we need to leave the io object in place.
372 * By leaving it on the io states list we avoid it being freed.
373 * We also mark it as closed to avoid using it.
374 */
375
b6237fb2 376 /* remove from the list of I/O states */
c3064fe0 377 last = &omapi_io_states;
b6237fb2 378 for (p = omapi_io_states.next; p; p = p -> next) {
20916cae
TL
379 if (p == obj) {
380 omapi_io_dereference (&last -> next, MDL);
381 omapi_io_reference (&last -> next, p -> next, MDL);
b6237fb2
TL
382 break;
383 }
384 last = p;
385 }
386 if (obj -> next)
20916cae 387 omapi_io_dereference (&obj -> next, MDL);
8fa0112d 388#endif
20916cae 389
b6237fb2
TL
390 if (obj -> outer) {
391 if (obj -> outer -> inner == (omapi_object_t *)obj)
392 omapi_object_dereference (&obj -> outer -> inner,
393 MDL);
394 omapi_object_dereference (&obj -> outer, MDL);
395 }
396 omapi_object_dereference (&obj -> inner, MDL);
397 omapi_object_dereference (&h -> outer, MDL);
98bf1607 398
8fa0112d 399#if SOCKDELETE
98bf1607
SR
400 /* remove isc socket associations */
401 if (obj->fd != NULL) {
8fa0112d
SR
402 isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
403 ISC_SOCKCANCEL_ALL);
98bf1607
SR
404 isc_socket_detach(&obj->fd);
405 }
8fa0112d
SR
406#else
407 obj->closed = ISC_TRUE;
408#endif
98bf1607 409
20916cae 410 omapi_io_dereference (&ph, MDL);
b6237fb2
TL
411 return ISC_R_SUCCESS;
412}
413
61b844bf
TL
414isc_result_t omapi_dispatch (struct timeval *t)
415{
7f152466
TM
416#ifdef DEBUG_PROTOCOL
417 log_debug("omapi_dispatch()");
418#endif
61b844bf 419 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
7f152466 420
61b844bf
TL
421 t);
422}
423
424isc_result_t omapi_wait_for_completion (omapi_object_t *object,
425 struct timeval *t)
426{
7f152466
TM
427#ifdef DEBUG_PROTOCOL
428 if (t) {
429 log_debug ("omapi_wait_for_completion(%u.%u secs)",
430 (unsigned int)(t->tv_sec),
431 (unsigned int)(t->tv_usec));
432 } else {
433 log_debug ("omapi_wait_for_completion(no timeout)");
434 }
435#endif
61b844bf
TL
436 isc_result_t status;
437 omapi_waiter_object_t *waiter;
438 omapi_object_t *inner;
439
440 if (object) {
20916cae
TL
441 waiter = (omapi_waiter_object_t *)0;
442 status = omapi_waiter_allocate (&waiter, MDL);
443 if (status != ISC_R_SUCCESS)
444 return status;
61b844bf
TL
445
446 /* Paste the waiter object onto the inner object we're
447 waiting on. */
448 for (inner = object; inner -> inner; inner = inner -> inner)
449 ;
450
4bd8800e 451 status = omapi_object_reference (&waiter -> outer, inner, MDL);
61b844bf 452 if (status != ISC_R_SUCCESS) {
20916cae 453 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
454 return status;
455 }
f6b8f48d 456
61b844bf
TL
457 status = omapi_object_reference (&inner -> inner,
458 (omapi_object_t *)waiter,
4bd8800e 459 MDL);
61b844bf 460 if (status != ISC_R_SUCCESS) {
20916cae 461 omapi_waiter_dereference (&waiter, MDL);
61b844bf
TL
462 return status;
463 }
464 } else
465 waiter = (omapi_waiter_object_t *)0;
466
467 do {
6a4c4be8 468 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
7f152466
TM
469 if (status != ISC_R_SUCCESS) {
470#ifdef DEBUG_PROTOCOL
471 log_debug ("- call to omapi_one_dispatch failed: %s",
472 isc_result_totext (status));
473#endif
474 /* Break out on failure, to ensure we free up the waiter(s) */
475 break;
476 }
61b844bf
TL
477 } while (!waiter || !waiter -> ready);
478
7f152466 479
727ebc3a
TL
480 if (waiter -> outer) {
481 if (waiter -> outer -> inner) {
482 omapi_object_dereference (&waiter -> outer -> inner,
4bd8800e 483 MDL);
727ebc3a
TL
484 if (waiter -> inner)
485 omapi_object_reference
486 (&waiter -> outer -> inner,
4bd8800e 487 waiter -> inner, MDL);
727ebc3a 488 }
4bd8800e 489 omapi_object_dereference (&waiter -> outer, MDL);
727ebc3a
TL
490 }
491 if (waiter -> inner)
4bd8800e 492 omapi_object_dereference (&waiter -> inner, MDL);
f6b8f48d 493
7f152466
TM
494 if (status == ISC_R_SUCCESS) {
495 /* If the invocation worked, return the server's
496 * execution status */
497 status = waiter -> waitstatus;
498 }
499
20916cae 500 omapi_waiter_dereference (&waiter, MDL);
86a9cf83 501 return status;
61b844bf
TL
502}
503
6a4c4be8 504isc_result_t omapi_one_dispatch (omapi_object_t *wo,
61b844bf
TL
505 struct timeval *t)
506{
7f152466
TM
507#ifdef DEBUG_PROTOCOL
508 log_debug ("omapi_one_dispatch()");
509#endif
6368a1bd 510 fd_set r, w, x, rr, ww, xx;
61b844bf
TL
511 int max = 0;
512 int count;
513 int desc;
514 struct timeval now, to;
4619c0a2 515 omapi_io_object_t *io, *prev, *next;
6a4c4be8 516 omapi_waiter_object_t *waiter;
b6237fb2 517 omapi_object_t *tmp = (omapi_object_t *)0;
6a4c4be8
TL
518
519 if (!wo || wo -> type != omapi_type_waiter)
520 waiter = (omapi_waiter_object_t *)0;
521 else
522 waiter = (omapi_waiter_object_t *)wo;
61b844bf
TL
523
524 FD_ZERO (&x);
525
526 /* First, see if the timeout has expired, and if so return. */
527 if (t) {
528 gettimeofday (&now, (struct timezone *)0);
be62cf06
FD
529 cur_tv.tv_sec = now.tv_sec;
530 cur_tv.tv_usec = now.tv_usec;
61b844bf
TL
531 if (now.tv_sec > t -> tv_sec ||
532 (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
533 return ISC_R_TIMEDOUT;
f6b8f48d 534
61b844bf
TL
535 /* We didn't time out, so figure out how long until
536 we do. */
537 to.tv_sec = t -> tv_sec - now.tv_sec;
538 to.tv_usec = t -> tv_usec - now.tv_usec;
539 if (to.tv_usec < 0) {
540 to.tv_usec += 1000000;
541 to.tv_sec--;
542 }
d01dde76
DN
543
544 /* It is possible for the timeout to get set larger than
545 the largest time select() is willing to accept.
546 Restricting the timeout to a maximum of one day should
547 work around this. -DPN. (Ref: Bug #416) */
548 if (to.tv_sec > (60 * 60 * 24))
549 to.tv_sec = 60 * 60 * 24;
61b844bf 550 }
f6b8f48d 551
61b844bf
TL
552 /* If the object we're waiting on has reached completion,
553 return now. */
554 if (waiter && waiter -> ready)
555 return ISC_R_SUCCESS;
f6b8f48d 556
cfb3f45d 557 again:
61b844bf
TL
558 /* If we have no I/O state, we can't proceed. */
559 if (!(io = omapi_io_states.next))
560 return ISC_R_NOMORE;
561
562 /* Set up the read and write masks. */
563 FD_ZERO (&r);
564 FD_ZERO (&w);
565
566 for (; io; io = io -> next) {
567 /* Check for a read socket. If we shouldn't be
568 trying to read for this I/O object, either there
569 won't be a readfd function, or it'll return -1. */
d8c46740 570 if (io -> readfd && io -> inner &&
61b844bf
TL
571 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
572 FD_SET (desc, &r);
573 if (desc > max)
574 max = desc;
575 }
f6b8f48d 576
61b844bf 577 /* Same deal for write fdets. */
d8c46740 578 if (io -> writefd && io -> inner &&
61b844bf 579 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
7f152466
TM
580 /* This block avoids adding writefds that are already connected
581 * but that do not have data waiting to write. This avoids
582 * select() calls dropping immediately simply because the
583 * the writefd is ready to write. Without this synchronous
584 * waiting becomes CPU intensive polling */
585 if (io->inner && io->inner->type == omapi_type_connection) {
586 omapi_connection_object_t* c;
587 c = (omapi_connection_object_t *)(io->inner);
588 if (c->state == omapi_connection_connected && c->out_bytes == 0) {
589 /* We are already connected and have no data waiting to
590 * be written, so we avoid registering the fd. */
591#ifdef DEBUG_PROTOCOL
592 log_debug ("--- Connected, nothing to write, skip writefd\n");
593#endif
594 continue;
595 }
596 }
597
598
61b844bf
TL
599 FD_SET (desc, &w);
600 if (desc > max)
601 max = desc;
602 }
603 }
604
f6b8f48d 605 /* poll if all reader are dry */
6368a1bd
DH
606 now.tv_sec = 0;
607 now.tv_usec = 0;
f6b8f48d
TM
608 rr=r;
609 ww=w;
6368a1bd
DH
610 xx=x;
611
612 /* poll once */
613 count = select(max + 1, &r, &w, &x, &now);
f6b8f48d
TM
614 if (!count) {
615 /* We are dry now */
6368a1bd
DH
616 trigger_event(&rw_queue_empty);
617 /* Wait for a packet or a timeout... XXX */
f9453d21
DH
618 r = rr;
619 w = ww;
620 x = xx;
7f152466
TM
621
622#ifdef DEBUG_PROTOCOL
623 if (t) {
624 log_debug (" calling select with timout: %u.%u secs",
625 (unsigned int)(to.tv_sec),
626 (unsigned int)(to.tv_usec));
627 }
628#endif
f9453d21 629 count = select(max + 1, &r, &w, &x, t ? &to : NULL);
6368a1bd 630 }
61b844bf
TL
631
632 /* Get the current time... */
be62cf06 633 gettimeofday (&cur_tv, (struct timezone *)0);
61b844bf 634
cfb3f45d
TL
635 /* We probably have a bad file descriptor. Figure out which one.
636 When we find it, call the reaper function on it, which will
637 maybe make it go away, and then try again. */
638 if (count < 0) {
639 struct timeval t0;
9bf59e83
TL
640 omapi_io_object_t *prev = (omapi_io_object_t *)0;
641 io = (omapi_io_object_t *)0;
642 if (omapi_io_states.next)
643 omapi_io_reference (&io, omapi_io_states.next, MDL);
cfb3f45d 644
9bf59e83 645 while (io) {
cfb3f45d
TL
646 omapi_object_t *obj;
647 FD_ZERO (&r);
648 FD_ZERO (&w);
649 t0.tv_sec = t0.tv_usec = 0;
650
651 if (io -> readfd && io -> inner &&
652 (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
653 FD_SET (desc, &r);
cfb3f45d
TL
654 count = select (desc + 1, &r, &w, &x, &t0);
655 bogon:
656 if (count < 0) {
657 log_error ("Bad descriptor %d.", desc);
658 for (obj = (omapi_object_t *)io;
659 obj -> outer;
660 obj = obj -> outer)
661 ;
645eab7b
TL
662 for (; obj; obj = obj -> inner) {
663 omapi_value_t *ov;
664 int len;
665 const char *s;
666 ov = (omapi_value_t *)0;
667 omapi_get_value_str (obj,
668 (omapi_object_t *)0,
669 "name", &ov);
670 if (ov && ov -> value &&
671 (ov -> value -> type ==
672 omapi_datatype_string)) {
673 s = (char *)
674 ov -> value -> u.buffer.value;
675 len = ov -> value -> u.buffer.len;
676 } else {
677 s = "";
678 len = 0;
679 }
680 log_error ("Object %lx %s%s%.*s",
681 (unsigned long)obj,
682 obj -> type -> name,
683 len ? " " : "",
684 len, s);
685 if (len)
686 omapi_value_dereference (&ov, MDL);
687 }
98311e4b 688 (*(io -> reaper)) (io -> inner);
9bf59e83
TL
689 if (prev) {
690 omapi_io_dereference (&prev -> next, MDL);
691 if (io -> next)
692 omapi_io_reference (&prev -> next,
693 io -> next, MDL);
694 } else {
695 omapi_io_dereference
696 (&omapi_io_states.next, MDL);
697 if (io -> next)
698 omapi_io_reference
699 (&omapi_io_states.next,
700 io -> next, MDL);
701 }
702 omapi_io_dereference (&io, MDL);
cfb3f45d
TL
703 goto again;
704 }
705 }
f6b8f48d 706
cfb3f45d
TL
707 FD_ZERO (&r);
708 FD_ZERO (&w);
709 t0.tv_sec = t0.tv_usec = 0;
710
711 /* Same deal for write fdets. */
712 if (io -> writefd && io -> inner &&
713 (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
714 FD_SET (desc, &w);
cfb3f45d
TL
715 count = select (desc + 1, &r, &w, &x, &t0);
716 if (count < 0)
717 goto bogon;
718 }
9bf59e83
TL
719 if (prev)
720 omapi_io_dereference (&prev, MDL);
721 omapi_io_reference (&prev, io, MDL);
722 omapi_io_dereference (&io, MDL);
723 if (prev -> next)
724 omapi_io_reference (&io, prev -> next, MDL);
cfb3f45d 725 }
9bf59e83
TL
726 if (prev)
727 omapi_io_dereference (&prev, MDL);
f6b8f48d 728
cfb3f45d 729 }
61b844bf
TL
730
731 for (io = omapi_io_states.next; io; io = io -> next) {
d8c46740
TL
732 if (!io -> inner)
733 continue;
b6237fb2 734 omapi_object_reference (&tmp, io -> inner, MDL);
61b844bf
TL
735 /* Check for a read descriptor, and if there is one,
736 see if we got input on that socket. */
737 if (io -> readfd &&
b6237fb2 738 (desc = (*(io -> readfd)) (tmp)) >= 0) {
7f152466 739 if (FD_ISSET (desc, &r)) {
98311e4b 740 ((*(io -> reader)) (tmp));
7f152466 741 }
61b844bf 742 }
f6b8f48d 743
61b844bf
TL
744 /* Same deal for write descriptors. */
745 if (io -> writefd &&
b6237fb2 746 (desc = (*(io -> writefd)) (tmp)) >= 0)
61b844bf 747 {
7f152466 748 if (FD_ISSET (desc, &w)) {
98311e4b 749 ((*(io -> writer)) (tmp));
7f152466 750 }
61b844bf 751 }
b6237fb2 752 omapi_object_dereference (&tmp, MDL);
61b844bf
TL
753 }
754
755 /* Now check for I/O handles that are no longer valid,
756 and remove them from the list. */
4619c0a2
DH
757 prev = NULL;
758 io = NULL;
759 if (omapi_io_states.next != NULL) {
760 omapi_io_reference(&io, omapi_io_states.next, MDL);
761 }
762 while (io != NULL) {
f6b8f48d
TM
763 if ((io->inner == NULL) ||
764 ((io->reaper != NULL) &&
765 ((io->reaper)(io->inner) != ISC_R_SUCCESS)))
4619c0a2
DH
766 {
767
768 omapi_io_object_t *tmp = NULL;
769 /* Save a reference to the next
770 pointer, if there is one. */
771 if (io->next != NULL) {
772 omapi_io_reference(&tmp, io->next, MDL);
773 omapi_io_dereference(&io->next, MDL);
61b844bf 774 }
4619c0a2
DH
775 if (prev != NULL) {
776 omapi_io_dereference(&prev->next, MDL);
777 if (tmp != NULL)
778 omapi_io_reference(&prev->next,
779 tmp, MDL);
780 } else {
f6b8f48d 781 omapi_io_dereference(&omapi_io_states.next,
4619c0a2
DH
782 MDL);
783 if (tmp != NULL)
784 omapi_io_reference
785 (&omapi_io_states.next,
786 tmp, MDL);
787 else
788 omapi_signal_in(
789 (omapi_object_t *)
790 &omapi_io_states,
791 "ready");
792 }
793 if (tmp != NULL)
794 omapi_io_dereference(&tmp, MDL);
795
796 } else {
797
798 if (prev != NULL) {
799 omapi_io_dereference(&prev, MDL);
800 }
801 omapi_io_reference(&prev, io, MDL);
61b844bf 802 }
4619c0a2
DH
803
804 /*
805 * Equivalent to:
806 * io = io->next
807 * But using our reference counting voodoo.
808 */
809 next = NULL;
810 if (io->next != NULL) {
811 omapi_io_reference(&next, io->next, MDL);
812 }
813 omapi_io_dereference(&io, MDL);
814 if (next != NULL) {
815 omapi_io_reference(&io, next, MDL);
816 omapi_io_dereference(&next, MDL);
817 }
818 }
819 if (prev != NULL) {
820 omapi_io_dereference(&prev, MDL);
61b844bf
TL
821 }
822
823 return ISC_R_SUCCESS;
824}
825
826isc_result_t omapi_io_set_value (omapi_object_t *h,
827 omapi_object_t *id,
828 omapi_data_string_t *name,
829 omapi_typed_data_t *value)
830{
831 if (h -> type != omapi_type_io_object)
98bf1607 832 return DHCP_R_INVALIDARG;
f6b8f48d 833
61b844bf
TL
834 if (h -> inner && h -> inner -> type -> set_value)
835 return (*(h -> inner -> type -> set_value))
836 (h -> inner, id, name, value);
837 return ISC_R_NOTFOUND;
838}
839
840isc_result_t omapi_io_get_value (omapi_object_t *h,
841 omapi_object_t *id,
842 omapi_data_string_t *name,
843 omapi_value_t **value)
844{
845 if (h -> type != omapi_type_io_object)
98bf1607 846 return DHCP_R_INVALIDARG;
f6b8f48d 847
61b844bf
TL
848 if (h -> inner && h -> inner -> type -> get_value)
849 return (*(h -> inner -> type -> get_value))
850 (h -> inner, id, name, value);
851 return ISC_R_NOTFOUND;
852}
853
98311e4b
DH
854/* omapi_io_destroy (object, MDL);
855 *
20ae1aff 856 * Find the requested IO [object] and remove it from the list of io
98311e4b
DH
857 * states, causing the cleanup functions to destroy it. Note that we must
858 * hold a reference on the object while moving its ->next reference and
859 * removing the reference in the chain to the target object...otherwise it
860 * may be cleaned up from under us.
861 */
4bd8800e 862isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
61b844bf 863{
98311e4b 864 omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
bdcaf7b9 865
61b844bf 866 if (h -> type != omapi_type_io_object)
98bf1607 867 return DHCP_R_INVALIDARG;
f6b8f48d 868
b6237fb2
TL
869 /* remove from the list of I/O states */
870 for (p = omapi_io_states.next; p; p = p -> next) {
98311e4b
DH
871 if (p == (omapi_io_object_t *)h) {
872 omapi_io_reference (&obj, p, MDL);
873
874 if (last)
875 holder = &last -> next;
876 else
877 holder = &omapi_io_states.next;
878
879 omapi_io_dereference (holder, MDL);
880
881 if (obj -> next) {
882 omapi_io_reference (holder, obj -> next, MDL);
883 omapi_io_dereference (&obj -> next, MDL);
884 }
885
886 return omapi_io_dereference (&obj, MDL);
bdcaf7b9 887 }
b6237fb2 888 last = p;
bdcaf7b9 889 }
98311e4b
DH
890
891 return ISC_R_NOTFOUND;
61b844bf
TL
892}
893
894isc_result_t omapi_io_signal_handler (omapi_object_t *h,
b1b7b521 895 const char *name, va_list ap)
61b844bf 896{
7f152466
TM
897#ifdef DEBUG_PROTOCOL
898 log_debug ("omapi_io_signal_handler(%s)", name);
899#endif
61b844bf 900 if (h -> type != omapi_type_io_object)
98bf1607 901 return DHCP_R_INVALIDARG;
f6b8f48d 902
61b844bf
TL
903 if (h -> inner && h -> inner -> type -> signal_handler)
904 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
905 name, ap);
906 return ISC_R_NOTFOUND;
907}
908
909isc_result_t omapi_io_stuff_values (omapi_object_t *c,
910 omapi_object_t *id,
911 omapi_object_t *i)
912{
913 if (i -> type != omapi_type_io_object)
98bf1607 914 return DHCP_R_INVALIDARG;
61b844bf
TL
915
916 if (i -> inner && i -> inner -> type -> stuff_values)
917 return (*(i -> inner -> type -> stuff_values)) (c, id,
918 i -> inner);
919 return ISC_R_SUCCESS;
920}
921
922isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
b1b7b521 923 const char *name, va_list ap)
61b844bf
TL
924{
925 omapi_waiter_object_t *waiter;
926
7f152466
TM
927#ifdef DEBUG_PROTOCOL
928 log_debug ("omapi_waiter_signal_handler(%s)", name);
929#endif
61b844bf 930 if (h -> type != omapi_type_waiter)
98bf1607 931 return DHCP_R_INVALIDARG;
f6b8f48d 932
61b844bf
TL
933 if (!strcmp (name, "ready")) {
934 waiter = (omapi_waiter_object_t *)h;
935 waiter -> ready = 1;
49146f3c
DN
936 waiter -> waitstatus = ISC_R_SUCCESS;
937 return ISC_R_SUCCESS;
938 }
939
98bf1607 940 if (!strcmp(name, "status")) {
49146f3c 941 waiter = (omapi_waiter_object_t *)h;
98bf1607
SR
942 waiter->ready = 1;
943 waiter->waitstatus = va_arg(ap, isc_result_t);
61b844bf
TL
944 return ISC_R_SUCCESS;
945 }
946
d758ad8c
TL
947 if (!strcmp (name, "disconnect")) {
948 waiter = (omapi_waiter_object_t *)h;
949 waiter -> ready = 1;
98bf1607 950 waiter -> waitstatus = DHCP_R_CONNRESET;
d758ad8c
TL
951 return ISC_R_SUCCESS;
952 }
953
61b844bf
TL
954 if (h -> inner && h -> inner -> type -> signal_handler)
955 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
956 name, ap);
957 return ISC_R_NOTFOUND;
958}
959
47e8308d
SR
960/** @brief calls a given function on every object
961 *
962 * @param func function to be called
963 * @param p parameter to be passed to each function instance
964 *
965 * @return result (ISC_R_SUCCESS if successful, error code otherwise)
966 */
d758ad8c
TL
967isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
968 void *),
969 void *p)
970{
47e8308d 971 omapi_io_object_t *io = NULL;
d758ad8c 972 isc_result_t status;
47e8308d 973 omapi_io_object_t *next = NULL;
d758ad8c 974
47e8308d
SR
975 /*
976 * This just calls func on every inner object on the list. It would
977 * be much simpler in general case, but one of the operations could be
978 * release of the objects. Therefore we need to ref count the io and
979 * io->next pointers.
980 */
981
982 if (omapi_io_states.next) {
983 omapi_object_reference((omapi_object_t**)&io,
984 (omapi_object_t*)omapi_io_states.next,
985 MDL);
986 }
987
988 while(io) {
989 /* If there's a next object, save it */
990 if (io->next) {
991 omapi_object_reference((omapi_object_t**)&next,
992 (omapi_object_t*)io->next, MDL);
993 }
994 if (io->inner) {
995 status = (*func) (io->inner, p);
996 if (status != ISC_R_SUCCESS) {
997 /* Something went wrong. Let's stop using io & next pointer
998 * and bail out */
999 omapi_object_dereference((omapi_object_t**)&io, MDL);
1000 if (next) {
1001 omapi_object_dereference((omapi_object_t**)&next, MDL);
1002 }
1003 return status;
d758ad8c 1004 }
47e8308d
SR
1005 }
1006 /* Update the io pointer and free the next pointer */
1007 omapi_object_dereference((omapi_object_t**)&io, MDL);
1008 if (next) {
1009 omapi_object_reference((omapi_object_t**)&io,
1010 (omapi_object_t*)next,
1011 MDL);
1012 omapi_object_dereference((omapi_object_t**)&next, MDL);
1013 }
d758ad8c 1014 }
47e8308d
SR
1015
1016 /*
1017 * The only way to get here is when next is NULL. There's no need
1018 * to dereference it.
1019 */
d758ad8c
TL
1020 return ISC_R_SUCCESS;
1021}