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