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