]>
Commit | Line | Data |
---|---|---|
61b844bf TL |
1 | /* dispatch.c |
2 | ||
3 | I/O dispatcher. */ | |
4 | ||
5 | /* | |
49733f31 TL |
6 | * Copyright (c) 1999-2000 Internet Software Consortium. |
7 | * All rights reserved. | |
61b844bf | 8 | * |
49733f31 TL |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
61b844bf | 12 | * |
49733f31 TL |
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. | |
61b844bf | 21 | * |
49733f31 TL |
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''. | |
61b844bf TL |
42 | */ |
43 | ||
6a4c4be8 | 44 | #include <omapip/omapip_p.h> |
61b844bf TL |
45 | |
46 | static omapi_io_object_t omapi_io_states; | |
47 | u_int32_t cur_time; | |
48 | ||
49 | /* Register an I/O handle so that we can do asynchronous I/O on it. */ | |
50 | ||
51 | isc_result_t omapi_register_io_object (omapi_object_t *h, | |
52 | int (*readfd) (omapi_object_t *), | |
53 | int (*writefd) (omapi_object_t *), | |
54 | isc_result_t (*reader) | |
55 | (omapi_object_t *), | |
56 | isc_result_t (*writer) | |
57 | (omapi_object_t *), | |
58 | isc_result_t (*reaper) | |
59 | (omapi_object_t *)) | |
60 | { | |
61 | isc_result_t status; | |
62 | omapi_io_object_t *obj, *p; | |
63 | ||
64 | /* omapi_io_states is a static object. If its reference count | |
65 | is zero, this is the first I/O handle to be registered, so | |
66 | we need to initialize it. Because there is no inner or outer | |
67 | pointer on this object, and we're setting its refcnt to 1, it | |
68 | will never be freed. */ | |
69 | if (!omapi_io_states.refcnt) { | |
70 | omapi_io_states.refcnt = 1; | |
71 | omapi_io_states.type = omapi_type_io_object; | |
72 | } | |
73 | ||
4bd8800e | 74 | obj = dmalloc (sizeof *obj, MDL); |
61b844bf TL |
75 | if (!obj) |
76 | return ISC_R_NOMEMORY; | |
77 | memset (obj, 0, sizeof *obj); | |
61b844bf | 78 | obj -> refcnt = 1; |
37e365b4 | 79 | rc_register_mdl (&obj, obj, obj -> refcnt); |
61b844bf TL |
80 | obj -> type = omapi_type_io_object; |
81 | ||
4bd8800e | 82 | status = omapi_object_reference (&obj -> inner, h, MDL); |
61b844bf | 83 | if (status != ISC_R_SUCCESS) { |
4bd8800e | 84 | omapi_object_dereference ((omapi_object_t **)&obj, MDL); |
61b844bf TL |
85 | return status; |
86 | } | |
87 | ||
4bd8800e TL |
88 | status = omapi_object_reference (&h -> outer, |
89 | (omapi_object_t *)obj, MDL); | |
61b844bf | 90 | if (status != ISC_R_SUCCESS) { |
4bd8800e | 91 | omapi_object_dereference ((omapi_object_t **)&obj, MDL); |
61b844bf TL |
92 | return status; |
93 | } | |
94 | ||
95 | /* Find the last I/O state, if there are any. */ | |
96 | for (p = omapi_io_states.next; | |
97 | p && p -> next; p = p -> next) | |
98 | ; | |
99 | if (p) | |
b6237fb2 TL |
100 | omapi_object_reference ((omapi_object_t **)&p -> next, |
101 | (omapi_object_t *)obj, MDL); | |
61b844bf | 102 | else |
b6237fb2 TL |
103 | omapi_object_reference |
104 | ((omapi_object_t **)&omapi_io_states.next, | |
105 | (omapi_object_t *)obj, MDL); | |
61b844bf TL |
106 | |
107 | obj -> readfd = readfd; | |
108 | obj -> writefd = writefd; | |
109 | obj -> reader = reader; | |
110 | obj -> writer = writer; | |
111 | obj -> reaper = reaper; | |
112 | return ISC_R_SUCCESS; | |
113 | } | |
114 | ||
b6237fb2 TL |
115 | isc_result_t omapi_unregister_io_object (omapi_object_t *h) |
116 | { | |
117 | omapi_io_object_t *p, *obj, *last; | |
118 | omapi_object_t *ph; | |
119 | ||
120 | obj = (omapi_io_object_t *)h -> outer; | |
121 | ph = (omapi_object_t *)0; | |
122 | omapi_object_reference (&ph, h -> outer, MDL); | |
123 | ||
124 | /* remove from the list of I/O states */ | |
125 | for (p = omapi_io_states.next; p; p = p -> next) { | |
126 | if ((omapi_object_t *)p == h -> outer) { | |
127 | omapi_object_dereference ((omapi_object_t **) | |
128 | &last -> next, MDL); | |
129 | omapi_object_reference ((omapi_object_t **) | |
130 | &last -> next, | |
131 | (omapi_object_t *)p -> next, | |
132 | MDL); | |
133 | break; | |
134 | } | |
135 | last = p; | |
136 | } | |
137 | if (obj -> next) | |
138 | omapi_object_dereference ((omapi_object_t **)&obj -> next, | |
139 | MDL); | |
140 | if (obj -> outer) { | |
141 | if (obj -> outer -> inner == (omapi_object_t *)obj) | |
142 | omapi_object_dereference (&obj -> outer -> inner, | |
143 | MDL); | |
144 | omapi_object_dereference (&obj -> outer, MDL); | |
145 | } | |
146 | omapi_object_dereference (&obj -> inner, MDL); | |
147 | omapi_object_dereference (&h -> outer, MDL); | |
148 | omapi_object_dereference (&ph, MDL); | |
149 | return ISC_R_SUCCESS; | |
150 | } | |
151 | ||
61b844bf TL |
152 | isc_result_t omapi_dispatch (struct timeval *t) |
153 | { | |
154 | return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, | |
155 | t); | |
156 | } | |
157 | ||
158 | isc_result_t omapi_wait_for_completion (omapi_object_t *object, | |
159 | struct timeval *t) | |
160 | { | |
161 | isc_result_t status; | |
162 | omapi_waiter_object_t *waiter; | |
163 | omapi_object_t *inner; | |
164 | ||
165 | if (object) { | |
4bd8800e | 166 | waiter = dmalloc (sizeof *waiter, MDL); |
61b844bf TL |
167 | if (!waiter) |
168 | return ISC_R_NOMEMORY; | |
169 | memset (waiter, 0, sizeof *waiter); | |
170 | waiter -> refcnt = 1; | |
37e365b4 | 171 | rc_register_mdl (&waiter, waiter, waiter -> refcnt); |
61b844bf TL |
172 | waiter -> type = omapi_type_waiter; |
173 | ||
174 | /* Paste the waiter object onto the inner object we're | |
175 | waiting on. */ | |
176 | for (inner = object; inner -> inner; inner = inner -> inner) | |
177 | ; | |
178 | ||
4bd8800e | 179 | status = omapi_object_reference (&waiter -> outer, inner, MDL); |
61b844bf TL |
180 | if (status != ISC_R_SUCCESS) { |
181 | omapi_object_dereference ((omapi_object_t **)&waiter, | |
4bd8800e | 182 | MDL); |
61b844bf TL |
183 | return status; |
184 | } | |
185 | ||
186 | status = omapi_object_reference (&inner -> inner, | |
187 | (omapi_object_t *)waiter, | |
4bd8800e | 188 | MDL); |
61b844bf TL |
189 | if (status != ISC_R_SUCCESS) { |
190 | omapi_object_dereference ((omapi_object_t **)&waiter, | |
4bd8800e | 191 | MDL); |
61b844bf TL |
192 | return status; |
193 | } | |
194 | } else | |
195 | waiter = (omapi_waiter_object_t *)0; | |
196 | ||
197 | do { | |
6a4c4be8 | 198 | status = omapi_one_dispatch ((omapi_object_t *)waiter, t); |
61b844bf TL |
199 | if (status != ISC_R_SUCCESS) |
200 | return status; | |
201 | } while (!waiter || !waiter -> ready); | |
202 | ||
727ebc3a TL |
203 | if (waiter -> outer) { |
204 | if (waiter -> outer -> inner) { | |
205 | omapi_object_dereference (&waiter -> outer -> inner, | |
4bd8800e | 206 | MDL); |
727ebc3a TL |
207 | if (waiter -> inner) |
208 | omapi_object_reference | |
209 | (&waiter -> outer -> inner, | |
4bd8800e | 210 | waiter -> inner, MDL); |
727ebc3a | 211 | } |
4bd8800e | 212 | omapi_object_dereference (&waiter -> outer, MDL); |
727ebc3a TL |
213 | } |
214 | if (waiter -> inner) | |
4bd8800e | 215 | omapi_object_dereference (&waiter -> inner, MDL); |
727ebc3a | 216 | |
4bd8800e | 217 | omapi_object_dereference ((omapi_object_t **)&waiter, MDL); |
61b844bf TL |
218 | return ISC_R_SUCCESS; |
219 | } | |
220 | ||
6a4c4be8 | 221 | isc_result_t omapi_one_dispatch (omapi_object_t *wo, |
61b844bf TL |
222 | struct timeval *t) |
223 | { | |
224 | fd_set r, w, x; | |
225 | int max = 0; | |
226 | int count; | |
227 | int desc; | |
228 | struct timeval now, to; | |
229 | omapi_io_object_t *io, *prev; | |
230 | isc_result_t status; | |
6a4c4be8 | 231 | omapi_waiter_object_t *waiter; |
b6237fb2 | 232 | omapi_object_t *tmp = (omapi_object_t *)0; |
6a4c4be8 TL |
233 | |
234 | if (!wo || wo -> type != omapi_type_waiter) | |
235 | waiter = (omapi_waiter_object_t *)0; | |
236 | else | |
237 | waiter = (omapi_waiter_object_t *)wo; | |
61b844bf TL |
238 | |
239 | FD_ZERO (&x); | |
240 | ||
241 | /* First, see if the timeout has expired, and if so return. */ | |
242 | if (t) { | |
243 | gettimeofday (&now, (struct timezone *)0); | |
244 | cur_time = now.tv_sec; | |
245 | if (now.tv_sec > t -> tv_sec || | |
246 | (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) | |
247 | return ISC_R_TIMEDOUT; | |
248 | ||
249 | /* We didn't time out, so figure out how long until | |
250 | we do. */ | |
251 | to.tv_sec = t -> tv_sec - now.tv_sec; | |
252 | to.tv_usec = t -> tv_usec - now.tv_usec; | |
253 | if (to.tv_usec < 0) { | |
254 | to.tv_usec += 1000000; | |
255 | to.tv_sec--; | |
256 | } | |
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 | /* If we have no I/O state, we can't proceed. */ | |
265 | if (!(io = omapi_io_states.next)) | |
266 | return ISC_R_NOMORE; | |
267 | ||
268 | /* Set up the read and write masks. */ | |
269 | FD_ZERO (&r); | |
270 | FD_ZERO (&w); | |
271 | ||
272 | for (; io; io = io -> next) { | |
273 | /* Check for a read socket. If we shouldn't be | |
274 | trying to read for this I/O object, either there | |
275 | won't be a readfd function, or it'll return -1. */ | |
276 | if (io -> readfd && | |
277 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { | |
278 | FD_SET (desc, &r); | |
279 | if (desc > max) | |
280 | max = desc; | |
281 | } | |
282 | ||
283 | /* Same deal for write fdets. */ | |
284 | if (io -> writefd && | |
285 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) { | |
286 | FD_SET (desc, &w); | |
287 | if (desc > max) | |
288 | max = desc; | |
289 | } | |
290 | } | |
291 | ||
292 | /* Wait for a packet or a timeout... XXX */ | |
293 | count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0); | |
294 | ||
295 | /* Get the current time... */ | |
296 | gettimeofday (&now, (struct timezone *)0); | |
297 | cur_time = now.tv_sec; | |
298 | ||
299 | /* Not likely to be transitory... */ | |
300 | if (count < 0) | |
301 | return ISC_R_UNEXPECTED; | |
302 | ||
303 | for (io = omapi_io_states.next; io; io = io -> next) { | |
b6237fb2 | 304 | omapi_object_reference (&tmp, io -> inner, MDL); |
61b844bf TL |
305 | /* Check for a read descriptor, and if there is one, |
306 | see if we got input on that socket. */ | |
307 | if (io -> readfd && | |
b6237fb2 | 308 | (desc = (*(io -> readfd)) (tmp)) >= 0) { |
61b844bf | 309 | if (FD_ISSET (desc, &r)) |
b6237fb2 | 310 | status = ((*(io -> reader)) (tmp)); |
61b844bf TL |
311 | /* XXX what to do with status? */ |
312 | } | |
313 | ||
314 | /* Same deal for write descriptors. */ | |
315 | if (io -> writefd && | |
b6237fb2 | 316 | (desc = (*(io -> writefd)) (tmp)) >= 0) |
61b844bf TL |
317 | { |
318 | if (FD_ISSET (desc, &w)) | |
b6237fb2 | 319 | status = ((*(io -> writer)) (tmp)); |
61b844bf TL |
320 | /* XXX what to do with status? */ |
321 | } | |
b6237fb2 | 322 | omapi_object_dereference (&tmp, MDL); |
61b844bf TL |
323 | } |
324 | ||
325 | /* Now check for I/O handles that are no longer valid, | |
326 | and remove them from the list. */ | |
327 | prev = (omapi_io_object_t *)0; | |
328 | for (io = omapi_io_states.next; io; io = io -> next) { | |
329 | if (io -> reaper) { | |
330 | status = (*(io -> reaper)) (io -> inner); | |
331 | if (status != ISC_R_SUCCESS) { | |
332 | omapi_io_object_t *tmp = | |
333 | (omapi_io_object_t *)0; | |
334 | /* Save a reference to the next | |
335 | pointer, if there is one. */ | |
336 | if (io -> next) | |
337 | omapi_object_reference | |
338 | ((omapi_object_t **)&tmp, | |
339 | (omapi_object_t *)io -> next, | |
4bd8800e | 340 | MDL); |
61b844bf TL |
341 | if (prev) { |
342 | omapi_object_dereference | |
343 | (((omapi_object_t **) | |
4bd8800e | 344 | &prev -> next), MDL); |
61b844bf TL |
345 | if (tmp) |
346 | omapi_object_reference | |
347 | (((omapi_object_t **) | |
348 | &prev -> next), | |
349 | (omapi_object_t *)tmp, | |
4bd8800e | 350 | MDL); |
61b844bf TL |
351 | } else { |
352 | omapi_object_dereference | |
353 | (((omapi_object_t **) | |
354 | &omapi_io_states.next), | |
4bd8800e | 355 | MDL); |
61b844bf TL |
356 | if (tmp) |
357 | omapi_object_reference | |
358 | (((omapi_object_t **) | |
359 | &omapi_io_states.next), | |
360 | (omapi_object_t *)tmp, | |
4bd8800e | 361 | MDL); |
61b844bf TL |
362 | else |
363 | omapi_signal_in | |
364 | ((omapi_object_t *) | |
365 | &omapi_io_states, | |
366 | "ready"); | |
367 | } | |
368 | if (tmp) | |
369 | omapi_object_dereference | |
4bd8800e | 370 | ((omapi_object_t **)&tmp, MDL); |
61b844bf TL |
371 | } |
372 | } | |
373 | prev = io; | |
374 | } | |
375 | ||
376 | return ISC_R_SUCCESS; | |
377 | } | |
378 | ||
379 | isc_result_t omapi_io_set_value (omapi_object_t *h, | |
380 | omapi_object_t *id, | |
381 | omapi_data_string_t *name, | |
382 | omapi_typed_data_t *value) | |
383 | { | |
384 | if (h -> type != omapi_type_io_object) | |
385 | return ISC_R_INVALIDARG; | |
386 | ||
387 | if (h -> inner && h -> inner -> type -> set_value) | |
388 | return (*(h -> inner -> type -> set_value)) | |
389 | (h -> inner, id, name, value); | |
390 | return ISC_R_NOTFOUND; | |
391 | } | |
392 | ||
393 | isc_result_t omapi_io_get_value (omapi_object_t *h, | |
394 | omapi_object_t *id, | |
395 | omapi_data_string_t *name, | |
396 | omapi_value_t **value) | |
397 | { | |
398 | if (h -> type != omapi_type_io_object) | |
399 | return ISC_R_INVALIDARG; | |
400 | ||
401 | if (h -> inner && h -> inner -> type -> get_value) | |
402 | return (*(h -> inner -> type -> get_value)) | |
403 | (h -> inner, id, name, value); | |
404 | return ISC_R_NOTFOUND; | |
405 | } | |
406 | ||
4bd8800e | 407 | isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line) |
61b844bf | 408 | { |
bdcaf7b9 TL |
409 | omapi_io_object_t *obj, *p, *last; |
410 | ||
61b844bf TL |
411 | if (h -> type != omapi_type_io_object) |
412 | return ISC_R_INVALIDARG; | |
bdcaf7b9 TL |
413 | |
414 | obj = (omapi_io_object_t *)h; | |
415 | ||
b6237fb2 TL |
416 | /* remove from the list of I/O states */ |
417 | for (p = omapi_io_states.next; p; p = p -> next) { | |
418 | if (p == obj) { | |
419 | omapi_object_dereference ((omapi_object_t **) | |
420 | &last -> next, MDL); | |
421 | omapi_object_reference ((omapi_object_t **) | |
422 | &last -> next, | |
423 | (omapi_object_t *)p -> next, | |
424 | MDL); | |
425 | omapi_object_dereference ((omapi_object_t **)&p, MDL); | |
426 | break; | |
bdcaf7b9 | 427 | } |
b6237fb2 | 428 | last = p; |
bdcaf7b9 | 429 | } |
b6237fb2 | 430 | |
61b844bf TL |
431 | return ISC_R_SUCCESS; |
432 | } | |
433 | ||
434 | isc_result_t omapi_io_signal_handler (omapi_object_t *h, | |
b1b7b521 | 435 | const char *name, va_list ap) |
61b844bf TL |
436 | { |
437 | if (h -> type != omapi_type_io_object) | |
438 | return ISC_R_INVALIDARG; | |
439 | ||
440 | if (h -> inner && h -> inner -> type -> signal_handler) | |
441 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
442 | name, ap); | |
443 | return ISC_R_NOTFOUND; | |
444 | } | |
445 | ||
446 | isc_result_t omapi_io_stuff_values (omapi_object_t *c, | |
447 | omapi_object_t *id, | |
448 | omapi_object_t *i) | |
449 | { | |
450 | if (i -> type != omapi_type_io_object) | |
451 | return ISC_R_INVALIDARG; | |
452 | ||
453 | if (i -> inner && i -> inner -> type -> stuff_values) | |
454 | return (*(i -> inner -> type -> stuff_values)) (c, id, | |
455 | i -> inner); | |
456 | return ISC_R_SUCCESS; | |
457 | } | |
458 | ||
459 | isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, | |
b1b7b521 | 460 | const char *name, va_list ap) |
61b844bf TL |
461 | { |
462 | omapi_waiter_object_t *waiter; | |
463 | ||
464 | if (h -> type != omapi_type_waiter) | |
465 | return ISC_R_INVALIDARG; | |
466 | ||
467 | if (!strcmp (name, "ready")) { | |
468 | waiter = (omapi_waiter_object_t *)h; | |
469 | waiter -> ready = 1; | |
470 | return ISC_R_SUCCESS; | |
471 | } | |
472 | ||
473 | if (h -> inner && h -> inner -> type -> signal_handler) | |
474 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
475 | name, ap); | |
476 | return ISC_R_NOTFOUND; | |
477 | } | |
478 |