xref: /minix3/external/bsd/dhcp/dist/common/dispatch.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
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