1 /* $NetBSD: dispatch.c,v 1.4 2014/07/12 12:09:37 spz Exp $ */ 2 /* dispatch.c 3 4 I/O dispatcher. */ 5 6 /* 7 * Copyright (c) 2004,2007-2009,2013-2014 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 1999-2003 by Internet Software Consortium 9 * 10 * Permission to use, copy, modify, and distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Internet Systems Consortium, Inc. 23 * 950 Charter Street 24 * Redwood City, CA 94063 25 * <info@isc.org> 26 * https://www.isc.org/ 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 __RCSID("$NetBSD: dispatch.c,v 1.4 2014/07/12 12:09:37 spz Exp $"); 32 33 #include "dhcpd.h" 34 35 #include <omapip/omapip_p.h> 36 #include <sys/time.h> 37 38 static omapi_io_object_t omapi_io_states; 39 struct timeval cur_tv; 40 41 struct eventqueue *rw_queue_empty; 42 43 OMAPI_OBJECT_ALLOC (omapi_io, 44 omapi_io_object_t, omapi_type_io_object) 45 OMAPI_OBJECT_ALLOC (omapi_waiter, 46 omapi_waiter_object_t, omapi_type_waiter) 47 48 void 49 register_eventhandler(struct eventqueue **queue, void (*handler)(void *)) 50 { 51 struct eventqueue *t, *q; 52 53 /* traverse to end of list */ 54 t = NULL; 55 for (q = *queue ; q ; q = q->next) { 56 if (q->handler == handler) 57 return; /* handler already registered */ 58 t = q; 59 } 60 61 q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL)); 62 if (!q) 63 log_fatal("register_eventhandler: no memory!"); 64 memset(q, 0, sizeof *q); 65 if (t) 66 t->next = q; 67 else 68 *queue = q; 69 q->handler = handler; 70 return; 71 } 72 73 void 74 unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *)) 75 { 76 struct eventqueue *t, *q; 77 78 /* traverse to end of list */ 79 t= NULL; 80 for (q = *queue ; q ; q = q->next) { 81 if (q->handler == handler) { 82 if (t) 83 t->next = q->next; 84 else 85 *queue = q->next; 86 dfree(q, MDL); /* Don't access q after this!*/ 87 break; 88 } 89 t = q; 90 } 91 return; 92 } 93 94 void 95 trigger_event(struct eventqueue **queue) 96 { 97 struct eventqueue *q; 98 99 for (q=*queue ; q ; q=q->next) { 100 if (q->handler) 101 (*q->handler)(NULL); 102 } 103 } 104 105 /* 106 * Callback routine to connect the omapi I/O object and socket with 107 * the isc socket code. The isc socket code will call this routine 108 * which will then call the correct local routine to process the bytes. 109 * 110 * Currently we are always willing to read more data, this should be modified 111 * so that on connections we don't read more if we already have enough. 112 * 113 * If we have more bytes to write we ask the library to call us when 114 * we can write more. If we indicate we don't have more to write we need 115 * to poke the library via isc_socket_fdwatchpoke. 116 */ 117 118 /* 119 * sockdelete indicates if we are deleting the socket or leaving it in place 120 * 1 is delete, 0 is leave in place 121 */ 122 #define SOCKDELETE 1 123 static int 124 omapi_iscsock_cb(isc_task_t *task, 125 isc_socket_t *socket, 126 void *cbarg, 127 int flags) 128 { 129 omapi_io_object_t *obj; 130 isc_result_t status; 131 132 /* Get the current time... */ 133 gettimeofday (&cur_tv, (struct timezone *)0); 134 135 /* isc socket stuff */ 136 #if SOCKDELETE 137 /* 138 * walk through the io states list, if our object is on there 139 * service it. if not ignore it. 140 */ 141 for (obj = omapi_io_states.next; 142 (obj != NULL) && (obj->next != NULL); 143 obj = obj->next) { 144 if (obj == cbarg) 145 break; 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 203 isc_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 310 isc_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 360 isc_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 419 isc_result_t omapi_dispatch (struct timeval *t) 420 { 421 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, 422 t); 423 } 424 425 isc_result_t omapi_wait_for_completion (omapi_object_t *object, 426 struct timeval *t) 427 { 428 isc_result_t status; 429 omapi_waiter_object_t *waiter; 430 omapi_object_t *inner; 431 432 if (object) { 433 waiter = (omapi_waiter_object_t *)0; 434 status = omapi_waiter_allocate (&waiter, MDL); 435 if (status != ISC_R_SUCCESS) 436 return status; 437 438 /* Paste the waiter object onto the inner object we're 439 waiting on. */ 440 for (inner = object; inner -> inner; inner = inner -> inner) 441 ; 442 443 status = omapi_object_reference (&waiter -> outer, inner, MDL); 444 if (status != ISC_R_SUCCESS) { 445 omapi_waiter_dereference (&waiter, MDL); 446 return status; 447 } 448 449 status = omapi_object_reference (&inner -> inner, 450 (omapi_object_t *)waiter, 451 MDL); 452 if (status != ISC_R_SUCCESS) { 453 omapi_waiter_dereference (&waiter, MDL); 454 return status; 455 } 456 } else 457 waiter = (omapi_waiter_object_t *)0; 458 459 do { 460 status = omapi_one_dispatch ((omapi_object_t *)waiter, t); 461 if (status != ISC_R_SUCCESS) 462 return status; 463 } while (!waiter || !waiter -> ready); 464 465 if (waiter -> outer) { 466 if (waiter -> outer -> inner) { 467 omapi_object_dereference (&waiter -> outer -> inner, 468 MDL); 469 if (waiter -> inner) 470 omapi_object_reference 471 (&waiter -> outer -> inner, 472 waiter -> inner, MDL); 473 } 474 omapi_object_dereference (&waiter -> outer, MDL); 475 } 476 if (waiter -> inner) 477 omapi_object_dereference (&waiter -> inner, MDL); 478 479 status = waiter -> waitstatus; 480 omapi_waiter_dereference (&waiter, MDL); 481 return status; 482 } 483 484 isc_result_t omapi_one_dispatch (omapi_object_t *wo, 485 struct timeval *t) 486 { 487 fd_set r, w, x, rr, ww, xx; 488 int max = 0; 489 int count; 490 int desc; 491 struct timeval now, to; 492 omapi_io_object_t *io, *prev, *next; 493 omapi_waiter_object_t *waiter; 494 omapi_object_t *tmp = (omapi_object_t *)0; 495 496 if (!wo || wo -> type != omapi_type_waiter) 497 waiter = (omapi_waiter_object_t *)0; 498 else 499 waiter = (omapi_waiter_object_t *)wo; 500 501 FD_ZERO (&x); 502 503 /* First, see if the timeout has expired, and if so return. */ 504 if (t) { 505 gettimeofday (&now, (struct timezone *)0); 506 cur_tv.tv_sec = now.tv_sec; 507 cur_tv.tv_usec = now.tv_usec; 508 if (now.tv_sec > t -> tv_sec || 509 (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) 510 return ISC_R_TIMEDOUT; 511 512 /* We didn't time out, so figure out how long until 513 we do. */ 514 to.tv_sec = t -> tv_sec - now.tv_sec; 515 to.tv_usec = t -> tv_usec - now.tv_usec; 516 if (to.tv_usec < 0) { 517 to.tv_usec += 1000000; 518 to.tv_sec--; 519 } 520 521 /* It is possible for the timeout to get set larger than 522 the largest time select() is willing to accept. 523 Restricting the timeout to a maximum of one day should 524 work around this. -DPN. (Ref: Bug #416) */ 525 if (to.tv_sec > (60 * 60 * 24)) 526 to.tv_sec = 60 * 60 * 24; 527 } 528 529 /* If the object we're waiting on has reached completion, 530 return now. */ 531 if (waiter && waiter -> ready) 532 return ISC_R_SUCCESS; 533 534 again: 535 /* If we have no I/O state, we can't proceed. */ 536 if (!(io = omapi_io_states.next)) 537 return ISC_R_NOMORE; 538 539 /* Set up the read and write masks. */ 540 FD_ZERO (&r); 541 FD_ZERO (&w); 542 543 for (; io; io = io -> next) { 544 /* Check for a read socket. If we shouldn't be 545 trying to read for this I/O object, either there 546 won't be a readfd function, or it'll return -1. */ 547 if (io -> readfd && io -> inner && 548 (desc = (*(io -> readfd)) (io -> inner)) >= 0) { 549 FD_SET (desc, &r); 550 if (desc > max) 551 max = desc; 552 } 553 554 /* Same deal for write fdets. */ 555 if (io -> writefd && io -> inner && 556 (desc = (*(io -> writefd)) (io -> inner)) >= 0) { 557 FD_SET (desc, &w); 558 if (desc > max) 559 max = desc; 560 } 561 } 562 563 /* poll if all reader are dry */ 564 now.tv_sec = 0; 565 now.tv_usec = 0; 566 rr=r; 567 ww=w; 568 xx=x; 569 570 /* poll once */ 571 count = select(max + 1, &r, &w, &x, &now); 572 if (!count) { 573 /* We are dry now */ 574 trigger_event(&rw_queue_empty); 575 /* Wait for a packet or a timeout... XXX */ 576 r = rr; 577 w = ww; 578 x = xx; 579 count = select(max + 1, &r, &w, &x, t ? &to : NULL); 580 } 581 582 /* Get the current time... */ 583 gettimeofday (&cur_tv, (struct timezone *)0); 584 585 /* We probably have a bad file descriptor. Figure out which one. 586 When we find it, call the reaper function on it, which will 587 maybe make it go away, and then try again. */ 588 if (count < 0) { 589 struct timeval t0; 590 omapi_io_object_t *prev = (omapi_io_object_t *)0; 591 io = (omapi_io_object_t *)0; 592 if (omapi_io_states.next) 593 omapi_io_reference (&io, omapi_io_states.next, MDL); 594 595 while (io) { 596 omapi_object_t *obj; 597 FD_ZERO (&r); 598 FD_ZERO (&w); 599 t0.tv_sec = t0.tv_usec = 0; 600 601 if (io -> readfd && io -> inner && 602 (desc = (*(io -> readfd)) (io -> inner)) >= 0) { 603 FD_SET (desc, &r); 604 count = select (desc + 1, &r, &w, &x, &t0); 605 bogon: 606 if (count < 0) { 607 log_error ("Bad descriptor %d.", desc); 608 for (obj = (omapi_object_t *)io; 609 obj -> outer; 610 obj = obj -> outer) 611 ; 612 for (; obj; obj = obj -> inner) { 613 omapi_value_t *ov; 614 int len; 615 const char *s; 616 ov = (omapi_value_t *)0; 617 omapi_get_value_str (obj, 618 (omapi_object_t *)0, 619 "name", &ov); 620 if (ov && ov -> value && 621 (ov -> value -> type == 622 omapi_datatype_string)) { 623 s = (char *) 624 ov -> value -> u.buffer.value; 625 len = ov -> value -> u.buffer.len; 626 } else { 627 s = ""; 628 len = 0; 629 } 630 log_error ("Object %lx %s%s%.*s", 631 (unsigned long)obj, 632 obj -> type -> name, 633 len ? " " : "", 634 len, s); 635 if (len) 636 omapi_value_dereference (&ov, MDL); 637 } 638 (*(io -> reaper)) (io -> inner); 639 if (prev) { 640 omapi_io_dereference (&prev -> next, MDL); 641 if (io -> next) 642 omapi_io_reference (&prev -> next, 643 io -> next, MDL); 644 } else { 645 omapi_io_dereference 646 (&omapi_io_states.next, MDL); 647 if (io -> next) 648 omapi_io_reference 649 (&omapi_io_states.next, 650 io -> next, MDL); 651 } 652 omapi_io_dereference (&io, MDL); 653 goto again; 654 } 655 } 656 657 FD_ZERO (&r); 658 FD_ZERO (&w); 659 t0.tv_sec = t0.tv_usec = 0; 660 661 /* Same deal for write fdets. */ 662 if (io -> writefd && io -> inner && 663 (desc = (*(io -> writefd)) (io -> inner)) >= 0) { 664 FD_SET (desc, &w); 665 count = select (desc + 1, &r, &w, &x, &t0); 666 if (count < 0) 667 goto bogon; 668 } 669 if (prev) 670 omapi_io_dereference (&prev, MDL); 671 omapi_io_reference (&prev, io, MDL); 672 omapi_io_dereference (&io, MDL); 673 if (prev -> next) 674 omapi_io_reference (&io, prev -> next, MDL); 675 } 676 if (prev) 677 omapi_io_dereference (&prev, MDL); 678 679 } 680 681 for (io = omapi_io_states.next; io; io = io -> next) { 682 if (!io -> inner) 683 continue; 684 omapi_object_reference (&tmp, io -> inner, MDL); 685 /* Check for a read descriptor, and if there is one, 686 see if we got input on that socket. */ 687 if (io -> readfd && 688 (desc = (*(io -> readfd)) (tmp)) >= 0) { 689 if (FD_ISSET (desc, &r)) 690 ((*(io -> reader)) (tmp)); 691 } 692 693 /* Same deal for write descriptors. */ 694 if (io -> writefd && 695 (desc = (*(io -> writefd)) (tmp)) >= 0) 696 { 697 if (FD_ISSET (desc, &w)) 698 ((*(io -> writer)) (tmp)); 699 } 700 omapi_object_dereference (&tmp, MDL); 701 } 702 703 /* Now check for I/O handles that are no longer valid, 704 and remove them from the list. */ 705 prev = NULL; 706 io = NULL; 707 if (omapi_io_states.next != NULL) { 708 omapi_io_reference(&io, omapi_io_states.next, MDL); 709 } 710 while (io != NULL) { 711 if ((io->inner == NULL) || 712 ((io->reaper != NULL) && 713 ((io->reaper)(io->inner) != ISC_R_SUCCESS))) 714 { 715 716 omapi_io_object_t *tmp = NULL; 717 /* Save a reference to the next 718 pointer, if there is one. */ 719 if (io->next != NULL) { 720 omapi_io_reference(&tmp, io->next, MDL); 721 omapi_io_dereference(&io->next, MDL); 722 } 723 if (prev != NULL) { 724 omapi_io_dereference(&prev->next, MDL); 725 if (tmp != NULL) 726 omapi_io_reference(&prev->next, 727 tmp, MDL); 728 } else { 729 omapi_io_dereference(&omapi_io_states.next, 730 MDL); 731 if (tmp != NULL) 732 omapi_io_reference 733 (&omapi_io_states.next, 734 tmp, MDL); 735 else 736 omapi_signal_in( 737 (omapi_object_t *) 738 &omapi_io_states, 739 "ready"); 740 } 741 if (tmp != NULL) 742 omapi_io_dereference(&tmp, MDL); 743 744 } else { 745 746 if (prev != NULL) { 747 omapi_io_dereference(&prev, MDL); 748 } 749 omapi_io_reference(&prev, io, MDL); 750 } 751 752 /* 753 * Equivalent to: 754 * io = io->next 755 * But using our reference counting voodoo. 756 */ 757 next = NULL; 758 if (io->next != NULL) { 759 omapi_io_reference(&next, io->next, MDL); 760 } 761 omapi_io_dereference(&io, MDL); 762 if (next != NULL) { 763 omapi_io_reference(&io, next, MDL); 764 omapi_io_dereference(&next, MDL); 765 } 766 } 767 if (prev != NULL) { 768 omapi_io_dereference(&prev, MDL); 769 } 770 771 return ISC_R_SUCCESS; 772 } 773 774 isc_result_t omapi_io_set_value (omapi_object_t *h, 775 omapi_object_t *id, 776 omapi_data_string_t *name, 777 omapi_typed_data_t *value) 778 { 779 if (h -> type != omapi_type_io_object) 780 return DHCP_R_INVALIDARG; 781 782 if (h -> inner && h -> inner -> type -> set_value) 783 return (*(h -> inner -> type -> set_value)) 784 (h -> inner, id, name, value); 785 return ISC_R_NOTFOUND; 786 } 787 788 isc_result_t omapi_io_get_value (omapi_object_t *h, 789 omapi_object_t *id, 790 omapi_data_string_t *name, 791 omapi_value_t **value) 792 { 793 if (h -> type != omapi_type_io_object) 794 return DHCP_R_INVALIDARG; 795 796 if (h -> inner && h -> inner -> type -> get_value) 797 return (*(h -> inner -> type -> get_value)) 798 (h -> inner, id, name, value); 799 return ISC_R_NOTFOUND; 800 } 801 802 /* omapi_io_destroy (object, MDL); 803 * 804 * Find the requested IO [object] and remove it from the list of io 805 * states, causing the cleanup functions to destroy it. Note that we must 806 * hold a reference on the object while moving its ->next reference and 807 * removing the reference in the chain to the target object...otherwise it 808 * may be cleaned up from under us. 809 */ 810 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line) 811 { 812 omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder; 813 814 if (h -> type != omapi_type_io_object) 815 return DHCP_R_INVALIDARG; 816 817 /* remove from the list of I/O states */ 818 for (p = omapi_io_states.next; p; p = p -> next) { 819 if (p == (omapi_io_object_t *)h) { 820 omapi_io_reference (&obj, p, MDL); 821 822 if (last) 823 holder = &last -> next; 824 else 825 holder = &omapi_io_states.next; 826 827 omapi_io_dereference (holder, MDL); 828 829 if (obj -> next) { 830 omapi_io_reference (holder, obj -> next, MDL); 831 omapi_io_dereference (&obj -> next, MDL); 832 } 833 834 return omapi_io_dereference (&obj, MDL); 835 } 836 last = p; 837 } 838 839 return ISC_R_NOTFOUND; 840 } 841 842 isc_result_t omapi_io_signal_handler (omapi_object_t *h, 843 const char *name, va_list ap) 844 { 845 if (h -> type != omapi_type_io_object) 846 return DHCP_R_INVALIDARG; 847 848 if (h -> inner && h -> inner -> type -> signal_handler) 849 return (*(h -> inner -> type -> signal_handler)) (h -> inner, 850 name, ap); 851 return ISC_R_NOTFOUND; 852 } 853 854 isc_result_t omapi_io_stuff_values (omapi_object_t *c, 855 omapi_object_t *id, 856 omapi_object_t *i) 857 { 858 if (i -> type != omapi_type_io_object) 859 return DHCP_R_INVALIDARG; 860 861 if (i -> inner && i -> inner -> type -> stuff_values) 862 return (*(i -> inner -> type -> stuff_values)) (c, id, 863 i -> inner); 864 return ISC_R_SUCCESS; 865 } 866 867 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, 868 const char *name, va_list ap) 869 { 870 omapi_waiter_object_t *waiter; 871 872 if (h -> type != omapi_type_waiter) 873 return DHCP_R_INVALIDARG; 874 875 if (!strcmp (name, "ready")) { 876 waiter = (omapi_waiter_object_t *)h; 877 waiter -> ready = 1; 878 waiter -> waitstatus = ISC_R_SUCCESS; 879 return ISC_R_SUCCESS; 880 } 881 882 if (!strcmp(name, "status")) { 883 waiter = (omapi_waiter_object_t *)h; 884 waiter->ready = 1; 885 waiter->waitstatus = va_arg(ap, isc_result_t); 886 return ISC_R_SUCCESS; 887 } 888 889 if (!strcmp (name, "disconnect")) { 890 waiter = (omapi_waiter_object_t *)h; 891 waiter -> ready = 1; 892 waiter -> waitstatus = DHCP_R_CONNRESET; 893 return ISC_R_SUCCESS; 894 } 895 896 if (h -> inner && h -> inner -> type -> signal_handler) 897 return (*(h -> inner -> type -> signal_handler)) (h -> inner, 898 name, ap); 899 return ISC_R_NOTFOUND; 900 } 901 902 /** @brief calls a given function on every object 903 * 904 * @param func function to be called 905 * @param p parameter to be passed to each function instance 906 * 907 * @return result (ISC_R_SUCCESS if successful, error code otherwise) 908 */ 909 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *, 910 void *), 911 void *p) 912 { 913 omapi_io_object_t *io = NULL; 914 isc_result_t status; 915 omapi_io_object_t *next = NULL; 916 917 /* 918 * This just calls func on every inner object on the list. It would 919 * be much simpler in general case, but one of the operations could be 920 * release of the objects. Therefore we need to ref count the io and 921 * io->next pointers. 922 */ 923 924 if (omapi_io_states.next) { 925 omapi_object_reference((omapi_object_t**)&io, 926 (omapi_object_t*)omapi_io_states.next, 927 MDL); 928 } 929 930 while(io) { 931 /* If there's a next object, save it */ 932 if (io->next) { 933 omapi_object_reference((omapi_object_t**)&next, 934 (omapi_object_t*)io->next, MDL); 935 } 936 if (io->inner) { 937 status = (*func) (io->inner, p); 938 if (status != ISC_R_SUCCESS) { 939 /* Something went wrong. Let's stop using io & next pointer 940 * and bail out */ 941 omapi_object_dereference((omapi_object_t**)&io, MDL); 942 if (next) { 943 omapi_object_dereference((omapi_object_t**)&next, MDL); 944 } 945 return status; 946 } 947 } 948 /* Update the io pointer and free the next pointer */ 949 omapi_object_dereference((omapi_object_t**)&io, MDL); 950 if (next) { 951 omapi_object_reference((omapi_object_t**)&io, 952 (omapi_object_t*)next, 953 MDL); 954 omapi_object_dereference((omapi_object_t**)&next, MDL); 955 } 956 } 957 958 /* 959 * The only way to get here is when next is NULL. There's no need 960 * to dereference it. 961 */ 962 return ISC_R_SUCCESS; 963 } 964