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