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