]> git.ipfire.org Git - thirdparty/dhcp.git/blob - omapip/dispatch.c
c571737d3c4d0cf3a698d0aace33cbbc3f9abc36
[thirdparty/dhcp.git] / omapip / dispatch.c
1 /* dispatch.c
2
3 I/O dispatcher. */
4
5 /*
6 * Copyright (c) 1996-2000 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_p.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 = dmalloc (sizeof *obj, MDL);
54 if (!obj)
55 return ISC_R_NOMEMORY;
56 memset (obj, 0, sizeof *obj);
57 obj -> refcnt = 1;
58 rc_register_mdl (&obj, obj, obj -> refcnt);
59 obj -> type = omapi_type_io_object;
60
61 status = omapi_object_reference (&obj -> inner, h, MDL);
62 if (status != ISC_R_SUCCESS) {
63 omapi_object_dereference ((omapi_object_t **)&obj, MDL);
64 return status;
65 }
66
67 status = omapi_object_reference (&h -> outer,
68 (omapi_object_t *)obj, MDL);
69 if (status != ISC_R_SUCCESS) {
70 omapi_object_dereference ((omapi_object_t **)&obj, MDL);
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) {
105 waiter = dmalloc (sizeof *waiter, MDL);
106 if (!waiter)
107 return ISC_R_NOMEMORY;
108 memset (waiter, 0, sizeof *waiter);
109 waiter -> refcnt = 1;
110 rc_register_mdl (&waiter, waiter, waiter -> refcnt);
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
118 status = omapi_object_reference (&waiter -> outer, inner, MDL);
119 if (status != ISC_R_SUCCESS) {
120 omapi_object_dereference ((omapi_object_t **)&waiter,
121 MDL);
122 return status;
123 }
124
125 status = omapi_object_reference (&inner -> inner,
126 (omapi_object_t *)waiter,
127 MDL);
128 if (status != ISC_R_SUCCESS) {
129 omapi_object_dereference ((omapi_object_t **)&waiter,
130 MDL);
131 return status;
132 }
133 } else
134 waiter = (omapi_waiter_object_t *)0;
135
136 do {
137 status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
138 if (status != ISC_R_SUCCESS)
139 return status;
140 } while (!waiter || !waiter -> ready);
141
142 if (waiter -> outer) {
143 if (waiter -> outer -> inner) {
144 omapi_object_dereference (&waiter -> outer -> inner,
145 MDL);
146 if (waiter -> inner)
147 omapi_object_reference
148 (&waiter -> outer -> inner,
149 waiter -> inner, MDL);
150 }
151 omapi_object_dereference (&waiter -> outer, MDL);
152 }
153 if (waiter -> inner)
154 omapi_object_dereference (&waiter -> inner, MDL);
155
156 omapi_object_dereference ((omapi_object_t **)&waiter, MDL);
157 return ISC_R_SUCCESS;
158 }
159
160 isc_result_t omapi_one_dispatch (omapi_object_t *wo,
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;
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;
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,
276 MDL);
277 if (prev) {
278 omapi_object_dereference
279 (((omapi_object_t **)
280 &prev -> next), MDL);
281 if (tmp)
282 omapi_object_reference
283 (((omapi_object_t **)
284 &prev -> next),
285 (omapi_object_t *)tmp,
286 MDL);
287 } else {
288 omapi_object_dereference
289 (((omapi_object_t **)
290 &omapi_io_states.next),
291 MDL);
292 if (tmp)
293 omapi_object_reference
294 (((omapi_object_t **)
295 &omapi_io_states.next),
296 (omapi_object_t *)tmp,
297 MDL);
298 else
299 omapi_signal_in
300 ((omapi_object_t *)
301 &omapi_io_states,
302 "ready");
303 }
304 if (tmp)
305 omapi_object_dereference
306 ((omapi_object_t **)&tmp, MDL);
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
343 isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
344 {
345 omapi_io_object_t *obj, *p, *last;
346
347 if (h -> type != omapi_type_io_object)
348 return ISC_R_INVALIDARG;
349
350 obj = (omapi_io_object_t *)h;
351
352 /* only ios for interface objects? */
353 if (strcmp (obj -> inner -> type ->name, "interface") == 0) {
354 /* remove from the list of I/O states */
355 for (p = omapi_io_states.next; p; p = p -> next) {
356 if (p == obj) {
357 last -> next = p -> next;
358 break;
359 }
360 last = p;
361 }
362
363 /*
364 * omapi_object_dereference ((omapi_object_t **)&obj, MDL);
365 */
366 }
367
368 return ISC_R_SUCCESS;
369 }
370
371 isc_result_t omapi_io_signal_handler (omapi_object_t *h,
372 const char *name, va_list ap)
373 {
374 if (h -> type != omapi_type_io_object)
375 return ISC_R_INVALIDARG;
376
377 if (h -> inner && h -> inner -> type -> signal_handler)
378 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
379 name, ap);
380 return ISC_R_NOTFOUND;
381 }
382
383 isc_result_t omapi_io_stuff_values (omapi_object_t *c,
384 omapi_object_t *id,
385 omapi_object_t *i)
386 {
387 if (i -> type != omapi_type_io_object)
388 return ISC_R_INVALIDARG;
389
390 if (i -> inner && i -> inner -> type -> stuff_values)
391 return (*(i -> inner -> type -> stuff_values)) (c, id,
392 i -> inner);
393 return ISC_R_SUCCESS;
394 }
395
396 isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
397 const char *name, va_list ap)
398 {
399 omapi_waiter_object_t *waiter;
400
401 if (h -> type != omapi_type_waiter)
402 return ISC_R_INVALIDARG;
403
404 if (!strcmp (name, "ready")) {
405 waiter = (omapi_waiter_object_t *)h;
406 waiter -> ready = 1;
407 return ISC_R_SUCCESS;
408 }
409
410 if (h -> inner && h -> inner -> type -> signal_handler)
411 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
412 name, ap);
413 return ISC_R_NOTFOUND;
414 }
415