1/* dispatch.c
2
3   Network input dispatcher... */
4
5/*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 *   Internet Systems Consortium, Inc.
22 *   950 Charter Street
23 *   Redwood City, CA 94063
24 *   <info@isc.org>
25 *   http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35#ifndef lint
36static char copyright[] =
37"$Id: dispatch.c,v 1.3 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38#endif /* not lint */
39
40#include "dhcpd.h"
41
42struct timeout *timeouts;
43static struct timeout *free_timeouts;
44
45void set_time (u_int32_t t)
46{
47	/* Do any outstanding timeouts. */
48	if (cur_time != t) {
49		cur_time = t;
50		process_outstanding_timeouts ((struct timeval *)0);
51	}
52}
53
54struct timeval *process_outstanding_timeouts (struct timeval *tvp)
55{
56	/* Call any expired timeouts, and then if there's
57	   still a timeout registered, time out the select
58	   call then. */
59      another:
60	if (timeouts) {
61		struct timeout *t;
62		if (timeouts -> when <= cur_time) {
63			t = timeouts;
64			timeouts = timeouts -> next;
65			(*(t -> func)) (t -> what);
66			if (t -> unref)
67				(*t -> unref) (&t -> what, MDL);
68			t -> next = free_timeouts;
69			free_timeouts = t;
70			goto another;
71		}
72		if (tvp) {
73			tvp -> tv_sec = timeouts -> when;
74			tvp -> tv_usec = 0;
75		}
76		return tvp;
77	} else
78		return (struct timeval *)0;
79}
80
81/* Wait for packets to come in using select().   When one does, call
82   receive_packet to receive the packet and possibly strip hardware
83   addressing information from it, and then call through the
84   bootp_packet_handler hook to try to do something with it. */
85
86void dispatch ()
87{
88	struct timeval tv, *tvp;
89	isc_result_t status;
90
91	/* Wait for a packet or a timeout... XXX */
92	do {
93		tvp = process_outstanding_timeouts (&tv);
94		status = omapi_one_dispatch (0, tvp);
95	} while (status == ISC_R_TIMEDOUT || status == ISC_R_SUCCESS);
96	log_fatal ("omapi_one_dispatch failed: %s -- exiting.",
97		   isc_result_totext (status));
98}
99
100void add_timeout (when, where, what, ref, unref)
101	TIME when;
102	void (*where) PROTO ((void *));
103	void *what;
104	tvref_t ref;
105	tvunref_t unref;
106{
107	struct timeout *t, *q;
108
109	/* See if this timeout supersedes an existing timeout. */
110	t = (struct timeout *)0;
111	for (q = timeouts; q; q = q -> next) {
112		if ((where == NULL || q -> func == where) &&
113		    q -> what == what) {
114			if (t)
115				t -> next = q -> next;
116			else
117				timeouts = q -> next;
118			break;
119		}
120		t = q;
121	}
122
123	/* If we didn't supersede a timeout, allocate a timeout
124	   structure now. */
125	if (!q) {
126		if (free_timeouts) {
127			q = free_timeouts;
128			free_timeouts = q -> next;
129		} else {
130			q = ((struct timeout *)
131			     dmalloc (sizeof (struct timeout), MDL));
132			if (!q)
133				log_fatal ("add_timeout: no memory!");
134		}
135		memset (q, 0, sizeof *q);
136		q -> func = where;
137		q -> ref = ref;
138		q -> unref = unref;
139		if (q -> ref)
140			(*q -> ref)(&q -> what, what, MDL);
141		else
142			q -> what = what;
143	}
144
145	q -> when = when;
146
147	/* Now sort this timeout into the timeout list. */
148
149	/* Beginning of list? */
150	if (!timeouts || timeouts -> when > q -> when) {
151		q -> next = timeouts;
152		timeouts = q;
153		return;
154	}
155
156	/* Middle of list? */
157	for (t = timeouts; t -> next; t = t -> next) {
158		if (t -> next -> when > q -> when) {
159			q -> next = t -> next;
160			t -> next = q;
161			return;
162		}
163	}
164
165	/* End of list. */
166	t -> next = q;
167	q -> next = (struct timeout *)0;
168}
169
170void cancel_timeout (where, what)
171	void (*where) PROTO ((void *));
172	void *what;
173{
174	struct timeout *t, *q;
175
176	/* Look for this timeout on the list, and unlink it if we find it. */
177	t = (struct timeout *)0;
178	for (q = timeouts; q; q = q -> next) {
179		if (q -> func == where && q -> what == what) {
180			if (t)
181				t -> next = q -> next;
182			else
183				timeouts = q -> next;
184			break;
185		}
186		t = q;
187	}
188
189	/* If we found the timeout, put it on the free list. */
190	if (q) {
191		if (q -> unref)
192			(*q -> unref) (&q -> what, MDL);
193		q -> next = free_timeouts;
194		free_timeouts = q;
195	}
196}
197
198#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
199void cancel_all_timeouts ()
200{
201	struct timeout *t, *n;
202	for (t = timeouts; t; t = n) {
203		n = t -> next;
204		if (t -> unref && t -> what)
205			(*t -> unref) (&t -> what, MDL);
206		t -> next = free_timeouts;
207		free_timeouts = t;
208	}
209}
210
211void relinquish_timeouts ()
212{
213	struct timeout *t, *n;
214	for (t = free_timeouts; t; t = n) {
215		n = t -> next;
216		dfree (t, MDL);
217	}
218}
219#endif
220