Remove building with NOCRYPTO option
[minix.git] / external / bsd / dhcp / dist / common / dispatch.c
blobf92115223f3b8a531245158fc07c40aaaf6bcc29
1 /* $NetBSD: dispatch.c,v 1.4 2014/07/12 12:09:37 spz Exp $ */
2 /* dispatch.c
4 Network input dispatcher... */
6 /*
7 * Copyright (c) 2004-2011,2013 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1995-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: dispatch.c,v 1.4 2014/07/12 12:09:37 spz Exp $");
33 #include "dhcpd.h"
35 #include <sys/time.h>
37 struct timeout *timeouts;
38 static struct timeout *free_timeouts;
40 void set_time(TIME t)
42 /* Do any outstanding timeouts. */
43 if (cur_tv . tv_sec != t) {
44 cur_tv . tv_sec = t;
45 cur_tv . tv_usec = 0;
46 process_outstanding_timeouts ((struct timeval *)0);
50 struct timeval *process_outstanding_timeouts (struct timeval *tvp)
52 /* Call any expired timeouts, and then if there's
53 still a timeout registered, time out the select
54 call then. */
55 another:
56 if (timeouts) {
57 struct timeout *t;
58 if ((timeouts -> when . tv_sec < cur_tv . tv_sec) ||
59 ((timeouts -> when . tv_sec == cur_tv . tv_sec) &&
60 (timeouts -> when . tv_usec <= cur_tv . tv_usec))) {
61 t = timeouts;
62 timeouts = timeouts -> next;
63 (*(t -> func)) (t -> what);
64 if (t -> unref)
65 (*t -> unref) (&t -> what, MDL);
66 t -> next = free_timeouts;
67 free_timeouts = t;
68 goto another;
70 if (tvp) {
71 tvp -> tv_sec = timeouts -> when . tv_sec;
72 tvp -> tv_usec = timeouts -> when . tv_usec;
74 return tvp;
75 } else
76 return (struct timeval *)0;
79 /* Wait for packets to come in using select(). When one does, call
80 receive_packet to receive the packet and possibly strip hardware
81 addressing information from it, and then call through the
82 bootp_packet_handler hook to try to do something with it. */
85 * Use the DHCP timeout list as a place to store DHCP specific
86 * information, but use the ISC timer system to actually dispatch
87 * the events.
89 * There are several things that the DHCP timer code does that the
90 * ISC code doesn't:
91 * 1) It allows for negative times
92 * 2) The cancel arguments are different. The DHCP code uses the
93 * function and data to find the proper timer to cancel while the
94 * ISC code uses a pointer to the timer.
95 * 3) The DHCP code includes provision for incrementing and decrementing
96 * a reference counter associated with the data.
97 * The first one is fairly easy to fix but will take some time to go throuh
98 * the callers and update them. The second is also not all that difficult
99 * in concept - add a pointer to the appropriate structures to hold a pointer
100 * to the timer and use that. The complications arise in trying to ensure
101 * that all of the corner cases are covered. The last one is potentially
102 * more painful and requires more investigation.
104 * The plan is continue with the older DHCP calls and timer list. The
105 * calls will continue to manipulate the list but will also pass a
106 * timer to the ISC timer code for the actual dispatch. Later, if desired,
107 * we can go back and modify the underlying calls to use the ISC
108 * timer functions directly without requiring all of the code to change
109 * at the same time.
112 void
113 dispatch(void)
115 isc_result_t status;
117 do {
118 status = isc_app_ctxrun(dhcp_gbl_ctx.actx);
121 * isc_app_ctxrun can be stopped by receiving a
122 * signal. It will return ISC_R_RELOAD in that
123 * case. That is a normal behavior.
126 if (status == ISC_R_RELOAD) {
128 * dhcp_set_control_state() will do the job.
129 * Note its first argument is ignored.
131 status = dhcp_set_control_state(server_shutdown,
132 server_shutdown);
133 if (status == ISC_R_SUCCESS)
134 status = ISC_R_RELOAD;
136 } while (status == ISC_R_RELOAD);
138 log_fatal ("Dispatch routine failed: %s -- exiting",
139 isc_result_totext (status));
142 static void
143 isclib_timer_callback(isc_task_t *taskp,
144 isc_event_t *eventp)
146 struct timeout *t = (struct timeout *)eventp->ev_arg;
147 struct timeout *q, *r;
149 /* Get the current time... */
150 gettimeofday (&cur_tv, (struct timezone *)0);
153 * Find the timeout on the dhcp list and remove it.
154 * As the list isn't ordered we search the entire list
157 r = NULL;
158 for (q = timeouts; q; q = q->next) {
159 if (q == t) {
160 if (r)
161 r->next = q->next;
162 else
163 timeouts = q->next;
164 break;
166 r = q;
170 * The timer should always be on the list. If it is we do
171 * the work and detach the timer block, if not we log an error.
172 * In both cases we attempt free the ISC event and continue
173 * processing.
176 if (q != NULL) {
177 /* call the callback function */
178 (*(q->func)) (q->what);
179 if (q->unref) {
180 (*q->unref) (&q->what, MDL);
182 q->next = free_timeouts;
183 isc_timer_detach(&q->isc_timeout);
184 free_timeouts = q;
185 } else {
187 * Hmm, we should clean up the timer structure but aren't
188 * sure about the pointer to the timer block we got so
189 * don't try to - may change this to a log_fatal
191 log_error("Error finding timer structure");
194 isc_event_free(&eventp);
195 return;
198 /* maximum value for usec */
199 #define USEC_MAX 1000000
200 #define DHCP_SEC_MAX 0xFFFFFFFF
202 void add_timeout (when, where, what, ref, unref)
203 struct timeval *when;
204 void (*where) (void *);
205 void *what;
206 tvref_t ref;
207 tvunref_t unref;
209 struct timeout *t, *q;
210 int usereset = 0;
211 isc_result_t status;
212 int64_t sec;
213 int usec;
214 isc_interval_t interval;
215 isc_time_t expires;
217 /* See if this timeout supersedes an existing timeout. */
218 t = (struct timeout *)0;
219 for (q = timeouts; q; q = q->next) {
220 if ((where == NULL || q->func == where) &&
221 q->what == what) {
222 if (t)
223 t->next = q->next;
224 else
225 timeouts = q->next;
226 usereset = 1;
227 break;
229 t = q;
232 /* If we didn't supersede a timeout, allocate a timeout
233 structure now. */
234 if (!q) {
235 if (free_timeouts) {
236 q = free_timeouts;
237 free_timeouts = q->next;
238 } else {
239 q = ((struct timeout *)
240 dmalloc(sizeof(struct timeout), MDL));
241 if (!q) {
242 log_fatal("add_timeout: no memory!");
245 memset(q, 0, sizeof *q);
246 q->func = where;
247 q->ref = ref;
248 q->unref = unref;
249 if (q->ref)
250 (*q->ref)(&q->what, what, MDL);
251 else
252 q->what = what;
256 * The value passed in is a time from an epoch but we need a relative
257 * time so we need to do some math to try and recover the period.
258 * This is complicated by the fact that not all of the calls cared
259 * about the usec value, if it's zero we assume the caller didn't care.
261 * The ISC timer library doesn't seem to like negative values
262 * and can't accept any values above 4G-1 seconds so we limit
263 * the values to 0 <= value < 4G-1. We do it before
264 * checking the trace option so that both the trace code and
265 * the working code use the same values.
268 sec = when->tv_sec - cur_tv.tv_sec;
269 usec = when->tv_usec - cur_tv.tv_usec;
271 if ((when->tv_usec != 0) && (usec < 0)) {
272 sec--;
273 usec += USEC_MAX;
276 if (sec < 0) {
277 sec = 0;
278 usec = 0;
279 } else if (sec > DHCP_SEC_MAX) {
280 log_error("Timeout requested too large "
281 "reducing to 2^^32-1");
282 sec = DHCP_SEC_MAX;
283 usec = 0;
284 } else if (usec < 0) {
285 usec = 0;
286 } else if (usec >= USEC_MAX) {
287 usec = USEC_MAX - 1;
291 * This is necessary for the tracing code but we put it
292 * here in case we want to compare timing information
293 * for some reason, like debugging.
295 q->when.tv_sec = cur_tv.tv_sec + (sec & DHCP_SEC_MAX);
296 q->when.tv_usec = usec;
298 #if defined (TRACING)
299 if (trace_playback()) {
301 * If we are doing playback we need to handle the timers
302 * within this code rather than having the isclib handle
303 * them for us. We need to keep the timer list in order
304 * to allow us to find the ones to timeout.
306 * By using a different timer setup in the playback we may
307 * have variations between the orginal and the playback but
308 * it's the best we can do for now.
311 /* Beginning of list? */
312 if (!timeouts || (timeouts->when.tv_sec > q-> when.tv_sec) ||
313 ((timeouts->when.tv_sec == q->when.tv_sec) &&
314 (timeouts->when.tv_usec > q->when.tv_usec))) {
315 q->next = timeouts;
316 timeouts = q;
317 return;
320 /* Middle of list? */
321 for (t = timeouts; t->next; t = t->next) {
322 if ((t->next->when.tv_sec > q->when.tv_sec) ||
323 ((t->next->when.tv_sec == q->when.tv_sec) &&
324 (t->next->when.tv_usec > q->when.tv_usec))) {
325 q->next = t->next;
326 t->next = q;
327 return;
331 /* End of list. */
332 t->next = q;
333 q->next = (struct timeout *)0;
334 return;
336 #endif
338 * Don't bother sorting the DHCP list, just add it to the front.
339 * Eventually the list should be removed as we migrate the callers
340 * to the native ISC timer functions, if it becomes a performance
341 * problem before then we may need to order the list.
343 q->next = timeouts;
344 timeouts = q;
346 isc_interval_set(&interval, sec & DHCP_SEC_MAX, usec * 1000);
347 status = isc_time_nowplusinterval(&expires, &interval);
348 if (status != ISC_R_SUCCESS) {
350 * The system time function isn't happy or returned
351 * a value larger than isc_time_t can hold.
353 log_fatal("Unable to set up timer: %s",
354 isc_result_totext(status));
357 if (usereset == 0) {
358 status = isc_timer_create(dhcp_gbl_ctx.timermgr,
359 isc_timertype_once, &expires,
360 NULL, dhcp_gbl_ctx.task,
361 isclib_timer_callback,
362 (void *)q, &q->isc_timeout);
363 } else {
364 status = isc_timer_reset(q->isc_timeout,
365 isc_timertype_once, &expires,
366 NULL, 0);
369 /* If it fails log an error and die */
370 if (status != ISC_R_SUCCESS) {
371 log_fatal("Unable to add timeout to isclib\n");
374 return;
377 void cancel_timeout (where, what)
378 void (*where) (void *);
379 void *what;
381 struct timeout *t, *q;
383 /* Look for this timeout on the list, and unlink it if we find it. */
384 t = (struct timeout *)0;
385 for (q = timeouts; q; q = q -> next) {
386 if (q->func == where && q->what == what) {
387 if (t)
388 t->next = q->next;
389 else
390 timeouts = q->next;
391 break;
393 t = q;
397 * If we found the timeout, cancel it and put it on the free list.
398 * The TRACING stuff is ugly but we don't add a timer when doing
399 * playback so we don't want to remove them then either.
401 if (q) {
402 #if defined (TRACING)
403 if (!trace_playback()) {
404 #endif
405 isc_timer_detach(&q->isc_timeout);
406 #if defined (TRACING)
408 #endif
410 if (q->unref)
411 (*q->unref) (&q->what, MDL);
412 q->next = free_timeouts;
413 free_timeouts = q;
417 #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
418 void cancel_all_timeouts ()
420 struct timeout *t, *n;
421 for (t = timeouts; t; t = n) {
422 n = t->next;
423 isc_timer_detach(&t->isc_timeout);
424 if (t->unref && t->what)
425 (*t->unref) (&t->what, MDL);
426 t->next = free_timeouts;
427 free_timeouts = t;
431 void relinquish_timeouts ()
433 struct timeout *t, *n;
434 for (t = free_timeouts; t; t = n) {
435 n = t->next;
436 dfree(t, MDL);
439 #endif