]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/dispatch.c
- Set the SO_REUSEADDR flag when creating sockets.
[thirdparty/dhcp.git] / omapip / dispatch.c
CommitLineData
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
25static omapi_io_object_t omapi_io_states;
26u_int32_t cur_time;
27
28/* Register an I/O handle so that we can do asynchronous I/O on it. */
29
30isc_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
94isc_result_t omapi_dispatch (struct timeval *t)
95{
96 return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
97 t);
98}
99
100isc_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
150isc_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
300isc_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
314isc_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
328isc_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
335isc_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
347isc_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
360isc_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