omapip/dispatch.c

Go to the documentation of this file.
00001 /* dispatch.c
00002 
00003    I/O dispatcher. */
00004 
00005 /*
00006  * Copyright (c) 2004,2007-2009,2013-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1999-2003 by Internet Software Consortium
00008  *
00009  * Permission to use, copy, modify, and distribute this software for any
00010  * purpose with or without fee is hereby granted, provided that the above
00011  * copyright notice and this permission notice appear in all copies.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00014  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00015  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00016  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00017  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00018  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00019  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00020  *
00021  *   Internet Systems Consortium, Inc.
00022  *   950 Charter Street
00023  *   Redwood City, CA 94063
00024  *   <info@isc.org>
00025  *   https://www.isc.org/
00026  *
00027  */
00028 
00029 #include "dhcpd.h"
00030 
00031 #include <omapip/omapip_p.h>
00032 #include <sys/time.h>
00033 
00034 static omapi_io_object_t omapi_io_states;
00035 struct timeval cur_tv;
00036 
00037 struct eventqueue *rw_queue_empty;
00038 
00039 OMAPI_OBJECT_ALLOC (omapi_io,
00040                     omapi_io_object_t, omapi_type_io_object)
00041 OMAPI_OBJECT_ALLOC (omapi_waiter,
00042                     omapi_waiter_object_t, omapi_type_waiter)
00043 
00044 void
00045 register_eventhandler(struct eventqueue **queue, void (*handler)(void *))
00046 {
00047         struct eventqueue *t, *q;
00048 
00049         /* traverse to end of list */
00050         t = NULL;
00051         for (q = *queue ; q ; q = q->next) {
00052                 if (q->handler == handler)
00053                         return; /* handler already registered */
00054                 t = q;
00055         }
00056                 
00057         q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL));
00058         if (!q)
00059                 log_fatal("register_eventhandler: no memory!");
00060         memset(q, 0, sizeof *q);
00061         if (t)
00062                 t->next = q;
00063         else 
00064                 *queue  = q;
00065         q->handler = handler;
00066         return;
00067 }
00068 
00069 void
00070 unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *))
00071 {
00072         struct eventqueue *t, *q;
00073         
00074         /* traverse to end of list */
00075         t= NULL;
00076         for (q = *queue ; q ; q = q->next) {
00077                 if (q->handler == handler) {
00078                         if (t)
00079                                 t->next = q->next;
00080                         else
00081                                 *queue = q->next;
00082                         dfree(q, MDL); /* Don't access q after this!*/
00083                         break;
00084                 }
00085                 t = q;
00086         }
00087         return;
00088 }
00089 
00090 void
00091 trigger_event(struct eventqueue **queue)
00092 {
00093         struct eventqueue *q;
00094 
00095         for (q=*queue ; q ; q=q->next) {
00096                 if (q->handler) 
00097                         (*q->handler)(NULL);
00098         }
00099 }
00100 
00101 /*
00102  * Callback routine to connect the omapi I/O object and socket with
00103  * the isc socket code.  The isc socket code will call this routine
00104  * which will then call the correct local routine to process the bytes.
00105  * 
00106  * Currently we are always willing to read more data, this should be modified
00107  * so that on connections we don't read more if we already have enough.
00108  *
00109  * If we have more bytes to write we ask the library to call us when
00110  * we can write more.  If we indicate we don't have more to write we need
00111  * to poke the library via isc_socket_fdwatchpoke.
00112  */
00113 
00114 /*
00115  * sockdelete indicates if we are deleting the socket or leaving it in place
00116  * 1 is delete, 0 is leave in place
00117  */
00118 #define SOCKDELETE 1
00119 int
00120 omapi_iscsock_cb(isc_task_t   *task,
00121                  isc_socket_t *socket,
00122                  void         *cbarg,
00123                  int           flags)
00124 {
00125         omapi_io_object_t *obj;
00126         isc_result_t status;
00127 
00128         /* Get the current time... */
00129         gettimeofday (&cur_tv, (struct timezone *)0);
00130 
00131         /* isc socket stuff */
00132 #if SOCKDELETE
00133         /*
00134          * walk through the io states list, if our object is on there
00135          * service it.  if not ignore it.
00136          */
00137         for (obj = omapi_io_states.next;
00138              (obj != NULL) && (obj->next != NULL);
00139              obj = obj->next) {
00140                 if (obj == cbarg)
00141                         break;
00142         }
00143         if (obj == NULL) {
00144                 return(0);
00145         }
00146 #else
00147         /* Not much to be done if we have the wrong type of object. */
00148         if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) {
00149                 log_fatal ("Incorrect object type, must be of type io_object");
00150         }
00151         obj = (omapi_io_object_t *)cbarg;
00152 
00153         /*
00154          * If the object is marked as closed don't try and process
00155          * anything just indicate that we don't want any more.
00156          *
00157          * This should be a temporary fix until we arrange to properly
00158          * close the socket.
00159          */
00160         if (obj->closed == ISC_TRUE) {
00161                 return(0);
00162         }
00163 #endif    
00164 
00165         if ((flags == ISC_SOCKFDWATCH_READ) &&
00166             (obj->reader != NULL) &&
00167             (obj->inner != NULL)) {
00168                 status = obj->reader(obj->inner);
00169                 /* 
00170                  * If we are shutting down (basically tried to
00171                  * read and got no bytes) we don't need to try
00172                  * again.
00173                  */
00174                 if (status == ISC_R_SHUTTINGDOWN)
00175                         return (0);
00176                 /* Otherwise We always ask for more when reading */
00177                 return (1);
00178         } else if ((flags == ISC_SOCKFDWATCH_WRITE) &&
00179                  (obj->writer != NULL) &&
00180                  (obj->inner != NULL)) {
00181                 status = obj->writer(obj->inner);
00182                 /* If the writer has more to write they should return
00183                  * ISC_R_INPROGRESS */
00184                 if (status == ISC_R_INPROGRESS) {
00185                         return (1);
00186                 }
00187         }
00188 
00189         /*
00190          * We get here if we either had an error (inconsistent
00191          * structures etc) or no more to write, tell the socket
00192          * lib we don't have more to do right now.
00193          */
00194         return (0);
00195 }
00196 
00197 /* Register an I/O handle so that we can do asynchronous I/O on it. */
00198 
00199 isc_result_t omapi_register_io_object (omapi_object_t *h,
00200                                        int (*readfd) (omapi_object_t *),
00201                                        int (*writefd) (omapi_object_t *),
00202                                        isc_result_t (*reader)
00203                                                 (omapi_object_t *),
00204                                        isc_result_t (*writer)
00205                                                 (omapi_object_t *),
00206                                        isc_result_t (*reaper)
00207                                                 (omapi_object_t *))
00208 {
00209         isc_result_t status;
00210         omapi_io_object_t *obj, *p;
00211         int fd_flags = 0, fd = 0;
00212 
00213         /* omapi_io_states is a static object.   If its reference count
00214            is zero, this is the first I/O handle to be registered, so
00215            we need to initialize it.   Because there is no inner or outer
00216            pointer on this object, and we're setting its refcnt to 1, it
00217            will never be freed. */
00218         if (!omapi_io_states.refcnt) {
00219                 omapi_io_states.refcnt = 1;
00220                 omapi_io_states.type = omapi_type_io_object;
00221         }
00222                 
00223         obj = (omapi_io_object_t *)0;
00224         status = omapi_io_allocate (&obj, MDL);
00225         if (status != ISC_R_SUCCESS)
00226                 return status;
00227         obj->closed = ISC_FALSE;  /* mark as open */
00228 
00229         status = omapi_object_reference (&obj -> inner, h, MDL);
00230         if (status != ISC_R_SUCCESS) {
00231                 omapi_io_dereference (&obj, MDL);
00232                 return status;
00233         }
00234 
00235         status = omapi_object_reference (&h -> outer,
00236                                          (omapi_object_t *)obj, MDL);
00237         if (status != ISC_R_SUCCESS) {
00238                 omapi_io_dereference (&obj, MDL);
00239                 return status;
00240         }
00241 
00242         /*
00243          * Attach the I/O object to the isc socket library via the 
00244          * fdwatch function.  This allows the socket library to watch
00245          * over a socket that we built.  If there are both a read and
00246          * a write socket we asssume they are the same socket.
00247          */
00248 
00249         if (readfd) {
00250                 fd_flags |= ISC_SOCKFDWATCH_READ;
00251                 fd = readfd(h);
00252         }
00253 
00254         if (writefd) {
00255                 fd_flags |= ISC_SOCKFDWATCH_WRITE;
00256                 fd = writefd(h);
00257         }
00258 
00259         if (fd_flags != 0) {
00260                 status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr,
00261                                                   fd, fd_flags,
00262                                                   omapi_iscsock_cb,
00263                                                   obj,
00264                                                   dhcp_gbl_ctx.task,
00265                                                   &obj->fd);
00266                 if (status != ISC_R_SUCCESS) {
00267                         log_error("Unable to register fd with library %s",
00268                                    isc_result_totext(status));
00269 
00270                         /*sar*/
00271                         /* is this the cleanup we need? */
00272                         omapi_object_dereference(&h->outer, MDL);
00273                         omapi_io_dereference (&obj, MDL);
00274                         return (status);
00275                 }
00276         }
00277 
00278 
00279         /* Find the last I/O state, if there are any. */
00280         for (p = omapi_io_states.next;
00281              p && p -> next; p = p -> next)
00282                 ;
00283         if (p)
00284                 omapi_io_reference (&p -> next, obj, MDL);
00285         else
00286                 omapi_io_reference (&omapi_io_states.next, obj, MDL);
00287 
00288         obj -> readfd = readfd;
00289         obj -> writefd = writefd;
00290         obj -> reader = reader;
00291         obj -> writer = writer;
00292         obj -> reaper = reaper;
00293 
00294         omapi_io_dereference(&obj, MDL);
00295         return ISC_R_SUCCESS;
00296 }
00297 
00298 /*
00299  * ReRegister an I/O handle so that we can do asynchronous I/O on it.
00300  * If the handle doesn't exist we call the register routine to build it.
00301  * If it does exist we change the functions associated with it, and
00302  * repoke the fd code to make it happy.  Neither the objects nor the
00303  * fd are allowed to have changed.
00304  */
00305 
00306 isc_result_t omapi_reregister_io_object (omapi_object_t *h,
00307                                          int (*readfd) (omapi_object_t *),
00308                                          int (*writefd) (omapi_object_t *),
00309                                          isc_result_t (*reader)
00310                                                 (omapi_object_t *),
00311                                          isc_result_t (*writer)
00312                                                 (omapi_object_t *),
00313                                          isc_result_t (*reaper)
00314                                                 (omapi_object_t *))
00315 {
00316         omapi_io_object_t *obj;
00317         int fd_flags = 0;
00318 
00319         if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
00320                 /*
00321                  * If we don't have an object or if the type isn't what 
00322                  * we expect do the normal registration (which will overwrite
00323                  * an incorrect type, that's what we did historically, may
00324                  * want to change that)
00325                  */
00326                 return (omapi_register_io_object (h, readfd, writefd,
00327                                                   reader, writer, reaper));
00328         }
00329 
00330         /* We have an io object of the correct type, try to update it */
00331         /*sar*/
00332         /* Should we validate that the fd matches the previous one?
00333          * It's suppossed to, that's a requirement, don't bother yet */
00334 
00335         obj = (omapi_io_object_t *)h->outer;
00336 
00337         obj->readfd = readfd;
00338         obj->writefd = writefd;
00339         obj->reader = reader;
00340         obj->writer = writer;
00341         obj->reaper = reaper;
00342 
00343         if (readfd) {
00344                 fd_flags |= ISC_SOCKFDWATCH_READ;
00345         }
00346 
00347         if (writefd) {
00348                 fd_flags |= ISC_SOCKFDWATCH_WRITE;
00349         }
00350 
00351         isc_socket_fdwatchpoke(obj->fd, fd_flags);
00352         
00353         return (ISC_R_SUCCESS);
00354 }
00355 
00356 isc_result_t omapi_unregister_io_object (omapi_object_t *h)
00357 {
00358         omapi_io_object_t *obj, *ph;
00359 #if SOCKDELETE
00360         omapi_io_object_t *p, *last; 
00361 #endif
00362 
00363         if (!h -> outer || h -> outer -> type != omapi_type_io_object)
00364                 return DHCP_R_INVALIDARG;
00365         obj = (omapi_io_object_t *)h -> outer;
00366         ph = (omapi_io_object_t *)0;
00367         omapi_io_reference (&ph, obj, MDL);
00368 
00369 #if SOCKDELETE
00370         /*
00371          * For now we leave this out.  We can't clean up the isc socket
00372          * structure cleanly yet so we need to leave the io object in place.
00373          * By leaving it on the io states list we avoid it being freed.
00374          * We also mark it as closed to avoid using it.
00375          */
00376 
00377         /* remove from the list of I/O states */
00378         last = &omapi_io_states;
00379         for (p = omapi_io_states.next; p; p = p -> next) {
00380                 if (p == obj) {
00381                         omapi_io_dereference (&last -> next, MDL);
00382                         omapi_io_reference (&last -> next, p -> next, MDL);
00383                         break;
00384                 }
00385                 last = p;
00386         }
00387         if (obj -> next)
00388                 omapi_io_dereference (&obj -> next, MDL);
00389 #endif
00390 
00391         if (obj -> outer) {
00392                 if (obj -> outer -> inner == (omapi_object_t *)obj)
00393                         omapi_object_dereference (&obj -> outer -> inner,
00394                                                   MDL);
00395                 omapi_object_dereference (&obj -> outer, MDL);
00396         }
00397         omapi_object_dereference (&obj -> inner, MDL);
00398         omapi_object_dereference (&h -> outer, MDL);
00399 
00400 #if SOCKDELETE
00401         /* remove isc socket associations */
00402         if (obj->fd != NULL) {
00403                 isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
00404                                   ISC_SOCKCANCEL_ALL);
00405                 isc_socket_detach(&obj->fd);
00406         }
00407 #else
00408         obj->closed = ISC_TRUE;
00409 #endif
00410 
00411         omapi_io_dereference (&ph, MDL);
00412         return ISC_R_SUCCESS;
00413 }
00414 
00415 isc_result_t omapi_dispatch (struct timeval *t)
00416 {
00417         return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
00418                                           t);
00419 }
00420 
00421 isc_result_t omapi_wait_for_completion (omapi_object_t *object,
00422                                         struct timeval *t)
00423 {
00424         isc_result_t status;
00425         omapi_waiter_object_t *waiter;
00426         omapi_object_t *inner;
00427 
00428         if (object) {
00429                 waiter = (omapi_waiter_object_t *)0;
00430                 status = omapi_waiter_allocate (&waiter, MDL);
00431                 if (status != ISC_R_SUCCESS)
00432                         return status;
00433 
00434                 /* Paste the waiter object onto the inner object we're
00435                    waiting on. */
00436                 for (inner = object; inner -> inner; inner = inner -> inner)
00437                         ;
00438 
00439                 status = omapi_object_reference (&waiter -> outer, inner, MDL);
00440                 if (status != ISC_R_SUCCESS) {
00441                         omapi_waiter_dereference (&waiter, MDL);
00442                         return status;
00443                 }
00444                 
00445                 status = omapi_object_reference (&inner -> inner,
00446                                                  (omapi_object_t *)waiter,
00447                                                  MDL);
00448                 if (status != ISC_R_SUCCESS) {
00449                         omapi_waiter_dereference (&waiter, MDL);
00450                         return status;
00451                 }
00452         } else
00453                 waiter = (omapi_waiter_object_t *)0;
00454 
00455         do {
00456                 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
00457                 if (status != ISC_R_SUCCESS)
00458                         return status;
00459         } while (!waiter || !waiter -> ready);
00460 
00461         if (waiter -> outer) {
00462                 if (waiter -> outer -> inner) {
00463                         omapi_object_dereference (&waiter -> outer -> inner,
00464                                                   MDL);
00465                         if (waiter -> inner)
00466                                 omapi_object_reference
00467                                         (&waiter -> outer -> inner,
00468                                          waiter -> inner, MDL);
00469                 }
00470                 omapi_object_dereference (&waiter -> outer, MDL);
00471         }
00472         if (waiter -> inner)
00473                 omapi_object_dereference (&waiter -> inner, MDL);
00474         
00475         status = waiter -> waitstatus;
00476         omapi_waiter_dereference (&waiter, MDL);
00477         return status;
00478 }
00479 
00480 isc_result_t omapi_one_dispatch (omapi_object_t *wo,
00481                                  struct timeval *t)
00482 {
00483         fd_set r, w, x, rr, ww, xx;
00484         int max = 0;
00485         int count;
00486         int desc;
00487         struct timeval now, to;
00488         omapi_io_object_t *io, *prev, *next;
00489         omapi_waiter_object_t *waiter;
00490         omapi_object_t *tmp = (omapi_object_t *)0;
00491 
00492         if (!wo || wo -> type != omapi_type_waiter)
00493                 waiter = (omapi_waiter_object_t *)0;
00494         else
00495                 waiter = (omapi_waiter_object_t *)wo;
00496 
00497         FD_ZERO (&x);
00498 
00499         /* First, see if the timeout has expired, and if so return. */
00500         if (t) {
00501                 gettimeofday (&now, (struct timezone *)0);
00502                 cur_tv.tv_sec = now.tv_sec;
00503                 cur_tv.tv_usec = now.tv_usec;
00504                 if (now.tv_sec > t -> tv_sec ||
00505                     (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
00506                         return ISC_R_TIMEDOUT;
00507                         
00508                 /* We didn't time out, so figure out how long until
00509                    we do. */
00510                 to.tv_sec = t -> tv_sec - now.tv_sec;
00511                 to.tv_usec = t -> tv_usec - now.tv_usec;
00512                 if (to.tv_usec < 0) {
00513                         to.tv_usec += 1000000;
00514                         to.tv_sec--;
00515                 }
00516 
00517                 /* It is possible for the timeout to get set larger than
00518                    the largest time select() is willing to accept.
00519                    Restricting the timeout to a maximum of one day should
00520                    work around this.  -DPN.  (Ref: Bug #416) */
00521                 if (to.tv_sec > (60 * 60 * 24))
00522                         to.tv_sec = 60 * 60 * 24;
00523         }
00524         
00525         /* If the object we're waiting on has reached completion,
00526            return now. */
00527         if (waiter && waiter -> ready)
00528                 return ISC_R_SUCCESS;
00529         
00530       again:
00531         /* If we have no I/O state, we can't proceed. */
00532         if (!(io = omapi_io_states.next))
00533                 return ISC_R_NOMORE;
00534 
00535         /* Set up the read and write masks. */
00536         FD_ZERO (&r);
00537         FD_ZERO (&w);
00538 
00539         for (; io; io = io -> next) {
00540                 /* Check for a read socket.   If we shouldn't be
00541                    trying to read for this I/O object, either there
00542                    won't be a readfd function, or it'll return -1. */
00543                 if (io -> readfd && io -> inner &&
00544                     (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
00545                         FD_SET (desc, &r);
00546                         if (desc > max)
00547                                 max = desc;
00548                 }
00549                 
00550                 /* Same deal for write fdets. */
00551                 if (io -> writefd && io -> inner &&
00552                     (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
00553                         FD_SET (desc, &w);
00554                         if (desc > max)
00555                                 max = desc;
00556                 }
00557         }
00558 
00559         /* poll if all reader are dry */ 
00560         now.tv_sec = 0;
00561         now.tv_usec = 0;
00562         rr=r; 
00563         ww=w; 
00564         xx=x;
00565 
00566         /* poll once */
00567         count = select(max + 1, &r, &w, &x, &now);
00568         if (!count) {  
00569                 /* We are dry now */ 
00570                 trigger_event(&rw_queue_empty);
00571                 /* Wait for a packet or a timeout... XXX */
00572                 r = rr;
00573                 w = ww;
00574                 x = xx;
00575                 count = select(max + 1, &r, &w, &x, t ? &to : NULL);
00576         }
00577 
00578         /* Get the current time... */
00579         gettimeofday (&cur_tv, (struct timezone *)0);
00580 
00581         /* We probably have a bad file descriptor.   Figure out which one.
00582            When we find it, call the reaper function on it, which will
00583            maybe make it go away, and then try again. */
00584         if (count < 0) {
00585                 struct timeval t0;
00586                 omapi_io_object_t *prev = (omapi_io_object_t *)0;
00587                 io = (omapi_io_object_t *)0;
00588                 if (omapi_io_states.next)
00589                         omapi_io_reference (&io, omapi_io_states.next, MDL);
00590 
00591                 while (io) {
00592                         omapi_object_t *obj;
00593                         FD_ZERO (&r);
00594                         FD_ZERO (&w);
00595                         t0.tv_sec = t0.tv_usec = 0;
00596 
00597                         if (io -> readfd && io -> inner &&
00598                             (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
00599                             FD_SET (desc, &r);
00600                             count = select (desc + 1, &r, &w, &x, &t0);
00601                            bogon:
00602                             if (count < 0) {
00603                                 log_error ("Bad descriptor %d.", desc);
00604                                 for (obj = (omapi_object_t *)io;
00605                                      obj -> outer;
00606                                      obj = obj -> outer)
00607                                         ;
00608                                 for (; obj; obj = obj -> inner) {
00609                                     omapi_value_t *ov;
00610                                     int len;
00611                                     const char *s;
00612                                     ov = (omapi_value_t *)0;
00613                                     omapi_get_value_str (obj,
00614                                                          (omapi_object_t *)0,
00615                                                          "name", &ov);
00616                                     if (ov && ov -> value &&
00617                                         (ov -> value -> type ==
00618                                          omapi_datatype_string)) {
00619                                         s = (char *)
00620                                                 ov -> value -> u.buffer.value;
00621                                         len = ov -> value -> u.buffer.len;
00622                                     } else {
00623                                         s = "";
00624                                         len = 0;
00625                                     }
00626                                     log_error ("Object %lx %s%s%.*s",
00627                                                (unsigned long)obj,
00628                                                obj -> type -> name,
00629                                                len ? " " : "",
00630                                                len, s);
00631                                     if (len)
00632                                         omapi_value_dereference (&ov, MDL);
00633                                 }
00634                                 (*(io -> reaper)) (io -> inner);
00635                                 if (prev) {
00636                                     omapi_io_dereference (&prev -> next, MDL);
00637                                     if (io -> next)
00638                                         omapi_io_reference (&prev -> next,
00639                                                             io -> next, MDL);
00640                                 } else {
00641                                     omapi_io_dereference
00642                                             (&omapi_io_states.next, MDL);
00643                                     if (io -> next)
00644                                         omapi_io_reference
00645                                                 (&omapi_io_states.next,
00646                                                  io -> next, MDL);
00647                                 }
00648                                 omapi_io_dereference (&io, MDL);
00649                                 goto again;
00650                             }
00651                         }
00652                         
00653                         FD_ZERO (&r);
00654                         FD_ZERO (&w);
00655                         t0.tv_sec = t0.tv_usec = 0;
00656 
00657                         /* Same deal for write fdets. */
00658                         if (io -> writefd && io -> inner &&
00659                             (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
00660                                 FD_SET (desc, &w);
00661                                 count = select (desc + 1, &r, &w, &x, &t0);
00662                                 if (count < 0)
00663                                         goto bogon;
00664                         }
00665                         if (prev)
00666                                 omapi_io_dereference (&prev, MDL);
00667                         omapi_io_reference (&prev, io, MDL);
00668                         omapi_io_dereference (&io, MDL);
00669                         if (prev -> next)
00670                             omapi_io_reference (&io, prev -> next, MDL);
00671                 }
00672                 if (prev)
00673                         omapi_io_dereference (&prev, MDL);
00674                 
00675         }
00676 
00677         for (io = omapi_io_states.next; io; io = io -> next) {
00678                 if (!io -> inner)
00679                         continue;
00680                 omapi_object_reference (&tmp, io -> inner, MDL);
00681                 /* Check for a read descriptor, and if there is one,
00682                    see if we got input on that socket. */
00683                 if (io -> readfd &&
00684                     (desc = (*(io -> readfd)) (tmp)) >= 0) {
00685                         if (FD_ISSET (desc, &r))
00686                                 ((*(io -> reader)) (tmp));
00687                 }
00688                 
00689                 /* Same deal for write descriptors. */
00690                 if (io -> writefd &&
00691                     (desc = (*(io -> writefd)) (tmp)) >= 0)
00692                 {
00693                         if (FD_ISSET (desc, &w))
00694                                 ((*(io -> writer)) (tmp));
00695                 }
00696                 omapi_object_dereference (&tmp, MDL);
00697         }
00698 
00699         /* Now check for I/O handles that are no longer valid,
00700            and remove them from the list. */
00701         prev = NULL;
00702         io = NULL;
00703         if (omapi_io_states.next != NULL) {
00704                 omapi_io_reference(&io, omapi_io_states.next, MDL);
00705         }
00706         while (io != NULL) {
00707                 if ((io->inner == NULL) || 
00708                     ((io->reaper != NULL) && 
00709                      ((io->reaper)(io->inner) != ISC_R_SUCCESS))) 
00710                 {
00711 
00712                         omapi_io_object_t *tmp = NULL;
00713                         /* Save a reference to the next
00714                            pointer, if there is one. */
00715                         if (io->next != NULL) {
00716                                 omapi_io_reference(&tmp, io->next, MDL);
00717                                 omapi_io_dereference(&io->next, MDL);
00718                         }
00719                         if (prev != NULL) {
00720                                 omapi_io_dereference(&prev->next, MDL);
00721                                 if (tmp != NULL)
00722                                         omapi_io_reference(&prev->next,
00723                                                            tmp, MDL);
00724                         } else {
00725                                 omapi_io_dereference(&omapi_io_states.next, 
00726                                                      MDL);
00727                                 if (tmp != NULL)
00728                                         omapi_io_reference
00729                                             (&omapi_io_states.next,
00730                                              tmp, MDL);
00731                                 else
00732                                         omapi_signal_in(
00733                                                         (omapi_object_t *)
00734                                                         &omapi_io_states,
00735                                                         "ready");
00736                         }
00737                         if (tmp != NULL)
00738                                 omapi_io_dereference(&tmp, MDL);
00739 
00740                 } else {
00741 
00742                         if (prev != NULL) {
00743                                 omapi_io_dereference(&prev, MDL);
00744                         }
00745                         omapi_io_reference(&prev, io, MDL);
00746                 }
00747 
00748                 /*
00749                  * Equivalent to:
00750                  *   io = io->next
00751                  * But using our reference counting voodoo.
00752                  */
00753                 next = NULL;
00754                 if (io->next != NULL) {
00755                         omapi_io_reference(&next, io->next, MDL);
00756                 }
00757                 omapi_io_dereference(&io, MDL);
00758                 if (next != NULL) {
00759                         omapi_io_reference(&io, next, MDL);
00760                         omapi_io_dereference(&next, MDL);
00761                 }
00762         }
00763         if (prev != NULL) {
00764                 omapi_io_dereference(&prev, MDL);
00765         }
00766 
00767         return ISC_R_SUCCESS;
00768 }
00769 
00770 isc_result_t omapi_io_set_value (omapi_object_t *h,
00771                                  omapi_object_t *id,
00772                                  omapi_data_string_t *name,
00773                                  omapi_typed_data_t *value)
00774 {
00775         if (h -> type != omapi_type_io_object)
00776                 return DHCP_R_INVALIDARG;
00777         
00778         if (h -> inner && h -> inner -> type -> set_value)
00779                 return (*(h -> inner -> type -> set_value))
00780                         (h -> inner, id, name, value);
00781         return ISC_R_NOTFOUND;
00782 }
00783 
00784 isc_result_t omapi_io_get_value (omapi_object_t *h,
00785                                  omapi_object_t *id,
00786                                  omapi_data_string_t *name,
00787                                  omapi_value_t **value)
00788 {
00789         if (h -> type != omapi_type_io_object)
00790                 return DHCP_R_INVALIDARG;
00791         
00792         if (h -> inner && h -> inner -> type -> get_value)
00793                 return (*(h -> inner -> type -> get_value))
00794                         (h -> inner, id, name, value);
00795         return ISC_R_NOTFOUND;
00796 }
00797 
00798 /* omapi_io_destroy (object, MDL);
00799  *
00800  *      Find the requested IO [object] and remove it from the list of io
00801  * states, causing the cleanup functions to destroy it.  Note that we must
00802  * hold a reference on the object while moving its ->next reference and
00803  * removing the reference in the chain to the target object...otherwise it
00804  * may be cleaned up from under us.
00805  */
00806 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
00807 {
00808         omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
00809 
00810         if (h -> type != omapi_type_io_object)
00811                 return DHCP_R_INVALIDARG;
00812         
00813         /* remove from the list of I/O states */
00814         for (p = omapi_io_states.next; p; p = p -> next) {
00815                 if (p == (omapi_io_object_t *)h) {
00816                         omapi_io_reference (&obj, p, MDL);
00817 
00818                         if (last)
00819                                 holder = &last -> next;
00820                         else
00821                                 holder = &omapi_io_states.next;
00822 
00823                         omapi_io_dereference (holder, MDL);
00824 
00825                         if (obj -> next) {
00826                                 omapi_io_reference (holder, obj -> next, MDL);
00827                                 omapi_io_dereference (&obj -> next, MDL);
00828                         }
00829 
00830                         return omapi_io_dereference (&obj, MDL);
00831                 }
00832                 last = p;
00833         }
00834 
00835         return ISC_R_NOTFOUND;
00836 }
00837 
00838 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
00839                                       const char *name, va_list ap)
00840 {
00841         if (h -> type != omapi_type_io_object)
00842                 return DHCP_R_INVALIDARG;
00843         
00844         if (h -> inner && h -> inner -> type -> signal_handler)
00845                 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
00846                                                                   name, ap);
00847         return ISC_R_NOTFOUND;
00848 }
00849 
00850 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
00851                                     omapi_object_t *id,
00852                                     omapi_object_t *i)
00853 {
00854         if (i -> type != omapi_type_io_object)
00855                 return DHCP_R_INVALIDARG;
00856 
00857         if (i -> inner && i -> inner -> type -> stuff_values)
00858                 return (*(i -> inner -> type -> stuff_values)) (c, id,
00859                                                                 i -> inner);
00860         return ISC_R_SUCCESS;
00861 }
00862 
00863 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
00864                                           const char *name, va_list ap)
00865 {
00866         omapi_waiter_object_t *waiter;
00867 
00868         if (h -> type != omapi_type_waiter)
00869                 return DHCP_R_INVALIDARG;
00870         
00871         if (!strcmp (name, "ready")) {
00872                 waiter = (omapi_waiter_object_t *)h;
00873                 waiter -> ready = 1;
00874                 waiter -> waitstatus = ISC_R_SUCCESS;
00875                 return ISC_R_SUCCESS;
00876         }
00877 
00878         if (!strcmp(name, "status")) {
00879                 waiter = (omapi_waiter_object_t *)h;
00880                 waiter->ready = 1;
00881                 waiter->waitstatus = va_arg(ap, isc_result_t);
00882                 return ISC_R_SUCCESS;
00883         }
00884 
00885         if (!strcmp (name, "disconnect")) {
00886                 waiter = (omapi_waiter_object_t *)h;
00887                 waiter -> ready = 1;
00888                 waiter -> waitstatus = DHCP_R_CONNRESET;
00889                 return ISC_R_SUCCESS;
00890         }
00891 
00892         if (h -> inner && h -> inner -> type -> signal_handler)
00893                 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
00894                                                                   name, ap);
00895         return ISC_R_NOTFOUND;
00896 }
00897 
00905 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
00906                                                            void *),
00907                                      void *p)
00908 {
00909         omapi_io_object_t *io = NULL;
00910         isc_result_t status;
00911         omapi_io_object_t *next = NULL;
00912 
00913         /*
00914          * This just calls func on every inner object on the list. It would
00915          * be much simpler in general case, but one of the operations could be
00916          * release of the objects. Therefore we need to ref count the io and
00917          * io->next pointers.
00918          */
00919 
00920         if (omapi_io_states.next) {
00921                 omapi_object_reference((omapi_object_t**)&io,
00922                                        (omapi_object_t*)omapi_io_states.next,
00923                                        MDL);
00924         }
00925 
00926         while(io) {
00927             /* If there's a next object, save it */
00928             if (io->next) {
00929                 omapi_object_reference((omapi_object_t**)&next,
00930                                        (omapi_object_t*)io->next, MDL);
00931             }
00932             if (io->inner) {
00933                 status = (*func) (io->inner, p);
00934                 if (status != ISC_R_SUCCESS) {
00935                     /* Something went wrong. Let's stop using io & next pointer
00936                      * and bail out */
00937                     omapi_object_dereference((omapi_object_t**)&io, MDL);
00938                     if (next) {
00939                         omapi_object_dereference((omapi_object_t**)&next, MDL);
00940                     }
00941                     return status;
00942                 }
00943             }
00944             /* Update the io pointer and free the next pointer */
00945             omapi_object_dereference((omapi_object_t**)&io, MDL);
00946             if (next) {
00947                 omapi_object_reference((omapi_object_t**)&io,
00948                                        (omapi_object_t*)next,
00949                                        MDL);
00950                 omapi_object_dereference((omapi_object_t**)&next, MDL);
00951             }
00952         }
00953 
00954         /*
00955          * The only way to get here is when next is NULL. There's no need
00956          * to dereference it.
00957          */
00958         return ISC_R_SUCCESS;
00959 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1