]>
Commit | Line | Data |
---|---|---|
61b844bf TL |
1 | /* dispatch.c |
2 | ||
3 | I/O dispatcher. */ | |
4 | ||
5 | /* | |
4bd8800e | 6 | * Copyright (c) 1996-2000 Internet Software Consortium. |
61b844bf TL |
7 | * Use is subject to license terms which appear in the file named |
8 | * ISC-LICENSE that should have accompanied this file when you | |
9 | * received it. If a file named ISC-LICENSE did not accompany this | |
10 | * file, or you are not sure the one you have is correct, you may | |
11 | * obtain an applicable copy of the license at: | |
12 | * | |
13 | * http://www.isc.org/isc-license-1.0.html. | |
14 | * | |
15 | * This file is part of the ISC DHCP distribution. The documentation | |
16 | * associated with this file is listed in the file DOCUMENTATION, | |
17 | * included in the top-level directory of this release. | |
18 | * | |
19 | * Support and other services are available for ISC products - see | |
20 | * http://www.isc.org for more information. | |
21 | */ | |
22 | ||
6a4c4be8 | 23 | #include <omapip/omapip_p.h> |
61b844bf TL |
24 | |
25 | static omapi_io_object_t omapi_io_states; | |
26 | u_int32_t cur_time; | |
27 | ||
28 | /* Register an I/O handle so that we can do asynchronous I/O on it. */ | |
29 | ||
30 | isc_result_t omapi_register_io_object (omapi_object_t *h, | |
31 | int (*readfd) (omapi_object_t *), | |
32 | int (*writefd) (omapi_object_t *), | |
33 | isc_result_t (*reader) | |
34 | (omapi_object_t *), | |
35 | isc_result_t (*writer) | |
36 | (omapi_object_t *), | |
37 | isc_result_t (*reaper) | |
38 | (omapi_object_t *)) | |
39 | { | |
40 | isc_result_t status; | |
41 | omapi_io_object_t *obj, *p; | |
42 | ||
43 | /* omapi_io_states is a static object. If its reference count | |
44 | is zero, this is the first I/O handle to be registered, so | |
45 | we need to initialize it. Because there is no inner or outer | |
46 | pointer on this object, and we're setting its refcnt to 1, it | |
47 | will never be freed. */ | |
48 | if (!omapi_io_states.refcnt) { | |
49 | omapi_io_states.refcnt = 1; | |
50 | omapi_io_states.type = omapi_type_io_object; | |
51 | } | |
52 | ||
4bd8800e | 53 | obj = dmalloc (sizeof *obj, MDL); |
61b844bf TL |
54 | if (!obj) |
55 | return ISC_R_NOMEMORY; | |
56 | memset (obj, 0, sizeof *obj); | |
61b844bf | 57 | obj -> refcnt = 1; |
37e365b4 | 58 | rc_register_mdl (&obj, obj, obj -> refcnt); |
61b844bf TL |
59 | obj -> type = omapi_type_io_object; |
60 | ||
4bd8800e | 61 | status = omapi_object_reference (&obj -> inner, h, MDL); |
61b844bf | 62 | if (status != ISC_R_SUCCESS) { |
4bd8800e | 63 | omapi_object_dereference ((omapi_object_t **)&obj, MDL); |
61b844bf TL |
64 | return status; |
65 | } | |
66 | ||
4bd8800e TL |
67 | status = omapi_object_reference (&h -> outer, |
68 | (omapi_object_t *)obj, MDL); | |
61b844bf | 69 | if (status != ISC_R_SUCCESS) { |
4bd8800e | 70 | omapi_object_dereference ((omapi_object_t **)&obj, MDL); |
61b844bf TL |
71 | return status; |
72 | } | |
73 | ||
74 | /* Find the last I/O state, if there are any. */ | |
75 | for (p = omapi_io_states.next; | |
76 | p && p -> next; p = p -> next) | |
77 | ; | |
78 | if (p) | |
79 | p -> next = obj; | |
80 | else | |
81 | omapi_io_states.next = obj; | |
82 | ||
83 | obj -> readfd = readfd; | |
84 | obj -> writefd = writefd; | |
85 | obj -> reader = reader; | |
86 | obj -> writer = writer; | |
87 | obj -> reaper = reaper; | |
88 | return ISC_R_SUCCESS; | |
89 | } | |
90 | ||
91 | isc_result_t omapi_dispatch (struct timeval *t) | |
92 | { | |
93 | return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, | |
94 | t); | |
95 | } | |
96 | ||
97 | isc_result_t omapi_wait_for_completion (omapi_object_t *object, | |
98 | struct timeval *t) | |
99 | { | |
100 | isc_result_t status; | |
101 | omapi_waiter_object_t *waiter; | |
102 | omapi_object_t *inner; | |
103 | ||
104 | if (object) { | |
4bd8800e | 105 | waiter = dmalloc (sizeof *waiter, MDL); |
61b844bf TL |
106 | if (!waiter) |
107 | return ISC_R_NOMEMORY; | |
108 | memset (waiter, 0, sizeof *waiter); | |
109 | waiter -> refcnt = 1; | |
37e365b4 | 110 | rc_register_mdl (&waiter, waiter, waiter -> refcnt); |
61b844bf TL |
111 | waiter -> type = omapi_type_waiter; |
112 | ||
113 | /* Paste the waiter object onto the inner object we're | |
114 | waiting on. */ | |
115 | for (inner = object; inner -> inner; inner = inner -> inner) | |
116 | ; | |
117 | ||
4bd8800e | 118 | status = omapi_object_reference (&waiter -> outer, inner, MDL); |
61b844bf TL |
119 | if (status != ISC_R_SUCCESS) { |
120 | omapi_object_dereference ((omapi_object_t **)&waiter, | |
4bd8800e | 121 | MDL); |
61b844bf TL |
122 | return status; |
123 | } | |
124 | ||
125 | status = omapi_object_reference (&inner -> inner, | |
126 | (omapi_object_t *)waiter, | |
4bd8800e | 127 | MDL); |
61b844bf TL |
128 | if (status != ISC_R_SUCCESS) { |
129 | omapi_object_dereference ((omapi_object_t **)&waiter, | |
4bd8800e | 130 | MDL); |
61b844bf TL |
131 | return status; |
132 | } | |
133 | } else | |
134 | waiter = (omapi_waiter_object_t *)0; | |
135 | ||
136 | do { | |
6a4c4be8 | 137 | status = omapi_one_dispatch ((omapi_object_t *)waiter, t); |
61b844bf TL |
138 | if (status != ISC_R_SUCCESS) |
139 | return status; | |
140 | } while (!waiter || !waiter -> ready); | |
141 | ||
727ebc3a TL |
142 | if (waiter -> outer) { |
143 | if (waiter -> outer -> inner) { | |
144 | omapi_object_dereference (&waiter -> outer -> inner, | |
4bd8800e | 145 | MDL); |
727ebc3a TL |
146 | if (waiter -> inner) |
147 | omapi_object_reference | |
148 | (&waiter -> outer -> inner, | |
4bd8800e | 149 | waiter -> inner, MDL); |
727ebc3a | 150 | } |
4bd8800e | 151 | omapi_object_dereference (&waiter -> outer, MDL); |
727ebc3a TL |
152 | } |
153 | if (waiter -> inner) | |
4bd8800e | 154 | omapi_object_dereference (&waiter -> inner, MDL); |
727ebc3a | 155 | |
4bd8800e | 156 | omapi_object_dereference ((omapi_object_t **)&waiter, MDL); |
61b844bf TL |
157 | return ISC_R_SUCCESS; |
158 | } | |
159 | ||
6a4c4be8 | 160 | isc_result_t omapi_one_dispatch (omapi_object_t *wo, |
61b844bf TL |
161 | struct timeval *t) |
162 | { | |
163 | fd_set r, w, x; | |
164 | int max = 0; | |
165 | int count; | |
166 | int desc; | |
167 | struct timeval now, to; | |
168 | omapi_io_object_t *io, *prev; | |
169 | isc_result_t status; | |
6a4c4be8 TL |
170 | omapi_waiter_object_t *waiter; |
171 | ||
172 | if (!wo || wo -> type != omapi_type_waiter) | |
173 | waiter = (omapi_waiter_object_t *)0; | |
174 | else | |
175 | waiter = (omapi_waiter_object_t *)wo; | |
61b844bf TL |
176 | |
177 | FD_ZERO (&x); | |
178 | ||
179 | /* First, see if the timeout has expired, and if so return. */ | |
180 | if (t) { | |
181 | gettimeofday (&now, (struct timezone *)0); | |
182 | cur_time = now.tv_sec; | |
183 | if (now.tv_sec > t -> tv_sec || | |
184 | (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) | |
185 | return ISC_R_TIMEDOUT; | |
186 | ||
187 | /* We didn't time out, so figure out how long until | |
188 | we do. */ | |
189 | to.tv_sec = t -> tv_sec - now.tv_sec; | |
190 | to.tv_usec = t -> tv_usec - now.tv_usec; | |
191 | if (to.tv_usec < 0) { | |
192 | to.tv_usec += 1000000; | |
193 | to.tv_sec--; | |
194 | } | |
195 | } | |
196 | ||
197 | /* If the object we're waiting on has reached completion, | |
198 | return now. */ | |
199 | if (waiter && waiter -> ready) | |
200 | return ISC_R_SUCCESS; | |
201 | ||
202 | /* If we have no I/O state, we can't proceed. */ | |
203 | if (!(io = omapi_io_states.next)) | |
204 | return ISC_R_NOMORE; | |
205 | ||
206 | /* Set up the read and write masks. */ | |
207 | FD_ZERO (&r); | |
208 | FD_ZERO (&w); | |
209 | ||
210 | for (; io; io = io -> next) { | |
211 | /* Check for a read socket. If we shouldn't be | |
212 | trying to read for this I/O object, either there | |
213 | won't be a readfd function, or it'll return -1. */ | |
214 | if (io -> readfd && | |
215 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { | |
216 | FD_SET (desc, &r); | |
217 | if (desc > max) | |
218 | max = desc; | |
219 | } | |
220 | ||
221 | /* Same deal for write fdets. */ | |
222 | if (io -> writefd && | |
223 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) { | |
224 | FD_SET (desc, &w); | |
225 | if (desc > max) | |
226 | max = desc; | |
227 | } | |
228 | } | |
229 | ||
230 | /* Wait for a packet or a timeout... XXX */ | |
231 | count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0); | |
232 | ||
233 | /* Get the current time... */ | |
234 | gettimeofday (&now, (struct timezone *)0); | |
235 | cur_time = now.tv_sec; | |
236 | ||
237 | /* Not likely to be transitory... */ | |
238 | if (count < 0) | |
239 | return ISC_R_UNEXPECTED; | |
240 | ||
241 | for (io = omapi_io_states.next; io; io = io -> next) { | |
242 | /* Check for a read descriptor, and if there is one, | |
243 | see if we got input on that socket. */ | |
244 | if (io -> readfd && | |
245 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { | |
246 | if (FD_ISSET (desc, &r)) | |
247 | status = ((*(io -> reader)) (io -> inner)); | |
248 | /* XXX what to do with status? */ | |
249 | } | |
250 | ||
251 | /* Same deal for write descriptors. */ | |
252 | if (io -> writefd && | |
253 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) | |
254 | { | |
255 | if (FD_ISSET (desc, &w)) | |
256 | status = ((*(io -> writer)) (io -> inner)); | |
257 | /* XXX what to do with status? */ | |
258 | } | |
259 | } | |
260 | ||
261 | /* Now check for I/O handles that are no longer valid, | |
262 | and remove them from the list. */ | |
263 | prev = (omapi_io_object_t *)0; | |
264 | for (io = omapi_io_states.next; io; io = io -> next) { | |
265 | if (io -> reaper) { | |
266 | status = (*(io -> reaper)) (io -> inner); | |
267 | if (status != ISC_R_SUCCESS) { | |
268 | omapi_io_object_t *tmp = | |
269 | (omapi_io_object_t *)0; | |
270 | /* Save a reference to the next | |
271 | pointer, if there is one. */ | |
272 | if (io -> next) | |
273 | omapi_object_reference | |
274 | ((omapi_object_t **)&tmp, | |
275 | (omapi_object_t *)io -> next, | |
4bd8800e | 276 | MDL); |
61b844bf TL |
277 | if (prev) { |
278 | omapi_object_dereference | |
279 | (((omapi_object_t **) | |
4bd8800e | 280 | &prev -> next), MDL); |
61b844bf TL |
281 | if (tmp) |
282 | omapi_object_reference | |
283 | (((omapi_object_t **) | |
284 | &prev -> next), | |
285 | (omapi_object_t *)tmp, | |
4bd8800e | 286 | MDL); |
61b844bf TL |
287 | } else { |
288 | omapi_object_dereference | |
289 | (((omapi_object_t **) | |
290 | &omapi_io_states.next), | |
4bd8800e | 291 | MDL); |
61b844bf TL |
292 | if (tmp) |
293 | omapi_object_reference | |
294 | (((omapi_object_t **) | |
295 | &omapi_io_states.next), | |
296 | (omapi_object_t *)tmp, | |
4bd8800e | 297 | MDL); |
61b844bf TL |
298 | else |
299 | omapi_signal_in | |
300 | ((omapi_object_t *) | |
301 | &omapi_io_states, | |
302 | "ready"); | |
303 | } | |
304 | if (tmp) | |
305 | omapi_object_dereference | |
4bd8800e | 306 | ((omapi_object_t **)&tmp, MDL); |
61b844bf TL |
307 | } |
308 | } | |
309 | prev = io; | |
310 | } | |
311 | ||
312 | return ISC_R_SUCCESS; | |
313 | } | |
314 | ||
315 | isc_result_t omapi_io_set_value (omapi_object_t *h, | |
316 | omapi_object_t *id, | |
317 | omapi_data_string_t *name, | |
318 | omapi_typed_data_t *value) | |
319 | { | |
320 | if (h -> type != omapi_type_io_object) | |
321 | return ISC_R_INVALIDARG; | |
322 | ||
323 | if (h -> inner && h -> inner -> type -> set_value) | |
324 | return (*(h -> inner -> type -> set_value)) | |
325 | (h -> inner, id, name, value); | |
326 | return ISC_R_NOTFOUND; | |
327 | } | |
328 | ||
329 | isc_result_t omapi_io_get_value (omapi_object_t *h, | |
330 | omapi_object_t *id, | |
331 | omapi_data_string_t *name, | |
332 | omapi_value_t **value) | |
333 | { | |
334 | if (h -> type != omapi_type_io_object) | |
335 | return ISC_R_INVALIDARG; | |
336 | ||
337 | if (h -> inner && h -> inner -> type -> get_value) | |
338 | return (*(h -> inner -> type -> get_value)) | |
339 | (h -> inner, id, name, value); | |
340 | return ISC_R_NOTFOUND; | |
341 | } | |
342 | ||
4bd8800e | 343 | isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line) |
61b844bf TL |
344 | { |
345 | if (h -> type != omapi_type_io_object) | |
346 | return ISC_R_INVALIDARG; | |
347 | return ISC_R_SUCCESS; | |
348 | } | |
349 | ||
350 | isc_result_t omapi_io_signal_handler (omapi_object_t *h, | |
b1b7b521 | 351 | const char *name, va_list ap) |
61b844bf TL |
352 | { |
353 | if (h -> type != omapi_type_io_object) | |
354 | return ISC_R_INVALIDARG; | |
355 | ||
356 | if (h -> inner && h -> inner -> type -> signal_handler) | |
357 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
358 | name, ap); | |
359 | return ISC_R_NOTFOUND; | |
360 | } | |
361 | ||
362 | isc_result_t omapi_io_stuff_values (omapi_object_t *c, | |
363 | omapi_object_t *id, | |
364 | omapi_object_t *i) | |
365 | { | |
366 | if (i -> type != omapi_type_io_object) | |
367 | return ISC_R_INVALIDARG; | |
368 | ||
369 | if (i -> inner && i -> inner -> type -> stuff_values) | |
370 | return (*(i -> inner -> type -> stuff_values)) (c, id, | |
371 | i -> inner); | |
372 | return ISC_R_SUCCESS; | |
373 | } | |
374 | ||
375 | isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, | |
b1b7b521 | 376 | const char *name, va_list ap) |
61b844bf TL |
377 | { |
378 | omapi_waiter_object_t *waiter; | |
379 | ||
380 | if (h -> type != omapi_type_waiter) | |
381 | return ISC_R_INVALIDARG; | |
382 | ||
383 | if (!strcmp (name, "ready")) { | |
384 | waiter = (omapi_waiter_object_t *)h; | |
385 | waiter -> ready = 1; | |
386 | return ISC_R_SUCCESS; | |
387 | } | |
388 | ||
389 | if (h -> inner && h -> inner -> type -> signal_handler) | |
390 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
391 | name, ap); | |
392 | return ISC_R_NOTFOUND; | |
393 | } | |
394 |