]>
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 | ||
145 | omapi_object_dereference ((omapi_object_t **)&waiter, | |
146 | "omapi_wait_for_completion"); | |
147 | return ISC_R_SUCCESS; | |
148 | } | |
149 | ||
150 | isc_result_t omapi_one_dispatch (omapi_waiter_object_t *waiter, | |
151 | struct timeval *t) | |
152 | { | |
153 | fd_set r, w, x; | |
154 | int max = 0; | |
155 | int count; | |
156 | int desc; | |
157 | struct timeval now, to; | |
158 | omapi_io_object_t *io, *prev; | |
159 | isc_result_t status; | |
160 | ||
161 | FD_ZERO (&x); | |
162 | ||
163 | /* First, see if the timeout has expired, and if so return. */ | |
164 | if (t) { | |
165 | gettimeofday (&now, (struct timezone *)0); | |
166 | cur_time = now.tv_sec; | |
167 | if (now.tv_sec > t -> tv_sec || | |
168 | (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) | |
169 | return ISC_R_TIMEDOUT; | |
170 | ||
171 | /* We didn't time out, so figure out how long until | |
172 | we do. */ | |
173 | to.tv_sec = t -> tv_sec - now.tv_sec; | |
174 | to.tv_usec = t -> tv_usec - now.tv_usec; | |
175 | if (to.tv_usec < 0) { | |
176 | to.tv_usec += 1000000; | |
177 | to.tv_sec--; | |
178 | } | |
179 | } | |
180 | ||
181 | /* If the object we're waiting on has reached completion, | |
182 | return now. */ | |
183 | if (waiter && waiter -> ready) | |
184 | return ISC_R_SUCCESS; | |
185 | ||
186 | /* If we have no I/O state, we can't proceed. */ | |
187 | if (!(io = omapi_io_states.next)) | |
188 | return ISC_R_NOMORE; | |
189 | ||
190 | /* Set up the read and write masks. */ | |
191 | FD_ZERO (&r); | |
192 | FD_ZERO (&w); | |
193 | ||
194 | for (; io; io = io -> next) { | |
195 | /* Check for a read socket. If we shouldn't be | |
196 | trying to read for this I/O object, either there | |
197 | won't be a readfd function, or it'll return -1. */ | |
198 | if (io -> readfd && | |
199 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { | |
200 | FD_SET (desc, &r); | |
201 | if (desc > max) | |
202 | max = desc; | |
203 | } | |
204 | ||
205 | /* Same deal for write fdets. */ | |
206 | if (io -> writefd && | |
207 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) { | |
208 | FD_SET (desc, &w); | |
209 | if (desc > max) | |
210 | max = desc; | |
211 | } | |
212 | } | |
213 | ||
214 | /* Wait for a packet or a timeout... XXX */ | |
215 | count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0); | |
216 | ||
217 | /* Get the current time... */ | |
218 | gettimeofday (&now, (struct timezone *)0); | |
219 | cur_time = now.tv_sec; | |
220 | ||
221 | /* Not likely to be transitory... */ | |
222 | if (count < 0) | |
223 | return ISC_R_UNEXPECTED; | |
224 | ||
225 | for (io = omapi_io_states.next; io; io = io -> next) { | |
226 | /* Check for a read descriptor, and if there is one, | |
227 | see if we got input on that socket. */ | |
228 | if (io -> readfd && | |
229 | (desc = (*(io -> readfd)) (io -> inner)) >= 0) { | |
230 | if (FD_ISSET (desc, &r)) | |
231 | status = ((*(io -> reader)) (io -> inner)); | |
232 | /* XXX what to do with status? */ | |
233 | } | |
234 | ||
235 | /* Same deal for write descriptors. */ | |
236 | if (io -> writefd && | |
237 | (desc = (*(io -> writefd)) (io -> inner)) >= 0) | |
238 | { | |
239 | if (FD_ISSET (desc, &w)) | |
240 | status = ((*(io -> writer)) (io -> inner)); | |
241 | /* XXX what to do with status? */ | |
242 | } | |
243 | } | |
244 | ||
245 | /* Now check for I/O handles that are no longer valid, | |
246 | and remove them from the list. */ | |
247 | prev = (omapi_io_object_t *)0; | |
248 | for (io = omapi_io_states.next; io; io = io -> next) { | |
249 | if (io -> reaper) { | |
250 | status = (*(io -> reaper)) (io -> inner); | |
251 | if (status != ISC_R_SUCCESS) { | |
252 | omapi_io_object_t *tmp = | |
253 | (omapi_io_object_t *)0; | |
254 | /* Save a reference to the next | |
255 | pointer, if there is one. */ | |
256 | if (io -> next) | |
257 | omapi_object_reference | |
258 | ((omapi_object_t **)&tmp, | |
259 | (omapi_object_t *)io -> next, | |
260 | "omapi_wfc"); | |
261 | if (prev) { | |
262 | omapi_object_dereference | |
263 | (((omapi_object_t **) | |
264 | &prev -> next), "omapi_wfc"); | |
265 | if (tmp) | |
266 | omapi_object_reference | |
267 | (((omapi_object_t **) | |
268 | &prev -> next), | |
269 | (omapi_object_t *)tmp, | |
270 | "omapi_wfc"); | |
271 | } else { | |
272 | omapi_object_dereference | |
273 | (((omapi_object_t **) | |
274 | &omapi_io_states.next), | |
275 | "omapi_wfc"); | |
276 | if (tmp) | |
277 | omapi_object_reference | |
278 | (((omapi_object_t **) | |
279 | &omapi_io_states.next), | |
280 | (omapi_object_t *)tmp, | |
281 | "omapi_wfc"); | |
282 | else | |
283 | omapi_signal_in | |
284 | ((omapi_object_t *) | |
285 | &omapi_io_states, | |
286 | "ready"); | |
287 | } | |
288 | if (tmp) | |
289 | omapi_object_dereference | |
290 | ((omapi_object_t **)&tmp, | |
291 | "omapi_wfc"); | |
292 | } | |
293 | } | |
294 | prev = io; | |
295 | } | |
296 | ||
297 | return ISC_R_SUCCESS; | |
298 | } | |
299 | ||
300 | isc_result_t omapi_io_set_value (omapi_object_t *h, | |
301 | omapi_object_t *id, | |
302 | omapi_data_string_t *name, | |
303 | omapi_typed_data_t *value) | |
304 | { | |
305 | if (h -> type != omapi_type_io_object) | |
306 | return ISC_R_INVALIDARG; | |
307 | ||
308 | if (h -> inner && h -> inner -> type -> set_value) | |
309 | return (*(h -> inner -> type -> set_value)) | |
310 | (h -> inner, id, name, value); | |
311 | return ISC_R_NOTFOUND; | |
312 | } | |
313 | ||
314 | isc_result_t omapi_io_get_value (omapi_object_t *h, | |
315 | omapi_object_t *id, | |
316 | omapi_data_string_t *name, | |
317 | omapi_value_t **value) | |
318 | { | |
319 | if (h -> type != omapi_type_io_object) | |
320 | return ISC_R_INVALIDARG; | |
321 | ||
322 | if (h -> inner && h -> inner -> type -> get_value) | |
323 | return (*(h -> inner -> type -> get_value)) | |
324 | (h -> inner, id, name, value); | |
325 | return ISC_R_NOTFOUND; | |
326 | } | |
327 | ||
328 | isc_result_t omapi_io_destroy (omapi_object_t *h, char *name) | |
329 | { | |
330 | if (h -> type != omapi_type_io_object) | |
331 | return ISC_R_INVALIDARG; | |
332 | return ISC_R_SUCCESS; | |
333 | } | |
334 | ||
335 | isc_result_t omapi_io_signal_handler (omapi_object_t *h, | |
336 | char *name, va_list ap) | |
337 | { | |
338 | if (h -> type != omapi_type_io_object) | |
339 | return ISC_R_INVALIDARG; | |
340 | ||
341 | if (h -> inner && h -> inner -> type -> signal_handler) | |
342 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
343 | name, ap); | |
344 | return ISC_R_NOTFOUND; | |
345 | } | |
346 | ||
347 | isc_result_t omapi_io_stuff_values (omapi_object_t *c, | |
348 | omapi_object_t *id, | |
349 | omapi_object_t *i) | |
350 | { | |
351 | if (i -> type != omapi_type_io_object) | |
352 | return ISC_R_INVALIDARG; | |
353 | ||
354 | if (i -> inner && i -> inner -> type -> stuff_values) | |
355 | return (*(i -> inner -> type -> stuff_values)) (c, id, | |
356 | i -> inner); | |
357 | return ISC_R_SUCCESS; | |
358 | } | |
359 | ||
360 | isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, | |
361 | char *name, va_list ap) | |
362 | { | |
363 | omapi_waiter_object_t *waiter; | |
364 | ||
365 | if (h -> type != omapi_type_waiter) | |
366 | return ISC_R_INVALIDARG; | |
367 | ||
368 | if (!strcmp (name, "ready")) { | |
369 | waiter = (omapi_waiter_object_t *)h; | |
370 | waiter -> ready = 1; | |
371 | return ISC_R_SUCCESS; | |
372 | } | |
373 | ||
374 | if (h -> inner && h -> inner -> type -> signal_handler) | |
375 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
376 | name, ap); | |
377 | return ISC_R_NOTFOUND; | |
378 | } | |
379 |