]>
Commit | Line | Data |
---|---|---|
61b844bf TL |
1 | /* dispatch.c |
2 | ||
3 | I/O dispatcher. */ | |
4 | ||
5 | /* | |
49a7fb58 | 6 | * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1999-2003 by Internet Software Consortium |
61b844bf | 8 | * |
7512d88b TM |
9 | * This Source Code Form is subject to the terms of the Mozilla Public |
10 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |
11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
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 | 21 | * Internet Systems Consortium, Inc. |
429a56d7 TM |
22 | * PO Box 360 |
23 | * Newmarket, NH 03857 USA | |
98311e4b | 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 | } | |
f6b8f48d | 56 | |
6368a1bd DH |
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; | |
f6b8f48d | 63 | else |
6368a1bd DH |
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; | |
f6b8f48d | 73 | |
6368a1bd DH |
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) { | |
f6b8f48d | 96 | if (q->handler) |
6368a1bd DH |
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. | |
f6b8f48d | 105 | * |
98bf1607 SR |
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 | } | |
f6b8f48d | 162 | #endif |
8fa0112d | 163 | |
98bf1607 SR |
164 | if ((flags == ISC_SOCKFDWATCH_READ) && |
165 | (obj->reader != NULL) && | |
166 | (obj->inner != NULL)) { | |
1e2a127b | 167 | status = obj->reader(obj->inner); |
f6b8f48d | 168 | /* |
1e2a127b SR |
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 | } | |
f6b8f48d | 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 | 241 | /* |
f6b8f48d | 242 | * Attach the I/O object to the isc socket library via the |
98bf1607 SR |
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 | 319 | /* |
f6b8f48d | 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); | |
f6b8f48d | 351 | |
0493fdca SR |
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 | |
f6b8f48d | 359 | omapi_io_object_t *p, *last; |
8fa0112d | 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 | { | |
7f152466 TM |
416 | #ifdef DEBUG_PROTOCOL |
417 | log_debug("omapi_dispatch()"); | |
418 | #endif | |
61b844bf | 419 | return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, |
7f152466 | 420 | |
61b844bf TL |
421 | t); |
422 | } | |
423 | ||
424 | isc_result_t omapi_wait_for_completion (omapi_object_t *object, | |
425 | struct timeval *t) | |
426 | { | |
7f152466 TM |
427 | #ifdef DEBUG_PROTOCOL |
428 | if (t) { | |
429 | log_debug ("omapi_wait_for_completion(%u.%u secs)", | |
430 | (unsigned int)(t->tv_sec), | |
431 | (unsigned int)(t->tv_usec)); | |
432 | } else { | |
433 | log_debug ("omapi_wait_for_completion(no timeout)"); | |
434 | } | |
435 | #endif | |
61b844bf TL |
436 | isc_result_t status; |
437 | omapi_waiter_object_t *waiter; | |
438 | omapi_object_t *inner; | |
439 | ||
440 | if (object) { | |
20916cae TL |
441 | waiter = (omapi_waiter_object_t *)0; |
442 | status = omapi_waiter_allocate (&waiter, MDL); | |
443 | if (status != ISC_R_SUCCESS) | |
444 | return status; | |
61b844bf TL |
445 | |
446 | /* Paste the waiter object onto the inner object we're | |
447 | waiting on. */ | |
448 | for (inner = object; inner -> inner; inner = inner -> inner) | |
449 | ; | |
450 | ||
4bd8800e | 451 | status = omapi_object_reference (&waiter -> outer, inner, MDL); |
61b844bf | 452 | if (status != ISC_R_SUCCESS) { |
20916cae | 453 | omapi_waiter_dereference (&waiter, MDL); |
61b844bf TL |
454 | return status; |
455 | } | |
f6b8f48d | 456 | |
61b844bf TL |
457 | status = omapi_object_reference (&inner -> inner, |
458 | (omapi_object_t *)waiter, | |
4bd8800e | 459 | MDL); |
61b844bf | 460 | if (status != ISC_R_SUCCESS) { |
20916cae | 461 | omapi_waiter_dereference (&waiter, MDL); |
61b844bf TL |
462 | return status; |
463 | } | |
464 | } else | |
465 | waiter = (omapi_waiter_object_t *)0; | |
466 | ||
467 | do { | |
6a4c4be8 | 468 | status = omapi_one_dispatch ((omapi_object_t *)waiter, t); |
7f152466 TM |
469 | if (status != ISC_R_SUCCESS) { |
470 | #ifdef DEBUG_PROTOCOL | |
471 | log_debug ("- call to omapi_one_dispatch failed: %s", | |
472 | isc_result_totext (status)); | |
473 | #endif | |
474 | /* Break out on failure, to ensure we free up the waiter(s) */ | |
475 | break; | |
476 | } | |
61b844bf TL |
477 | } while (!waiter || !waiter -> ready); |
478 | ||
7f152466 | 479 | |
727ebc3a TL |
480 | if (waiter -> outer) { |
481 | if (waiter -> outer -> inner) { | |
482 | omapi_object_dereference (&waiter -> outer -> inner, | |
4bd8800e | 483 | MDL); |
727ebc3a TL |
484 | if (waiter -> inner) |
485 | omapi_object_reference | |
486 | (&waiter -> outer -> inner, | |
4bd8800e | 487 | waiter -> inner, MDL); |
727ebc3a | 488 | } |
4bd8800e | 489 | omapi_object_dereference (&waiter -> outer, MDL); |
727ebc3a TL |
490 | } |
491 | if (waiter -> inner) | |
4bd8800e | 492 | omapi_object_dereference (&waiter -> inner, MDL); |
f6b8f48d | 493 | |
7f152466 TM |
494 | if (status == ISC_R_SUCCESS) { |
495 | /* If the invocation worked, return the server's | |
496 | * execution status */ | |
497 | status = waiter -> waitstatus; | |
498 | } | |
499 | ||
20916cae | 500 | omapi_waiter_dereference (&waiter, MDL); |
86a9cf83 | 501 | return status; |
61b844bf TL |
502 | } |
503 | ||
6a4c4be8 | 504 | isc_result_t omapi_one_dispatch (omapi_object_t *wo, |
61b844bf TL |
505 | struct timeval *t) |
506 | { | |
7f152466 TM |
507 | #ifdef DEBUG_PROTOCOL |
508 | log_debug ("omapi_one_dispatch()"); | |
509 | #endif | |
6368a1bd | 510 | fd_set r, w, x, rr, ww, xx; |
61b844bf TL |
511 | int max = 0; |
512 | int count; | |
513 | int desc; | |
514 | struct timeval now, to; | |
4619c0a2 | 515 | omapi_io_object_t *io, *prev, *next; |
6a4c4be8 | 516 | omapi_waiter_object_t *waiter; |
b6237fb2 | 517 | omapi_object_t *tmp = (omapi_object_t *)0; |
6a4c4be8 TL |
518 | |
519 | if (!wo || wo -> type != omapi_type_waiter) | |
520 | waiter = (omapi_waiter_object_t *)0; | |
521 | else | |
522 | waiter = (omapi_waiter_object_t *)wo; | |
61b844bf TL |
523 | |
524 | FD_ZERO (&x); | |
525 | ||
526 | /* First, see if the timeout has expired, and if so return. */ | |
527 | if (t) { | |
528 | gettimeofday (&now, (struct timezone *)0); | |
be62cf06 FD |
529 | cur_tv.tv_sec = now.tv_sec; |
530 | cur_tv.tv_usec = now.tv_usec; | |
61b844bf TL |
531 | if (now.tv_sec > t -> tv_sec || |
532 | (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) | |
533 | return ISC_R_TIMEDOUT; | |
f6b8f48d | 534 | |
61b844bf TL |
535 | /* We didn't time out, so figure out how long until |
536 | we do. */ | |
537 | to.tv_sec = t -> tv_sec - now.tv_sec; | |
538 | to.tv_usec = t -> tv_usec - now.tv_usec; | |
539 | if (to.tv_usec < 0) { | |
540 | to.tv_usec += 1000000; | |
541 | to.tv_sec--; | |
542 | } | |
d01dde76 DN |
543 | |
544 | /* It is possible for the timeout to get set larger than | |
545 | the largest time select() is willing to accept. | |
546 | Restricting the timeout to a maximum of one day should | |
547 | work around this. -DPN. (Ref: Bug #416) */ | |
548 | if (to.tv_sec > (60 * 60 * 24)) | |
549 | to.tv_sec = 60 * 60 * 24; | |
61b844bf | 550 | } |
f6b8f48d | 551 | |
61b844bf TL |
552 | /* If the object we're waiting on has reached completion, |
553 | return now. */ | |
554 | if (waiter && waiter -> ready) | |
555 | return ISC_R_SUCCESS; | |
f6b8f48d | 556 | |
cfb3f45d | 557 | again: |
61b844bf TL |
558 | /* If we have no I/O state, we can't proceed. */ |
559 | if (!(io = omapi_io_states.next)) | |
560 | return ISC_R_NOMORE; | |
561 | ||
562 | /* Set up the read and write masks. */ | |
563 | FD_ZERO (&r); | |
564 | FD_ZERO (&w); | |
565 | ||
566 | for (; io; io = io -> next) { | |
567 | /* Check for a read socket. If we shouldn't be | |
568 | trying to read for this I/O object, either there | |
569 | won't be a readfd function, or it'll return -1. */ | |
d8c46740 | 570 | if (io -> readfd && io -> inner && |
61b844bf TL |
571 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { |
572 | FD_SET (desc, &r); | |
573 | if (desc > max) | |
574 | max = desc; | |
575 | } | |
f6b8f48d | 576 | |
61b844bf | 577 | /* Same deal for write fdets. */ |
d8c46740 | 578 | if (io -> writefd && io -> inner && |
61b844bf | 579 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) { |
7f152466 TM |
580 | /* This block avoids adding writefds that are already connected |
581 | * but that do not have data waiting to write. This avoids | |
582 | * select() calls dropping immediately simply because the | |
583 | * the writefd is ready to write. Without this synchronous | |
584 | * waiting becomes CPU intensive polling */ | |
585 | if (io->inner && io->inner->type == omapi_type_connection) { | |
586 | omapi_connection_object_t* c; | |
587 | c = (omapi_connection_object_t *)(io->inner); | |
588 | if (c->state == omapi_connection_connected && c->out_bytes == 0) { | |
589 | /* We are already connected and have no data waiting to | |
590 | * be written, so we avoid registering the fd. */ | |
591 | #ifdef DEBUG_PROTOCOL | |
592 | log_debug ("--- Connected, nothing to write, skip writefd\n"); | |
593 | #endif | |
594 | continue; | |
595 | } | |
596 | } | |
597 | ||
598 | ||
61b844bf TL |
599 | FD_SET (desc, &w); |
600 | if (desc > max) | |
601 | max = desc; | |
602 | } | |
603 | } | |
604 | ||
f6b8f48d | 605 | /* poll if all reader are dry */ |
6368a1bd DH |
606 | now.tv_sec = 0; |
607 | now.tv_usec = 0; | |
f6b8f48d TM |
608 | rr=r; |
609 | ww=w; | |
6368a1bd DH |
610 | xx=x; |
611 | ||
612 | /* poll once */ | |
613 | count = select(max + 1, &r, &w, &x, &now); | |
f6b8f48d TM |
614 | if (!count) { |
615 | /* We are dry now */ | |
6368a1bd DH |
616 | trigger_event(&rw_queue_empty); |
617 | /* Wait for a packet or a timeout... XXX */ | |
f9453d21 DH |
618 | r = rr; |
619 | w = ww; | |
620 | x = xx; | |
7f152466 TM |
621 | |
622 | #ifdef DEBUG_PROTOCOL | |
623 | if (t) { | |
624 | log_debug (" calling select with timout: %u.%u secs", | |
625 | (unsigned int)(to.tv_sec), | |
626 | (unsigned int)(to.tv_usec)); | |
627 | } | |
628 | #endif | |
f9453d21 | 629 | count = select(max + 1, &r, &w, &x, t ? &to : NULL); |
6368a1bd | 630 | } |
61b844bf TL |
631 | |
632 | /* Get the current time... */ | |
be62cf06 | 633 | gettimeofday (&cur_tv, (struct timezone *)0); |
61b844bf | 634 | |
cfb3f45d TL |
635 | /* We probably have a bad file descriptor. Figure out which one. |
636 | When we find it, call the reaper function on it, which will | |
637 | maybe make it go away, and then try again. */ | |
638 | if (count < 0) { | |
639 | struct timeval t0; | |
9bf59e83 TL |
640 | omapi_io_object_t *prev = (omapi_io_object_t *)0; |
641 | io = (omapi_io_object_t *)0; | |
642 | if (omapi_io_states.next) | |
643 | omapi_io_reference (&io, omapi_io_states.next, MDL); | |
cfb3f45d | 644 | |
9bf59e83 | 645 | while (io) { |
cfb3f45d TL |
646 | omapi_object_t *obj; |
647 | FD_ZERO (&r); | |
648 | FD_ZERO (&w); | |
649 | t0.tv_sec = t0.tv_usec = 0; | |
650 | ||
651 | if (io -> readfd && io -> inner && | |
652 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { | |
653 | FD_SET (desc, &r); | |
cfb3f45d TL |
654 | count = select (desc + 1, &r, &w, &x, &t0); |
655 | bogon: | |
656 | if (count < 0) { | |
657 | log_error ("Bad descriptor %d.", desc); | |
658 | for (obj = (omapi_object_t *)io; | |
659 | obj -> outer; | |
660 | obj = obj -> outer) | |
661 | ; | |
645eab7b TL |
662 | for (; obj; obj = obj -> inner) { |
663 | omapi_value_t *ov; | |
664 | int len; | |
665 | const char *s; | |
666 | ov = (omapi_value_t *)0; | |
667 | omapi_get_value_str (obj, | |
668 | (omapi_object_t *)0, | |
669 | "name", &ov); | |
670 | if (ov && ov -> value && | |
671 | (ov -> value -> type == | |
672 | omapi_datatype_string)) { | |
673 | s = (char *) | |
674 | ov -> value -> u.buffer.value; | |
675 | len = ov -> value -> u.buffer.len; | |
676 | } else { | |
677 | s = ""; | |
678 | len = 0; | |
679 | } | |
680 | log_error ("Object %lx %s%s%.*s", | |
681 | (unsigned long)obj, | |
682 | obj -> type -> name, | |
683 | len ? " " : "", | |
684 | len, s); | |
685 | if (len) | |
686 | omapi_value_dereference (&ov, MDL); | |
687 | } | |
98311e4b | 688 | (*(io -> reaper)) (io -> inner); |
9bf59e83 TL |
689 | if (prev) { |
690 | omapi_io_dereference (&prev -> next, MDL); | |
691 | if (io -> next) | |
692 | omapi_io_reference (&prev -> next, | |
693 | io -> next, MDL); | |
694 | } else { | |
695 | omapi_io_dereference | |
696 | (&omapi_io_states.next, MDL); | |
697 | if (io -> next) | |
698 | omapi_io_reference | |
699 | (&omapi_io_states.next, | |
700 | io -> next, MDL); | |
701 | } | |
702 | omapi_io_dereference (&io, MDL); | |
cfb3f45d TL |
703 | goto again; |
704 | } | |
705 | } | |
f6b8f48d | 706 | |
cfb3f45d TL |
707 | FD_ZERO (&r); |
708 | FD_ZERO (&w); | |
709 | t0.tv_sec = t0.tv_usec = 0; | |
710 | ||
711 | /* Same deal for write fdets. */ | |
712 | if (io -> writefd && io -> inner && | |
713 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) { | |
714 | FD_SET (desc, &w); | |
cfb3f45d TL |
715 | count = select (desc + 1, &r, &w, &x, &t0); |
716 | if (count < 0) | |
717 | goto bogon; | |
718 | } | |
9bf59e83 TL |
719 | if (prev) |
720 | omapi_io_dereference (&prev, MDL); | |
721 | omapi_io_reference (&prev, io, MDL); | |
722 | omapi_io_dereference (&io, MDL); | |
723 | if (prev -> next) | |
724 | omapi_io_reference (&io, prev -> next, MDL); | |
cfb3f45d | 725 | } |
9bf59e83 TL |
726 | if (prev) |
727 | omapi_io_dereference (&prev, MDL); | |
f6b8f48d | 728 | |
cfb3f45d | 729 | } |
61b844bf TL |
730 | |
731 | for (io = omapi_io_states.next; io; io = io -> next) { | |
d8c46740 TL |
732 | if (!io -> inner) |
733 | continue; | |
b6237fb2 | 734 | omapi_object_reference (&tmp, io -> inner, MDL); |
61b844bf TL |
735 | /* Check for a read descriptor, and if there is one, |
736 | see if we got input on that socket. */ | |
737 | if (io -> readfd && | |
b6237fb2 | 738 | (desc = (*(io -> readfd)) (tmp)) >= 0) { |
7f152466 | 739 | if (FD_ISSET (desc, &r)) { |
98311e4b | 740 | ((*(io -> reader)) (tmp)); |
7f152466 | 741 | } |
61b844bf | 742 | } |
f6b8f48d | 743 | |
61b844bf TL |
744 | /* Same deal for write descriptors. */ |
745 | if (io -> writefd && | |
b6237fb2 | 746 | (desc = (*(io -> writefd)) (tmp)) >= 0) |
61b844bf | 747 | { |
7f152466 | 748 | if (FD_ISSET (desc, &w)) { |
98311e4b | 749 | ((*(io -> writer)) (tmp)); |
7f152466 | 750 | } |
61b844bf | 751 | } |
b6237fb2 | 752 | omapi_object_dereference (&tmp, MDL); |
61b844bf TL |
753 | } |
754 | ||
755 | /* Now check for I/O handles that are no longer valid, | |
756 | and remove them from the list. */ | |
4619c0a2 DH |
757 | prev = NULL; |
758 | io = NULL; | |
759 | if (omapi_io_states.next != NULL) { | |
760 | omapi_io_reference(&io, omapi_io_states.next, MDL); | |
761 | } | |
762 | while (io != NULL) { | |
f6b8f48d TM |
763 | if ((io->inner == NULL) || |
764 | ((io->reaper != NULL) && | |
765 | ((io->reaper)(io->inner) != ISC_R_SUCCESS))) | |
4619c0a2 DH |
766 | { |
767 | ||
768 | omapi_io_object_t *tmp = NULL; | |
769 | /* Save a reference to the next | |
770 | pointer, if there is one. */ | |
771 | if (io->next != NULL) { | |
772 | omapi_io_reference(&tmp, io->next, MDL); | |
773 | omapi_io_dereference(&io->next, MDL); | |
61b844bf | 774 | } |
4619c0a2 DH |
775 | if (prev != NULL) { |
776 | omapi_io_dereference(&prev->next, MDL); | |
777 | if (tmp != NULL) | |
778 | omapi_io_reference(&prev->next, | |
779 | tmp, MDL); | |
780 | } else { | |
f6b8f48d | 781 | omapi_io_dereference(&omapi_io_states.next, |
4619c0a2 DH |
782 | MDL); |
783 | if (tmp != NULL) | |
784 | omapi_io_reference | |
785 | (&omapi_io_states.next, | |
786 | tmp, MDL); | |
787 | else | |
788 | omapi_signal_in( | |
789 | (omapi_object_t *) | |
790 | &omapi_io_states, | |
791 | "ready"); | |
792 | } | |
793 | if (tmp != NULL) | |
794 | omapi_io_dereference(&tmp, MDL); | |
795 | ||
796 | } else { | |
797 | ||
798 | if (prev != NULL) { | |
799 | omapi_io_dereference(&prev, MDL); | |
800 | } | |
801 | omapi_io_reference(&prev, io, MDL); | |
61b844bf | 802 | } |
4619c0a2 DH |
803 | |
804 | /* | |
805 | * Equivalent to: | |
806 | * io = io->next | |
807 | * But using our reference counting voodoo. | |
808 | */ | |
809 | next = NULL; | |
810 | if (io->next != NULL) { | |
811 | omapi_io_reference(&next, io->next, MDL); | |
812 | } | |
813 | omapi_io_dereference(&io, MDL); | |
814 | if (next != NULL) { | |
815 | omapi_io_reference(&io, next, MDL); | |
816 | omapi_io_dereference(&next, MDL); | |
817 | } | |
818 | } | |
819 | if (prev != NULL) { | |
820 | omapi_io_dereference(&prev, MDL); | |
61b844bf TL |
821 | } |
822 | ||
823 | return ISC_R_SUCCESS; | |
824 | } | |
825 | ||
826 | isc_result_t omapi_io_set_value (omapi_object_t *h, | |
827 | omapi_object_t *id, | |
828 | omapi_data_string_t *name, | |
829 | omapi_typed_data_t *value) | |
830 | { | |
831 | if (h -> type != omapi_type_io_object) | |
98bf1607 | 832 | return DHCP_R_INVALIDARG; |
f6b8f48d | 833 | |
61b844bf TL |
834 | if (h -> inner && h -> inner -> type -> set_value) |
835 | return (*(h -> inner -> type -> set_value)) | |
836 | (h -> inner, id, name, value); | |
837 | return ISC_R_NOTFOUND; | |
838 | } | |
839 | ||
840 | isc_result_t omapi_io_get_value (omapi_object_t *h, | |
841 | omapi_object_t *id, | |
842 | omapi_data_string_t *name, | |
843 | omapi_value_t **value) | |
844 | { | |
845 | if (h -> type != omapi_type_io_object) | |
98bf1607 | 846 | return DHCP_R_INVALIDARG; |
f6b8f48d | 847 | |
61b844bf TL |
848 | if (h -> inner && h -> inner -> type -> get_value) |
849 | return (*(h -> inner -> type -> get_value)) | |
850 | (h -> inner, id, name, value); | |
851 | return ISC_R_NOTFOUND; | |
852 | } | |
853 | ||
98311e4b DH |
854 | /* omapi_io_destroy (object, MDL); |
855 | * | |
20ae1aff | 856 | * Find the requested IO [object] and remove it from the list of io |
98311e4b DH |
857 | * states, causing the cleanup functions to destroy it. Note that we must |
858 | * hold a reference on the object while moving its ->next reference and | |
859 | * removing the reference in the chain to the target object...otherwise it | |
860 | * may be cleaned up from under us. | |
861 | */ | |
4bd8800e | 862 | isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line) |
61b844bf | 863 | { |
98311e4b | 864 | omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder; |
bdcaf7b9 | 865 | |
61b844bf | 866 | if (h -> type != omapi_type_io_object) |
98bf1607 | 867 | return DHCP_R_INVALIDARG; |
f6b8f48d | 868 | |
b6237fb2 TL |
869 | /* remove from the list of I/O states */ |
870 | for (p = omapi_io_states.next; p; p = p -> next) { | |
98311e4b DH |
871 | if (p == (omapi_io_object_t *)h) { |
872 | omapi_io_reference (&obj, p, MDL); | |
873 | ||
874 | if (last) | |
875 | holder = &last -> next; | |
876 | else | |
877 | holder = &omapi_io_states.next; | |
878 | ||
879 | omapi_io_dereference (holder, MDL); | |
880 | ||
881 | if (obj -> next) { | |
882 | omapi_io_reference (holder, obj -> next, MDL); | |
883 | omapi_io_dereference (&obj -> next, MDL); | |
884 | } | |
885 | ||
886 | return omapi_io_dereference (&obj, MDL); | |
bdcaf7b9 | 887 | } |
b6237fb2 | 888 | last = p; |
bdcaf7b9 | 889 | } |
98311e4b DH |
890 | |
891 | return ISC_R_NOTFOUND; | |
61b844bf TL |
892 | } |
893 | ||
894 | isc_result_t omapi_io_signal_handler (omapi_object_t *h, | |
b1b7b521 | 895 | const char *name, va_list ap) |
61b844bf | 896 | { |
7f152466 TM |
897 | #ifdef DEBUG_PROTOCOL |
898 | log_debug ("omapi_io_signal_handler(%s)", name); | |
899 | #endif | |
61b844bf | 900 | if (h -> type != omapi_type_io_object) |
98bf1607 | 901 | return DHCP_R_INVALIDARG; |
f6b8f48d | 902 | |
61b844bf TL |
903 | if (h -> inner && h -> inner -> type -> signal_handler) |
904 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
905 | name, ap); | |
906 | return ISC_R_NOTFOUND; | |
907 | } | |
908 | ||
909 | isc_result_t omapi_io_stuff_values (omapi_object_t *c, | |
910 | omapi_object_t *id, | |
911 | omapi_object_t *i) | |
912 | { | |
913 | if (i -> type != omapi_type_io_object) | |
98bf1607 | 914 | return DHCP_R_INVALIDARG; |
61b844bf TL |
915 | |
916 | if (i -> inner && i -> inner -> type -> stuff_values) | |
917 | return (*(i -> inner -> type -> stuff_values)) (c, id, | |
918 | i -> inner); | |
919 | return ISC_R_SUCCESS; | |
920 | } | |
921 | ||
922 | isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, | |
b1b7b521 | 923 | const char *name, va_list ap) |
61b844bf TL |
924 | { |
925 | omapi_waiter_object_t *waiter; | |
926 | ||
7f152466 TM |
927 | #ifdef DEBUG_PROTOCOL |
928 | log_debug ("omapi_waiter_signal_handler(%s)", name); | |
929 | #endif | |
61b844bf | 930 | if (h -> type != omapi_type_waiter) |
98bf1607 | 931 | return DHCP_R_INVALIDARG; |
f6b8f48d | 932 | |
61b844bf TL |
933 | if (!strcmp (name, "ready")) { |
934 | waiter = (omapi_waiter_object_t *)h; | |
935 | waiter -> ready = 1; | |
49146f3c DN |
936 | waiter -> waitstatus = ISC_R_SUCCESS; |
937 | return ISC_R_SUCCESS; | |
938 | } | |
939 | ||
98bf1607 | 940 | if (!strcmp(name, "status")) { |
49146f3c | 941 | waiter = (omapi_waiter_object_t *)h; |
98bf1607 SR |
942 | waiter->ready = 1; |
943 | waiter->waitstatus = va_arg(ap, isc_result_t); | |
61b844bf TL |
944 | return ISC_R_SUCCESS; |
945 | } | |
946 | ||
d758ad8c TL |
947 | if (!strcmp (name, "disconnect")) { |
948 | waiter = (omapi_waiter_object_t *)h; | |
949 | waiter -> ready = 1; | |
98bf1607 | 950 | waiter -> waitstatus = DHCP_R_CONNRESET; |
d758ad8c TL |
951 | return ISC_R_SUCCESS; |
952 | } | |
953 | ||
61b844bf TL |
954 | if (h -> inner && h -> inner -> type -> signal_handler) |
955 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
956 | name, ap); | |
957 | return ISC_R_NOTFOUND; | |
958 | } | |
959 | ||
47e8308d SR |
960 | /** @brief calls a given function on every object |
961 | * | |
962 | * @param func function to be called | |
963 | * @param p parameter to be passed to each function instance | |
964 | * | |
965 | * @return result (ISC_R_SUCCESS if successful, error code otherwise) | |
966 | */ | |
d758ad8c TL |
967 | isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *, |
968 | void *), | |
969 | void *p) | |
970 | { | |
47e8308d | 971 | omapi_io_object_t *io = NULL; |
d758ad8c | 972 | isc_result_t status; |
47e8308d | 973 | omapi_io_object_t *next = NULL; |
d758ad8c | 974 | |
47e8308d SR |
975 | /* |
976 | * This just calls func on every inner object on the list. It would | |
977 | * be much simpler in general case, but one of the operations could be | |
978 | * release of the objects. Therefore we need to ref count the io and | |
979 | * io->next pointers. | |
980 | */ | |
981 | ||
982 | if (omapi_io_states.next) { | |
983 | omapi_object_reference((omapi_object_t**)&io, | |
984 | (omapi_object_t*)omapi_io_states.next, | |
985 | MDL); | |
986 | } | |
987 | ||
988 | while(io) { | |
989 | /* If there's a next object, save it */ | |
990 | if (io->next) { | |
991 | omapi_object_reference((omapi_object_t**)&next, | |
992 | (omapi_object_t*)io->next, MDL); | |
993 | } | |
994 | if (io->inner) { | |
995 | status = (*func) (io->inner, p); | |
996 | if (status != ISC_R_SUCCESS) { | |
997 | /* Something went wrong. Let's stop using io & next pointer | |
998 | * and bail out */ | |
999 | omapi_object_dereference((omapi_object_t**)&io, MDL); | |
1000 | if (next) { | |
1001 | omapi_object_dereference((omapi_object_t**)&next, MDL); | |
1002 | } | |
1003 | return status; | |
d758ad8c | 1004 | } |
47e8308d SR |
1005 | } |
1006 | /* Update the io pointer and free the next pointer */ | |
1007 | omapi_object_dereference((omapi_object_t**)&io, MDL); | |
1008 | if (next) { | |
1009 | omapi_object_reference((omapi_object_t**)&io, | |
1010 | (omapi_object_t*)next, | |
1011 | MDL); | |
1012 | omapi_object_dereference((omapi_object_t**)&next, MDL); | |
1013 | } | |
d758ad8c | 1014 | } |
47e8308d SR |
1015 | |
1016 | /* | |
1017 | * The only way to get here is when next is NULL. There's no need | |
1018 | * to dereference it. | |
1019 | */ | |
d758ad8c TL |
1020 | return ISC_R_SUCCESS; |
1021 | } |