Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / isc-dhcp / omapip / dispatch.c
1 /* dispatch.c
2
3    I/O dispatcher. */
4
5 /*
6  * Copyright (c) 1999-2000 Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38  * To learn more about the Internet Software Consortium, see
39  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
40  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
41  * ``http://www.nominum.com''.
42  */
43
44 #include <omapip/omapip_p.h>
45
46 static omapi_io_object_t omapi_io_states;
47 u_int32_t cur_time;
48
49 OMAPI_OBJECT_ALLOC (omapi_io,
50                     omapi_io_object_t, omapi_type_io_object)
51 OMAPI_OBJECT_ALLOC (omapi_waiter,
52                     omapi_waiter_object_t, omapi_type_waiter)
53
54 /* Register an I/O handle so that we can do asynchronous I/O on it. */
55
56 isc_result_t omapi_register_io_object (omapi_object_t *h,
57                                        int (*readfd) (omapi_object_t *),
58                                        int (*writefd) (omapi_object_t *),
59                                        isc_result_t (*reader)
60                                                 (omapi_object_t *),
61                                        isc_result_t (*writer)
62                                                 (omapi_object_t *),
63                                        isc_result_t (*reaper)
64                                                 (omapi_object_t *))
65 {
66         isc_result_t status;
67         omapi_io_object_t *obj, *p;
68
69         /* omapi_io_states is a static object.   If its reference count
70            is zero, this is the first I/O handle to be registered, so
71            we need to initialize it.   Because there is no inner or outer
72            pointer on this object, and we're setting its refcnt to 1, it
73            will never be freed. */
74         if (!omapi_io_states.refcnt) {
75                 omapi_io_states.refcnt = 1;
76                 omapi_io_states.type = omapi_type_io_object;
77         }
78                 
79         obj = (omapi_io_object_t *)0;
80         status = omapi_io_allocate (&obj, MDL);
81         if (status != ISC_R_SUCCESS)
82                 return status;
83
84         status = omapi_object_reference (&obj -> inner, h, MDL);
85         if (status != ISC_R_SUCCESS) {
86                 omapi_io_dereference (&obj, MDL);
87                 return status;
88         }
89
90         status = omapi_object_reference (&h -> outer,
91                                          (omapi_object_t *)obj, MDL);
92         if (status != ISC_R_SUCCESS) {
93                 omapi_io_dereference (&obj, MDL);
94                 return status;
95         }
96
97         /* Find the last I/O state, if there are any. */
98         for (p = omapi_io_states.next;
99              p && p -> next; p = p -> next)
100                 ;
101         if (p)
102                 omapi_io_reference (&p -> next, obj, MDL);
103         else
104                 omapi_io_reference (&omapi_io_states.next, obj, MDL);
105
106         obj -> readfd = readfd;
107         obj -> writefd = writefd;
108         obj -> reader = reader;
109         obj -> writer = writer;
110         obj -> reaper = reaper;
111         return ISC_R_SUCCESS;
112 }
113
114 isc_result_t omapi_unregister_io_object (omapi_object_t *h)
115 {
116         omapi_io_object_t *p, *obj, *last, *ph;
117
118         if (!h -> outer || h -> outer -> type != omapi_type_io_object)
119                 return ISC_R_INVALIDARG;
120         obj = (omapi_io_object_t *)h -> outer;
121         ph = (omapi_io_object_t *)0;
122         omapi_io_reference (&ph, obj, MDL);
123
124         /* remove from the list of I/O states */
125         last = &omapi_io_states;
126         for (p = omapi_io_states.next; p; p = p -> next) {
127                 if (p == obj) {
128                         omapi_io_dereference (&last -> next, MDL);
129                         omapi_io_reference (&last -> next, p -> next, MDL);
130                         break;
131                 }
132                 last = p;
133         }
134         if (obj -> next)
135                 omapi_io_dereference (&obj -> next, MDL);
136
137         if (obj -> outer) {
138                 if (obj -> outer -> inner == (omapi_object_t *)obj)
139                         omapi_object_dereference (&obj -> outer -> inner,
140                                                   MDL);
141                 omapi_object_dereference (&obj -> outer, MDL);
142         }
143         omapi_object_dereference (&obj -> inner, MDL);
144         omapi_object_dereference (&h -> outer, MDL);
145         omapi_io_dereference (&ph, MDL);
146         return ISC_R_SUCCESS;
147 }
148
149 isc_result_t omapi_dispatch (struct timeval *t)
150 {
151         return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
152                                           t);
153 }
154
155 isc_result_t omapi_wait_for_completion (omapi_object_t *object,
156                                         struct timeval *t)
157 {
158         isc_result_t status;
159         omapi_waiter_object_t *waiter;
160         omapi_object_t *inner;
161
162         if (object) {
163                 waiter = (omapi_waiter_object_t *)0;
164                 status = omapi_waiter_allocate (&waiter, MDL);
165                 if (status != ISC_R_SUCCESS)
166                         return status;
167
168                 /* Paste the waiter object onto the inner object we're
169                    waiting on. */
170                 for (inner = object; inner -> inner; inner = inner -> inner)
171                         ;
172
173                 status = omapi_object_reference (&waiter -> outer, inner, MDL);
174                 if (status != ISC_R_SUCCESS) {
175                         omapi_waiter_dereference (&waiter, MDL);
176                         return status;
177                 }
178                 
179                 status = omapi_object_reference (&inner -> inner,
180                                                  (omapi_object_t *)waiter,
181                                                  MDL);
182                 if (status != ISC_R_SUCCESS) {
183                         omapi_waiter_dereference (&waiter, MDL);
184                         return status;
185                 }
186         } else
187                 waiter = (omapi_waiter_object_t *)0;
188
189         do {
190                 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
191                 if (status != ISC_R_SUCCESS)
192                         return status;
193         } while (!waiter || !waiter -> ready);
194
195         if (waiter -> outer) {
196                 if (waiter -> outer -> inner) {
197                         omapi_object_dereference (&waiter -> outer -> inner,
198                                                   MDL);
199                         if (waiter -> inner)
200                                 omapi_object_reference
201                                         (&waiter -> outer -> inner,
202                                          waiter -> inner, MDL);
203                 }
204                 omapi_object_dereference (&waiter -> outer, MDL);
205         }
206         if (waiter -> inner)
207                 omapi_object_dereference (&waiter -> inner, MDL);
208         
209         status = waiter -> waitstatus;
210         omapi_waiter_dereference (&waiter, MDL);
211         return status;
212 }
213
214 isc_result_t omapi_one_dispatch (omapi_object_t *wo,
215                                  struct timeval *t)
216 {
217         fd_set r, w, x;
218         int max = 0;
219         int count;
220         int desc;
221         struct timeval now, to;
222         omapi_io_object_t *io, *prev;
223         isc_result_t status;
224         omapi_waiter_object_t *waiter;
225         omapi_object_t *tmp = (omapi_object_t *)0;
226
227         if (!wo || wo -> type != omapi_type_waiter)
228                 waiter = (omapi_waiter_object_t *)0;
229         else
230                 waiter = (omapi_waiter_object_t *)wo;
231
232         FD_ZERO (&x);
233
234         /* First, see if the timeout has expired, and if so return. */
235         if (t) {
236                 gettimeofday (&now, (struct timezone *)0);
237                 cur_time = now.tv_sec;
238                 if (now.tv_sec > t -> tv_sec ||
239                     (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
240                         return ISC_R_TIMEDOUT;
241                         
242                 /* We didn't time out, so figure out how long until
243                    we do. */
244                 to.tv_sec = t -> tv_sec - now.tv_sec;
245                 to.tv_usec = t -> tv_usec - now.tv_usec;
246                 if (to.tv_usec < 0) {
247                         to.tv_usec += 1000000;
248                         to.tv_sec--;
249                 }
250
251                 /* It is possible for the timeout to get set larger than
252                    the largest time select() is willing to accept.
253                    Restricting the timeout to a maximum of one day should
254                    work around this.  -DPN.  (Ref: Bug #416) */
255                 if (to.tv_sec > (60 * 60 * 24))
256                         to.tv_sec = 60 * 60 * 24;
257         }
258         
259         /* If the object we're waiting on has reached completion,
260            return now. */
261         if (waiter && waiter -> ready)
262                 return ISC_R_SUCCESS;
263         
264       again:
265         /* If we have no I/O state, we can't proceed. */
266         if (!(io = omapi_io_states.next))
267                 return ISC_R_NOMORE;
268
269         /* Set up the read and write masks. */
270         FD_ZERO (&r);
271         FD_ZERO (&w);
272
273         for (; io; io = io -> next) {
274                 /* Check for a read socket.   If we shouldn't be
275                    trying to read for this I/O object, either there
276                    won't be a readfd function, or it'll return -1. */
277                 if (io -> readfd && io -> inner &&
278                     (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
279                         FD_SET (desc, &r);
280                         if (desc > max)
281                                 max = desc;
282                 }
283                 
284                 /* Same deal for write fdets. */
285                 if (io -> writefd && io -> inner &&
286                     (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
287                         FD_SET (desc, &w);
288                         if (desc > max)
289                                 max = desc;
290                 }
291         }
292
293         /* Wait for a packet or a timeout... XXX */
294 #if 0
295 #if defined (__linux__)
296 #define fds_bits __fds_bits
297 #endif
298         log_error ("dispatch: %d %lx %lx", max,
299                    (unsigned long)r.fds_bits [0],
300                    (unsigned long)w.fds_bits [0]);
301 #endif
302         count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0);
303
304         /* Get the current time... */
305         gettimeofday (&now, (struct timezone *)0);
306         cur_time = now.tv_sec;
307
308         /* We probably have a bad file descriptor.   Figure out which one.
309            When we find it, call the reaper function on it, which will
310            maybe make it go away, and then try again. */
311         if (count < 0) {
312                 struct timeval t0;
313                 omapi_io_object_t *prev = (omapi_io_object_t *)0;
314                 io = (omapi_io_object_t *)0;
315                 if (omapi_io_states.next)
316                         omapi_io_reference (&io, omapi_io_states.next, MDL);
317
318                 while (io) {
319                         omapi_object_t *obj;
320                         FD_ZERO (&r);
321                         FD_ZERO (&w);
322                         t0.tv_sec = t0.tv_usec = 0;
323
324                         if (io -> readfd && io -> inner &&
325                             (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
326                             FD_SET (desc, &r);
327 #if 0
328                             log_error ("read check: %d %lx %lx", max,
329                                        (unsigned long)r.fds_bits [0],
330                                        (unsigned long)w.fds_bits [0]);
331 #endif
332                             count = select (desc + 1, &r, &w, &x, &t0);
333                            bogon:
334                             if (count < 0) {
335                                 log_error ("Bad descriptor %d.", desc);
336                                 for (obj = (omapi_object_t *)io;
337                                      obj -> outer;
338                                      obj = obj -> outer)
339                                         ;
340                                 for (; obj; obj = obj -> inner) {
341                                     omapi_value_t *ov;
342                                     int len;
343                                     const char *s;
344                                     ov = (omapi_value_t *)0;
345                                     omapi_get_value_str (obj,
346                                                          (omapi_object_t *)0,
347                                                          "name", &ov);
348                                     if (ov && ov -> value &&
349                                         (ov -> value -> type ==
350                                          omapi_datatype_string)) {
351                                         s = (char *)
352                                                 ov -> value -> u.buffer.value;
353                                         len = ov -> value -> u.buffer.len;
354                                     } else {
355                                         s = "";
356                                         len = 0;
357                                     }
358                                     log_error ("Object %lx %s%s%.*s",
359                                                (unsigned long)obj,
360                                                obj -> type -> name,
361                                                len ? " " : "",
362                                                len, s);
363                                     if (len)
364                                         omapi_value_dereference (&ov, MDL);
365                                 }
366                                 status = (*(io -> reaper)) (io -> inner);
367                                 if (prev) {
368                                     omapi_io_dereference (&prev -> next, MDL);
369                                     if (io -> next)
370                                         omapi_io_reference (&prev -> next,
371                                                             io -> next, MDL);
372                                 } else {
373                                     omapi_io_dereference
374                                             (&omapi_io_states.next, MDL);
375                                     if (io -> next)
376                                         omapi_io_reference
377                                                 (&omapi_io_states.next,
378                                                  io -> next, MDL);
379                                 }
380                                 omapi_io_dereference (&io, MDL);
381                                 goto again;
382                             }
383                         }
384                         
385                         FD_ZERO (&r);
386                         FD_ZERO (&w);
387                         t0.tv_sec = t0.tv_usec = 0;
388
389                         /* Same deal for write fdets. */
390                         if (io -> writefd && io -> inner &&
391                             (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
392                                 FD_SET (desc, &w);
393                                 count = select (desc + 1, &r, &w, &x, &t0);
394                                 if (count < 0)
395                                         goto bogon;
396                         }
397                         if (prev)
398                                 omapi_io_dereference (&prev, MDL);
399                         omapi_io_reference (&prev, io, MDL);
400                         omapi_io_dereference (&io, MDL);
401                         if (prev -> next)
402                             omapi_io_reference (&io, prev -> next, MDL);
403                 }
404                 if (prev)
405                         omapi_io_dereference (&prev, MDL);
406                 
407         }
408
409         for (io = omapi_io_states.next; io; io = io -> next) {
410                 if (!io -> inner)
411                         continue;
412                 omapi_object_reference (&tmp, io -> inner, MDL);
413                 /* Check for a read descriptor, and if there is one,
414                    see if we got input on that socket. */
415                 if (io -> readfd &&
416                     (desc = (*(io -> readfd)) (tmp)) >= 0) {
417                         if (FD_ISSET (desc, &r))
418                                 status = ((*(io -> reader)) (tmp));
419                                 /* XXX what to do with status? */
420                 }
421                 
422                 /* Same deal for write descriptors. */
423                 if (io -> writefd &&
424                     (desc = (*(io -> writefd)) (tmp)) >= 0)
425                 {
426                         if (FD_ISSET (desc, &w))
427                                 status = ((*(io -> writer)) (tmp));
428                                 /* XXX what to do with status? */
429                 }
430                 omapi_object_dereference (&tmp, MDL);
431         }
432
433         /* Now check for I/O handles that are no longer valid,
434            and remove them from the list. */
435         prev = (omapi_io_object_t *)0;
436         for (io = omapi_io_states.next; io; io = io -> next) {
437                 if (io -> reaper) {
438                         if (io -> inner)
439                                 status = (*(io -> reaper)) (io -> inner);
440                         if (!io -> inner || status != ISC_R_SUCCESS) {
441                                 omapi_io_object_t *tmp =
442                                         (omapi_io_object_t *)0;
443                                 /* Save a reference to the next
444                                    pointer, if there is one. */
445                                 if (io -> next)
446                                         omapi_io_reference (&tmp,
447                                                             io -> next, MDL);
448                                 if (prev) {
449                                         omapi_io_dereference (&prev -> next,
450                                                               MDL);
451                                         if (tmp)
452                                                 omapi_io_reference
453                                                         (&prev -> next,
454                                                          tmp, MDL);
455                                 } else {
456                                         omapi_io_dereference
457                                                 (&omapi_io_states.next, MDL);
458                                         if (tmp)
459                                                 omapi_io_reference
460                                                     (&omapi_io_states.next,
461                                                      tmp, MDL);
462                                         else
463                                                 omapi_signal_in
464                                                         ((omapi_object_t *)
465                                                          &omapi_io_states,
466                                                          "ready");
467                                 }
468                                 if (tmp)
469                                         omapi_io_dereference (&tmp, MDL);
470                         }
471                 }
472                 prev = io;
473         }
474
475         return ISC_R_SUCCESS;
476 }
477
478 isc_result_t omapi_io_set_value (omapi_object_t *h,
479                                  omapi_object_t *id,
480                                  omapi_data_string_t *name,
481                                  omapi_typed_data_t *value)
482 {
483         if (h -> type != omapi_type_io_object)
484                 return ISC_R_INVALIDARG;
485         
486         if (h -> inner && h -> inner -> type -> set_value)
487                 return (*(h -> inner -> type -> set_value))
488                         (h -> inner, id, name, value);
489         return ISC_R_NOTFOUND;
490 }
491
492 isc_result_t omapi_io_get_value (omapi_object_t *h,
493                                  omapi_object_t *id,
494                                  omapi_data_string_t *name,
495                                  omapi_value_t **value)
496 {
497         if (h -> type != omapi_type_io_object)
498                 return ISC_R_INVALIDARG;
499         
500         if (h -> inner && h -> inner -> type -> get_value)
501                 return (*(h -> inner -> type -> get_value))
502                         (h -> inner, id, name, value);
503         return ISC_R_NOTFOUND;
504 }
505
506 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
507 {
508         omapi_io_object_t *obj, *p, *last;
509
510         if (h -> type != omapi_type_io_object)
511                 return ISC_R_INVALIDARG;
512         
513         obj = (omapi_io_object_t *)h;
514
515         /* remove from the list of I/O states */
516         for (p = omapi_io_states.next; p; p = p -> next) {
517                 if (p == obj) {
518                         omapi_io_dereference (&last -> next, MDL);
519                         omapi_io_reference (&last -> next, p -> next, MDL);
520                         omapi_io_dereference (&p, MDL);
521                         break;
522                 }
523                 last = p;
524         }
525                 
526         return ISC_R_SUCCESS;
527 }
528
529 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
530                                       const char *name, va_list ap)
531 {
532         if (h -> type != omapi_type_io_object)
533                 return ISC_R_INVALIDARG;
534         
535         if (h -> inner && h -> inner -> type -> signal_handler)
536                 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
537                                                                   name, ap);
538         return ISC_R_NOTFOUND;
539 }
540
541 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
542                                     omapi_object_t *id,
543                                     omapi_object_t *i)
544 {
545         if (i -> type != omapi_type_io_object)
546                 return ISC_R_INVALIDARG;
547
548         if (i -> inner && i -> inner -> type -> stuff_values)
549                 return (*(i -> inner -> type -> stuff_values)) (c, id,
550                                                                 i -> inner);
551         return ISC_R_SUCCESS;
552 }
553
554 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
555                                           const char *name, va_list ap)
556 {
557         omapi_waiter_object_t *waiter;
558
559         if (h -> type != omapi_type_waiter)
560                 return ISC_R_INVALIDARG;
561         
562         if (!strcmp (name, "ready")) {
563                 waiter = (omapi_waiter_object_t *)h;
564                 waiter -> ready = 1;
565                 waiter -> waitstatus = ISC_R_SUCCESS;
566                 return ISC_R_SUCCESS;
567         }
568
569         if (!strcmp (name, "status")) {
570                 waiter = (omapi_waiter_object_t *)h;
571                 waiter -> ready = 1;
572                 waiter -> waitstatus = va_arg (ap, isc_result_t);
573                 return ISC_R_SUCCESS;
574         }
575
576         if (!strcmp (name, "disconnect")) {
577                 waiter = (omapi_waiter_object_t *)h;
578                 waiter -> ready = 1;
579                 waiter -> waitstatus = ISC_R_CONNRESET;
580                 return ISC_R_SUCCESS;
581         }
582
583         if (h -> inner && h -> inner -> type -> signal_handler)
584                 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
585                                                                   name, ap);
586         return ISC_R_NOTFOUND;
587 }
588
589 isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
590                                                            void *),
591                                      void *p)
592 {
593         omapi_io_object_t *io;
594         isc_result_t status;
595
596         for (io = omapi_io_states.next; io; io = io -> next) {
597                 if (io -> inner) {
598                         status = (*func) (io -> inner, p);
599                         if (status != ISC_R_SUCCESS)
600                                 return status;
601                 }
602         }
603         return ISC_R_SUCCESS;
604 }