xref: /minix/external/bsd/dhcp/dist/omapip/dispatch.c (revision 83ee113e)
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    I/O dispatcher. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004,2007-2009,2013-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 1999-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 <omapip/omapip_p.h>
36*83ee113eSDavid van Moolenbroek #include <sys/time.h>
37*83ee113eSDavid van Moolenbroek 
38*83ee113eSDavid van Moolenbroek static omapi_io_object_t omapi_io_states;
39*83ee113eSDavid van Moolenbroek struct timeval cur_tv;
40*83ee113eSDavid van Moolenbroek 
41*83ee113eSDavid van Moolenbroek struct eventqueue *rw_queue_empty;
42*83ee113eSDavid van Moolenbroek 
OMAPI_OBJECT_ALLOC(omapi_io,omapi_io_object_t,omapi_type_io_object)43*83ee113eSDavid van Moolenbroek OMAPI_OBJECT_ALLOC (omapi_io,
44*83ee113eSDavid van Moolenbroek 		    omapi_io_object_t, omapi_type_io_object)
45*83ee113eSDavid van Moolenbroek OMAPI_OBJECT_ALLOC (omapi_waiter,
46*83ee113eSDavid van Moolenbroek 		    omapi_waiter_object_t, omapi_type_waiter)
47*83ee113eSDavid van Moolenbroek 
48*83ee113eSDavid van Moolenbroek void
49*83ee113eSDavid van Moolenbroek register_eventhandler(struct eventqueue **queue, void (*handler)(void *))
50*83ee113eSDavid van Moolenbroek {
51*83ee113eSDavid van Moolenbroek 	struct eventqueue *t, *q;
52*83ee113eSDavid van Moolenbroek 
53*83ee113eSDavid van Moolenbroek 	/* traverse to end of list */
54*83ee113eSDavid van Moolenbroek 	t = NULL;
55*83ee113eSDavid van Moolenbroek 	for (q = *queue ; q ; q = q->next) {
56*83ee113eSDavid van Moolenbroek 		if (q->handler == handler)
57*83ee113eSDavid van Moolenbroek 			return; /* handler already registered */
58*83ee113eSDavid van Moolenbroek 		t = q;
59*83ee113eSDavid van Moolenbroek 	}
60*83ee113eSDavid van Moolenbroek 
61*83ee113eSDavid van Moolenbroek 	q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL));
62*83ee113eSDavid van Moolenbroek 	if (!q)
63*83ee113eSDavid van Moolenbroek 		log_fatal("register_eventhandler: no memory!");
64*83ee113eSDavid van Moolenbroek 	memset(q, 0, sizeof *q);
65*83ee113eSDavid van Moolenbroek 	if (t)
66*83ee113eSDavid van Moolenbroek 		t->next = q;
67*83ee113eSDavid van Moolenbroek 	else
68*83ee113eSDavid van Moolenbroek 		*queue	= q;
69*83ee113eSDavid van Moolenbroek 	q->handler = handler;
70*83ee113eSDavid van Moolenbroek 	return;
71*83ee113eSDavid van Moolenbroek }
72*83ee113eSDavid van Moolenbroek 
73*83ee113eSDavid van Moolenbroek void
unregister_eventhandler(struct eventqueue ** queue,void (* handler)(void *))74*83ee113eSDavid van Moolenbroek unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *))
75*83ee113eSDavid van Moolenbroek {
76*83ee113eSDavid van Moolenbroek 	struct eventqueue *t, *q;
77*83ee113eSDavid van Moolenbroek 
78*83ee113eSDavid van Moolenbroek 	/* traverse to end of list */
79*83ee113eSDavid van Moolenbroek 	t= NULL;
80*83ee113eSDavid van Moolenbroek 	for (q = *queue ; q ; q = q->next) {
81*83ee113eSDavid van Moolenbroek 		if (q->handler == handler) {
82*83ee113eSDavid van Moolenbroek 			if (t)
83*83ee113eSDavid van Moolenbroek 				t->next = q->next;
84*83ee113eSDavid van Moolenbroek 			else
85*83ee113eSDavid van Moolenbroek 				*queue = q->next;
86*83ee113eSDavid van Moolenbroek 			dfree(q, MDL); /* Don't access q after this!*/
87*83ee113eSDavid van Moolenbroek 			break;
88*83ee113eSDavid van Moolenbroek 		}
89*83ee113eSDavid van Moolenbroek 		t = q;
90*83ee113eSDavid van Moolenbroek 	}
91*83ee113eSDavid van Moolenbroek 	return;
92*83ee113eSDavid van Moolenbroek }
93*83ee113eSDavid van Moolenbroek 
94*83ee113eSDavid van Moolenbroek void
trigger_event(struct eventqueue ** queue)95*83ee113eSDavid van Moolenbroek trigger_event(struct eventqueue **queue)
96*83ee113eSDavid van Moolenbroek {
97*83ee113eSDavid van Moolenbroek 	struct eventqueue *q;
98*83ee113eSDavid van Moolenbroek 
99*83ee113eSDavid van Moolenbroek 	for (q=*queue ; q ; q=q->next) {
100*83ee113eSDavid van Moolenbroek 		if (q->handler)
101*83ee113eSDavid van Moolenbroek 			(*q->handler)(NULL);
102*83ee113eSDavid van Moolenbroek 	}
103*83ee113eSDavid van Moolenbroek }
104*83ee113eSDavid van Moolenbroek 
105*83ee113eSDavid van Moolenbroek /*
106*83ee113eSDavid van Moolenbroek  * Callback routine to connect the omapi I/O object and socket with
107*83ee113eSDavid van Moolenbroek  * the isc socket code.  The isc socket code will call this routine
108*83ee113eSDavid van Moolenbroek  * which will then call the correct local routine to process the bytes.
109*83ee113eSDavid van Moolenbroek  *
110*83ee113eSDavid van Moolenbroek  * Currently we are always willing to read more data, this should be modified
111*83ee113eSDavid van Moolenbroek  * so that on connections we don't read more if we already have enough.
112*83ee113eSDavid van Moolenbroek  *
113*83ee113eSDavid van Moolenbroek  * If we have more bytes to write we ask the library to call us when
114*83ee113eSDavid van Moolenbroek  * we can write more.  If we indicate we don't have more to write we need
115*83ee113eSDavid van Moolenbroek  * to poke the library via isc_socket_fdwatchpoke.
116*83ee113eSDavid van Moolenbroek  */
117*83ee113eSDavid van Moolenbroek 
118*83ee113eSDavid van Moolenbroek /*
119*83ee113eSDavid van Moolenbroek  * sockdelete indicates if we are deleting the socket or leaving it in place
120*83ee113eSDavid van Moolenbroek  * 1 is delete, 0 is leave in place
121*83ee113eSDavid van Moolenbroek  */
122*83ee113eSDavid van Moolenbroek #define SOCKDELETE 1
123*83ee113eSDavid van Moolenbroek static int
omapi_iscsock_cb(isc_task_t * task,isc_socket_t * socket,void * cbarg,int flags)124*83ee113eSDavid van Moolenbroek omapi_iscsock_cb(isc_task_t   *task,
125*83ee113eSDavid van Moolenbroek 		 isc_socket_t *socket,
126*83ee113eSDavid van Moolenbroek 		 void         *cbarg,
127*83ee113eSDavid van Moolenbroek 		 int           flags)
128*83ee113eSDavid van Moolenbroek {
129*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *obj;
130*83ee113eSDavid van Moolenbroek 	isc_result_t status;
131*83ee113eSDavid van Moolenbroek 
132*83ee113eSDavid van Moolenbroek 	/* Get the current time... */
133*83ee113eSDavid van Moolenbroek 	gettimeofday (&cur_tv, (struct timezone *)0);
134*83ee113eSDavid van Moolenbroek 
135*83ee113eSDavid van Moolenbroek 	/* isc socket stuff */
136*83ee113eSDavid van Moolenbroek #if SOCKDELETE
137*83ee113eSDavid van Moolenbroek 	/*
138*83ee113eSDavid van Moolenbroek 	 * walk through the io states list, if our object is on there
139*83ee113eSDavid van Moolenbroek 	 * service it.  if not ignore it.
140*83ee113eSDavid van Moolenbroek 	 */
141*83ee113eSDavid van Moolenbroek 	for (obj = omapi_io_states.next;
142*83ee113eSDavid van Moolenbroek 	     (obj != NULL) && (obj->next != NULL);
143*83ee113eSDavid van Moolenbroek 	     obj = obj->next) {
144*83ee113eSDavid van Moolenbroek 		if (obj == cbarg)
145*83ee113eSDavid van Moolenbroek 			break;
146*83ee113eSDavid van Moolenbroek 	}
147*83ee113eSDavid van Moolenbroek 	if (obj == NULL) {
148*83ee113eSDavid van Moolenbroek 		return(0);
149*83ee113eSDavid van Moolenbroek 	}
150*83ee113eSDavid van Moolenbroek #else
151*83ee113eSDavid van Moolenbroek 	/* Not much to be done if we have the wrong type of object. */
152*83ee113eSDavid van Moolenbroek 	if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) {
153*83ee113eSDavid van Moolenbroek 		log_fatal ("Incorrect object type, must be of type io_object");
154*83ee113eSDavid van Moolenbroek 	}
155*83ee113eSDavid van Moolenbroek 	obj = (omapi_io_object_t *)cbarg;
156*83ee113eSDavid van Moolenbroek 
157*83ee113eSDavid van Moolenbroek 	/*
158*83ee113eSDavid van Moolenbroek 	 * If the object is marked as closed don't try and process
159*83ee113eSDavid van Moolenbroek 	 * anything just indicate that we don't want any more.
160*83ee113eSDavid van Moolenbroek 	 *
161*83ee113eSDavid van Moolenbroek 	 * This should be a temporary fix until we arrange to properly
162*83ee113eSDavid van Moolenbroek 	 * close the socket.
163*83ee113eSDavid van Moolenbroek 	 */
164*83ee113eSDavid van Moolenbroek 	if (obj->closed == ISC_TRUE) {
165*83ee113eSDavid van Moolenbroek 		return(0);
166*83ee113eSDavid van Moolenbroek 	}
167*83ee113eSDavid van Moolenbroek #endif
168*83ee113eSDavid van Moolenbroek 
169*83ee113eSDavid van Moolenbroek 	if ((flags == ISC_SOCKFDWATCH_READ) &&
170*83ee113eSDavid van Moolenbroek 	    (obj->reader != NULL) &&
171*83ee113eSDavid van Moolenbroek 	    (obj->inner != NULL)) {
172*83ee113eSDavid van Moolenbroek 		status = obj->reader(obj->inner);
173*83ee113eSDavid van Moolenbroek 		/*
174*83ee113eSDavid van Moolenbroek 		 * If we are shutting down (basically tried to
175*83ee113eSDavid van Moolenbroek 		 * read and got no bytes) we don't need to try
176*83ee113eSDavid van Moolenbroek 		 * again.
177*83ee113eSDavid van Moolenbroek 		 */
178*83ee113eSDavid van Moolenbroek 		if (status == ISC_R_SHUTTINGDOWN)
179*83ee113eSDavid van Moolenbroek 			return (0);
180*83ee113eSDavid van Moolenbroek 		/* Otherwise We always ask for more when reading */
181*83ee113eSDavid van Moolenbroek 		return (1);
182*83ee113eSDavid van Moolenbroek 	} else if ((flags == ISC_SOCKFDWATCH_WRITE) &&
183*83ee113eSDavid van Moolenbroek 		 (obj->writer != NULL) &&
184*83ee113eSDavid van Moolenbroek 		 (obj->inner != NULL)) {
185*83ee113eSDavid van Moolenbroek 		status = obj->writer(obj->inner);
186*83ee113eSDavid van Moolenbroek 		/* If the writer has more to write they should return
187*83ee113eSDavid van Moolenbroek 		 * ISC_R_INPROGRESS */
188*83ee113eSDavid van Moolenbroek 		if (status == ISC_R_INPROGRESS) {
189*83ee113eSDavid van Moolenbroek 			return (1);
190*83ee113eSDavid van Moolenbroek 		}
191*83ee113eSDavid van Moolenbroek 	}
192*83ee113eSDavid van Moolenbroek 
193*83ee113eSDavid van Moolenbroek 	/*
194*83ee113eSDavid van Moolenbroek 	 * We get here if we either had an error (inconsistent
195*83ee113eSDavid van Moolenbroek 	 * structures etc) or no more to write, tell the socket
196*83ee113eSDavid van Moolenbroek 	 * lib we don't have more to do right now.
197*83ee113eSDavid van Moolenbroek 	 */
198*83ee113eSDavid van Moolenbroek 	return (0);
199*83ee113eSDavid van Moolenbroek }
200*83ee113eSDavid van Moolenbroek 
201*83ee113eSDavid van Moolenbroek /* Register an I/O handle so that we can do asynchronous I/O on it. */
202*83ee113eSDavid van Moolenbroek 
omapi_register_io_object(omapi_object_t * h,int (* readfd)(omapi_object_t *),int (* writefd)(omapi_object_t *),isc_result_t (* reader)(omapi_object_t *),isc_result_t (* writer)(omapi_object_t *),isc_result_t (* reaper)(omapi_object_t *))203*83ee113eSDavid van Moolenbroek isc_result_t omapi_register_io_object (omapi_object_t *h,
204*83ee113eSDavid van Moolenbroek 				       int (*readfd) (omapi_object_t *),
205*83ee113eSDavid van Moolenbroek 				       int (*writefd) (omapi_object_t *),
206*83ee113eSDavid van Moolenbroek 				       isc_result_t (*reader)
207*83ee113eSDavid van Moolenbroek 						(omapi_object_t *),
208*83ee113eSDavid van Moolenbroek 				       isc_result_t (*writer)
209*83ee113eSDavid van Moolenbroek 						(omapi_object_t *),
210*83ee113eSDavid van Moolenbroek 				       isc_result_t (*reaper)
211*83ee113eSDavid van Moolenbroek 						(omapi_object_t *))
212*83ee113eSDavid van Moolenbroek {
213*83ee113eSDavid van Moolenbroek 	isc_result_t status;
214*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *obj, *p;
215*83ee113eSDavid van Moolenbroek 	int fd_flags = 0, fd = 0;
216*83ee113eSDavid van Moolenbroek 
217*83ee113eSDavid van Moolenbroek 	/* omapi_io_states is a static object.   If its reference count
218*83ee113eSDavid van Moolenbroek 	   is zero, this is the first I/O handle to be registered, so
219*83ee113eSDavid van Moolenbroek 	   we need to initialize it.   Because there is no inner or outer
220*83ee113eSDavid van Moolenbroek 	   pointer on this object, and we're setting its refcnt to 1, it
221*83ee113eSDavid van Moolenbroek 	   will never be freed. */
222*83ee113eSDavid van Moolenbroek 	if (!omapi_io_states.refcnt) {
223*83ee113eSDavid van Moolenbroek 		omapi_io_states.refcnt = 1;
224*83ee113eSDavid van Moolenbroek 		omapi_io_states.type = omapi_type_io_object;
225*83ee113eSDavid van Moolenbroek 	}
226*83ee113eSDavid van Moolenbroek 
227*83ee113eSDavid van Moolenbroek 	obj = (omapi_io_object_t *)0;
228*83ee113eSDavid van Moolenbroek 	status = omapi_io_allocate (&obj, MDL);
229*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
230*83ee113eSDavid van Moolenbroek 		return status;
231*83ee113eSDavid van Moolenbroek 	obj->closed = ISC_FALSE;  /* mark as open */
232*83ee113eSDavid van Moolenbroek 
233*83ee113eSDavid van Moolenbroek 	status = omapi_object_reference (&obj -> inner, h, MDL);
234*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
235*83ee113eSDavid van Moolenbroek 		omapi_io_dereference (&obj, MDL);
236*83ee113eSDavid van Moolenbroek 		return status;
237*83ee113eSDavid van Moolenbroek 	}
238*83ee113eSDavid van Moolenbroek 
239*83ee113eSDavid van Moolenbroek 	status = omapi_object_reference (&h -> outer,
240*83ee113eSDavid van Moolenbroek 					 (omapi_object_t *)obj, MDL);
241*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
242*83ee113eSDavid van Moolenbroek 		omapi_io_dereference (&obj, MDL);
243*83ee113eSDavid van Moolenbroek 		return status;
244*83ee113eSDavid van Moolenbroek 	}
245*83ee113eSDavid van Moolenbroek 
246*83ee113eSDavid van Moolenbroek 	/*
247*83ee113eSDavid van Moolenbroek 	 * Attach the I/O object to the isc socket library via the
248*83ee113eSDavid van Moolenbroek 	 * fdwatch function.  This allows the socket library to watch
249*83ee113eSDavid van Moolenbroek 	 * over a socket that we built.  If there are both a read and
250*83ee113eSDavid van Moolenbroek 	 * a write socket we asssume they are the same socket.
251*83ee113eSDavid van Moolenbroek 	 */
252*83ee113eSDavid van Moolenbroek 
253*83ee113eSDavid van Moolenbroek 	if (readfd) {
254*83ee113eSDavid van Moolenbroek 		fd_flags |= ISC_SOCKFDWATCH_READ;
255*83ee113eSDavid van Moolenbroek 		fd = readfd(h);
256*83ee113eSDavid van Moolenbroek 	}
257*83ee113eSDavid van Moolenbroek 
258*83ee113eSDavid van Moolenbroek 	if (writefd) {
259*83ee113eSDavid van Moolenbroek 		fd_flags |= ISC_SOCKFDWATCH_WRITE;
260*83ee113eSDavid van Moolenbroek 		fd = writefd(h);
261*83ee113eSDavid van Moolenbroek 	}
262*83ee113eSDavid van Moolenbroek 
263*83ee113eSDavid van Moolenbroek 	if (fd_flags != 0) {
264*83ee113eSDavid van Moolenbroek 		status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr,
265*83ee113eSDavid van Moolenbroek 						  fd, fd_flags,
266*83ee113eSDavid van Moolenbroek 						  omapi_iscsock_cb,
267*83ee113eSDavid van Moolenbroek 						  obj,
268*83ee113eSDavid van Moolenbroek 						  dhcp_gbl_ctx.task,
269*83ee113eSDavid van Moolenbroek 						  &obj->fd);
270*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
271*83ee113eSDavid van Moolenbroek 			log_error("Unable to register fd with library %s",
272*83ee113eSDavid van Moolenbroek 				   isc_result_totext(status));
273*83ee113eSDavid van Moolenbroek 
274*83ee113eSDavid van Moolenbroek 			/*sar*/
275*83ee113eSDavid van Moolenbroek 			/* is this the cleanup we need? */
276*83ee113eSDavid van Moolenbroek 			omapi_object_dereference(&h->outer, MDL);
277*83ee113eSDavid van Moolenbroek 			omapi_io_dereference (&obj, MDL);
278*83ee113eSDavid van Moolenbroek 			return (status);
279*83ee113eSDavid van Moolenbroek 		}
280*83ee113eSDavid van Moolenbroek 	}
281*83ee113eSDavid van Moolenbroek 
282*83ee113eSDavid van Moolenbroek 
283*83ee113eSDavid van Moolenbroek 	/* Find the last I/O state, if there are any. */
284*83ee113eSDavid van Moolenbroek 	for (p = omapi_io_states.next;
285*83ee113eSDavid van Moolenbroek 	     p && p -> next; p = p -> next)
286*83ee113eSDavid van Moolenbroek 		;
287*83ee113eSDavid van Moolenbroek 	if (p)
288*83ee113eSDavid van Moolenbroek 		omapi_io_reference (&p -> next, obj, MDL);
289*83ee113eSDavid van Moolenbroek 	else
290*83ee113eSDavid van Moolenbroek 		omapi_io_reference (&omapi_io_states.next, obj, MDL);
291*83ee113eSDavid van Moolenbroek 
292*83ee113eSDavid van Moolenbroek 	obj -> readfd = readfd;
293*83ee113eSDavid van Moolenbroek 	obj -> writefd = writefd;
294*83ee113eSDavid van Moolenbroek 	obj -> reader = reader;
295*83ee113eSDavid van Moolenbroek 	obj -> writer = writer;
296*83ee113eSDavid van Moolenbroek 	obj -> reaper = reaper;
297*83ee113eSDavid van Moolenbroek 
298*83ee113eSDavid van Moolenbroek 	omapi_io_dereference(&obj, MDL);
299*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
300*83ee113eSDavid van Moolenbroek }
301*83ee113eSDavid van Moolenbroek 
302*83ee113eSDavid van Moolenbroek /*
303*83ee113eSDavid van Moolenbroek  * ReRegister an I/O handle so that we can do asynchronous I/O on it.
304*83ee113eSDavid van Moolenbroek  * If the handle doesn't exist we call the register routine to build it.
305*83ee113eSDavid van Moolenbroek  * If it does exist we change the functions associated with it, and
306*83ee113eSDavid van Moolenbroek  * repoke the fd code to make it happy.  Neither the objects nor the
307*83ee113eSDavid van Moolenbroek  * fd are allowed to have changed.
308*83ee113eSDavid van Moolenbroek  */
309*83ee113eSDavid van Moolenbroek 
omapi_reregister_io_object(omapi_object_t * h,int (* readfd)(omapi_object_t *),int (* writefd)(omapi_object_t *),isc_result_t (* reader)(omapi_object_t *),isc_result_t (* writer)(omapi_object_t *),isc_result_t (* reaper)(omapi_object_t *))310*83ee113eSDavid van Moolenbroek isc_result_t omapi_reregister_io_object (omapi_object_t *h,
311*83ee113eSDavid van Moolenbroek 					 int (*readfd) (omapi_object_t *),
312*83ee113eSDavid van Moolenbroek 					 int (*writefd) (omapi_object_t *),
313*83ee113eSDavid van Moolenbroek 					 isc_result_t (*reader)
314*83ee113eSDavid van Moolenbroek 					 	(omapi_object_t *),
315*83ee113eSDavid van Moolenbroek 					 isc_result_t (*writer)
316*83ee113eSDavid van Moolenbroek 					 	(omapi_object_t *),
317*83ee113eSDavid van Moolenbroek 					 isc_result_t (*reaper)
318*83ee113eSDavid van Moolenbroek 					 	(omapi_object_t *))
319*83ee113eSDavid van Moolenbroek {
320*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *obj;
321*83ee113eSDavid van Moolenbroek 	int fd_flags = 0;
322*83ee113eSDavid van Moolenbroek 
323*83ee113eSDavid van Moolenbroek 	if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) {
324*83ee113eSDavid van Moolenbroek 		/*
325*83ee113eSDavid van Moolenbroek 		 * If we don't have an object or if the type isn't what
326*83ee113eSDavid van Moolenbroek 		 * we expect do the normal registration (which will overwrite
327*83ee113eSDavid van Moolenbroek 		 * an incorrect type, that's what we did historically, may
328*83ee113eSDavid van Moolenbroek 		 * want to change that)
329*83ee113eSDavid van Moolenbroek 		 */
330*83ee113eSDavid van Moolenbroek 		return (omapi_register_io_object (h, readfd, writefd,
331*83ee113eSDavid van Moolenbroek 						  reader, writer, reaper));
332*83ee113eSDavid van Moolenbroek 	}
333*83ee113eSDavid van Moolenbroek 
334*83ee113eSDavid van Moolenbroek 	/* We have an io object of the correct type, try to update it */
335*83ee113eSDavid van Moolenbroek 	/*sar*/
336*83ee113eSDavid van Moolenbroek 	/* Should we validate that the fd matches the previous one?
337*83ee113eSDavid van Moolenbroek 	 * It's suppossed to, that's a requirement, don't bother yet */
338*83ee113eSDavid van Moolenbroek 
339*83ee113eSDavid van Moolenbroek 	obj = (omapi_io_object_t *)h->outer;
340*83ee113eSDavid van Moolenbroek 
341*83ee113eSDavid van Moolenbroek 	obj->readfd = readfd;
342*83ee113eSDavid van Moolenbroek 	obj->writefd = writefd;
343*83ee113eSDavid van Moolenbroek 	obj->reader = reader;
344*83ee113eSDavid van Moolenbroek 	obj->writer = writer;
345*83ee113eSDavid van Moolenbroek 	obj->reaper = reaper;
346*83ee113eSDavid van Moolenbroek 
347*83ee113eSDavid van Moolenbroek 	if (readfd) {
348*83ee113eSDavid van Moolenbroek 		fd_flags |= ISC_SOCKFDWATCH_READ;
349*83ee113eSDavid van Moolenbroek 	}
350*83ee113eSDavid van Moolenbroek 
351*83ee113eSDavid van Moolenbroek 	if (writefd) {
352*83ee113eSDavid van Moolenbroek 		fd_flags |= ISC_SOCKFDWATCH_WRITE;
353*83ee113eSDavid van Moolenbroek 	}
354*83ee113eSDavid van Moolenbroek 
355*83ee113eSDavid van Moolenbroek 	isc_socket_fdwatchpoke(obj->fd, fd_flags);
356*83ee113eSDavid van Moolenbroek 
357*83ee113eSDavid van Moolenbroek 	return (ISC_R_SUCCESS);
358*83ee113eSDavid van Moolenbroek }
359*83ee113eSDavid van Moolenbroek 
omapi_unregister_io_object(omapi_object_t * h)360*83ee113eSDavid van Moolenbroek isc_result_t omapi_unregister_io_object (omapi_object_t *h)
361*83ee113eSDavid van Moolenbroek {
362*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *obj, *ph;
363*83ee113eSDavid van Moolenbroek #if SOCKDELETE
364*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *p, *last;
365*83ee113eSDavid van Moolenbroek #endif
366*83ee113eSDavid van Moolenbroek 
367*83ee113eSDavid van Moolenbroek 	if (!h -> outer || h -> outer -> type != omapi_type_io_object)
368*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
369*83ee113eSDavid van Moolenbroek 	obj = (omapi_io_object_t *)h -> outer;
370*83ee113eSDavid van Moolenbroek 	ph = (omapi_io_object_t *)0;
371*83ee113eSDavid van Moolenbroek 	omapi_io_reference (&ph, obj, MDL);
372*83ee113eSDavid van Moolenbroek 
373*83ee113eSDavid van Moolenbroek #if SOCKDELETE
374*83ee113eSDavid van Moolenbroek 	/*
375*83ee113eSDavid van Moolenbroek 	 * For now we leave this out.  We can't clean up the isc socket
376*83ee113eSDavid van Moolenbroek 	 * structure cleanly yet so we need to leave the io object in place.
377*83ee113eSDavid van Moolenbroek 	 * By leaving it on the io states list we avoid it being freed.
378*83ee113eSDavid van Moolenbroek 	 * We also mark it as closed to avoid using it.
379*83ee113eSDavid van Moolenbroek 	 */
380*83ee113eSDavid van Moolenbroek 
381*83ee113eSDavid van Moolenbroek 	/* remove from the list of I/O states */
382*83ee113eSDavid van Moolenbroek         last = &omapi_io_states;
383*83ee113eSDavid van Moolenbroek 	for (p = omapi_io_states.next; p; p = p -> next) {
384*83ee113eSDavid van Moolenbroek 		if (p == obj) {
385*83ee113eSDavid van Moolenbroek 			omapi_io_dereference (&last -> next, MDL);
386*83ee113eSDavid van Moolenbroek 			omapi_io_reference (&last -> next, p -> next, MDL);
387*83ee113eSDavid van Moolenbroek 			break;
388*83ee113eSDavid van Moolenbroek 		}
389*83ee113eSDavid van Moolenbroek 		last = p;
390*83ee113eSDavid van Moolenbroek 	}
391*83ee113eSDavid van Moolenbroek 	if (obj -> next)
392*83ee113eSDavid van Moolenbroek 		omapi_io_dereference (&obj -> next, MDL);
393*83ee113eSDavid van Moolenbroek #endif
394*83ee113eSDavid van Moolenbroek 
395*83ee113eSDavid van Moolenbroek 	if (obj -> outer) {
396*83ee113eSDavid van Moolenbroek 		if (obj -> outer -> inner == (omapi_object_t *)obj)
397*83ee113eSDavid van Moolenbroek 			omapi_object_dereference (&obj -> outer -> inner,
398*83ee113eSDavid van Moolenbroek 						  MDL);
399*83ee113eSDavid van Moolenbroek 		omapi_object_dereference (&obj -> outer, MDL);
400*83ee113eSDavid van Moolenbroek 	}
401*83ee113eSDavid van Moolenbroek 	omapi_object_dereference (&obj -> inner, MDL);
402*83ee113eSDavid van Moolenbroek 	omapi_object_dereference (&h -> outer, MDL);
403*83ee113eSDavid van Moolenbroek 
404*83ee113eSDavid van Moolenbroek #if SOCKDELETE
405*83ee113eSDavid van Moolenbroek 	/* remove isc socket associations */
406*83ee113eSDavid van Moolenbroek 	if (obj->fd != NULL) {
407*83ee113eSDavid van Moolenbroek 		isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task,
408*83ee113eSDavid van Moolenbroek 				  ISC_SOCKCANCEL_ALL);
409*83ee113eSDavid van Moolenbroek 		isc_socket_detach(&obj->fd);
410*83ee113eSDavid van Moolenbroek 	}
411*83ee113eSDavid van Moolenbroek #else
412*83ee113eSDavid van Moolenbroek 	obj->closed = ISC_TRUE;
413*83ee113eSDavid van Moolenbroek #endif
414*83ee113eSDavid van Moolenbroek 
415*83ee113eSDavid van Moolenbroek 	omapi_io_dereference (&ph, MDL);
416*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
417*83ee113eSDavid van Moolenbroek }
418*83ee113eSDavid van Moolenbroek 
omapi_dispatch(struct timeval * t)419*83ee113eSDavid van Moolenbroek isc_result_t omapi_dispatch (struct timeval *t)
420*83ee113eSDavid van Moolenbroek {
421*83ee113eSDavid van Moolenbroek 	return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
422*83ee113eSDavid van Moolenbroek 					  t);
423*83ee113eSDavid van Moolenbroek }
424*83ee113eSDavid van Moolenbroek 
omapi_wait_for_completion(omapi_object_t * object,struct timeval * t)425*83ee113eSDavid van Moolenbroek isc_result_t omapi_wait_for_completion (omapi_object_t *object,
426*83ee113eSDavid van Moolenbroek 					struct timeval *t)
427*83ee113eSDavid van Moolenbroek {
428*83ee113eSDavid van Moolenbroek 	isc_result_t status;
429*83ee113eSDavid van Moolenbroek 	omapi_waiter_object_t *waiter;
430*83ee113eSDavid van Moolenbroek 	omapi_object_t *inner;
431*83ee113eSDavid van Moolenbroek 
432*83ee113eSDavid van Moolenbroek 	if (object) {
433*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)0;
434*83ee113eSDavid van Moolenbroek 		status = omapi_waiter_allocate (&waiter, MDL);
435*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
436*83ee113eSDavid van Moolenbroek 			return status;
437*83ee113eSDavid van Moolenbroek 
438*83ee113eSDavid van Moolenbroek 		/* Paste the waiter object onto the inner object we're
439*83ee113eSDavid van Moolenbroek 		   waiting on. */
440*83ee113eSDavid van Moolenbroek 		for (inner = object; inner -> inner; inner = inner -> inner)
441*83ee113eSDavid van Moolenbroek 			;
442*83ee113eSDavid van Moolenbroek 
443*83ee113eSDavid van Moolenbroek 		status = omapi_object_reference (&waiter -> outer, inner, MDL);
444*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
445*83ee113eSDavid van Moolenbroek 			omapi_waiter_dereference (&waiter, MDL);
446*83ee113eSDavid van Moolenbroek 			return status;
447*83ee113eSDavid van Moolenbroek 		}
448*83ee113eSDavid van Moolenbroek 
449*83ee113eSDavid van Moolenbroek 		status = omapi_object_reference (&inner -> inner,
450*83ee113eSDavid van Moolenbroek 						 (omapi_object_t *)waiter,
451*83ee113eSDavid van Moolenbroek 						 MDL);
452*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
453*83ee113eSDavid van Moolenbroek 			omapi_waiter_dereference (&waiter, MDL);
454*83ee113eSDavid van Moolenbroek 			return status;
455*83ee113eSDavid van Moolenbroek 		}
456*83ee113eSDavid van Moolenbroek 	} else
457*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)0;
458*83ee113eSDavid van Moolenbroek 
459*83ee113eSDavid van Moolenbroek 	do {
460*83ee113eSDavid van Moolenbroek 		status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
461*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
462*83ee113eSDavid van Moolenbroek 			return status;
463*83ee113eSDavid van Moolenbroek 	} while (!waiter || !waiter -> ready);
464*83ee113eSDavid van Moolenbroek 
465*83ee113eSDavid van Moolenbroek 	if (waiter -> outer) {
466*83ee113eSDavid van Moolenbroek 		if (waiter -> outer -> inner) {
467*83ee113eSDavid van Moolenbroek 			omapi_object_dereference (&waiter -> outer -> inner,
468*83ee113eSDavid van Moolenbroek 						  MDL);
469*83ee113eSDavid van Moolenbroek 			if (waiter -> inner)
470*83ee113eSDavid van Moolenbroek 				omapi_object_reference
471*83ee113eSDavid van Moolenbroek 					(&waiter -> outer -> inner,
472*83ee113eSDavid van Moolenbroek 					 waiter -> inner, MDL);
473*83ee113eSDavid van Moolenbroek 		}
474*83ee113eSDavid van Moolenbroek 		omapi_object_dereference (&waiter -> outer, MDL);
475*83ee113eSDavid van Moolenbroek 	}
476*83ee113eSDavid van Moolenbroek 	if (waiter -> inner)
477*83ee113eSDavid van Moolenbroek 		omapi_object_dereference (&waiter -> inner, MDL);
478*83ee113eSDavid van Moolenbroek 
479*83ee113eSDavid van Moolenbroek 	status = waiter -> waitstatus;
480*83ee113eSDavid van Moolenbroek 	omapi_waiter_dereference (&waiter, MDL);
481*83ee113eSDavid van Moolenbroek 	return status;
482*83ee113eSDavid van Moolenbroek }
483*83ee113eSDavid van Moolenbroek 
omapi_one_dispatch(omapi_object_t * wo,struct timeval * t)484*83ee113eSDavid van Moolenbroek isc_result_t omapi_one_dispatch (omapi_object_t *wo,
485*83ee113eSDavid van Moolenbroek 				 struct timeval *t)
486*83ee113eSDavid van Moolenbroek {
487*83ee113eSDavid van Moolenbroek 	fd_set r, w, x, rr, ww, xx;
488*83ee113eSDavid van Moolenbroek 	int max = 0;
489*83ee113eSDavid van Moolenbroek 	int count;
490*83ee113eSDavid van Moolenbroek 	int desc;
491*83ee113eSDavid van Moolenbroek 	struct timeval now, to;
492*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *io, *prev, *next;
493*83ee113eSDavid van Moolenbroek 	omapi_waiter_object_t *waiter;
494*83ee113eSDavid van Moolenbroek 	omapi_object_t *tmp = (omapi_object_t *)0;
495*83ee113eSDavid van Moolenbroek 
496*83ee113eSDavid van Moolenbroek 	if (!wo || wo -> type != omapi_type_waiter)
497*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)0;
498*83ee113eSDavid van Moolenbroek 	else
499*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)wo;
500*83ee113eSDavid van Moolenbroek 
501*83ee113eSDavid van Moolenbroek 	FD_ZERO (&x);
502*83ee113eSDavid van Moolenbroek 
503*83ee113eSDavid van Moolenbroek 	/* First, see if the timeout has expired, and if so return. */
504*83ee113eSDavid van Moolenbroek 	if (t) {
505*83ee113eSDavid van Moolenbroek 		gettimeofday (&now, (struct timezone *)0);
506*83ee113eSDavid van Moolenbroek 		cur_tv.tv_sec = now.tv_sec;
507*83ee113eSDavid van Moolenbroek 		cur_tv.tv_usec = now.tv_usec;
508*83ee113eSDavid van Moolenbroek 		if (now.tv_sec > t -> tv_sec ||
509*83ee113eSDavid van Moolenbroek 		    (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
510*83ee113eSDavid van Moolenbroek 			return ISC_R_TIMEDOUT;
511*83ee113eSDavid van Moolenbroek 
512*83ee113eSDavid van Moolenbroek 		/* We didn't time out, so figure out how long until
513*83ee113eSDavid van Moolenbroek 		   we do. */
514*83ee113eSDavid van Moolenbroek 		to.tv_sec = t -> tv_sec - now.tv_sec;
515*83ee113eSDavid van Moolenbroek 		to.tv_usec = t -> tv_usec - now.tv_usec;
516*83ee113eSDavid van Moolenbroek 		if (to.tv_usec < 0) {
517*83ee113eSDavid van Moolenbroek 			to.tv_usec += 1000000;
518*83ee113eSDavid van Moolenbroek 			to.tv_sec--;
519*83ee113eSDavid van Moolenbroek 		}
520*83ee113eSDavid van Moolenbroek 
521*83ee113eSDavid van Moolenbroek 		/* It is possible for the timeout to get set larger than
522*83ee113eSDavid van Moolenbroek 		   the largest time select() is willing to accept.
523*83ee113eSDavid van Moolenbroek 		   Restricting the timeout to a maximum of one day should
524*83ee113eSDavid van Moolenbroek 		   work around this.  -DPN.  (Ref: Bug #416) */
525*83ee113eSDavid van Moolenbroek 		if (to.tv_sec > (60 * 60 * 24))
526*83ee113eSDavid van Moolenbroek 			to.tv_sec = 60 * 60 * 24;
527*83ee113eSDavid van Moolenbroek 	}
528*83ee113eSDavid van Moolenbroek 
529*83ee113eSDavid van Moolenbroek 	/* If the object we're waiting on has reached completion,
530*83ee113eSDavid van Moolenbroek 	   return now. */
531*83ee113eSDavid van Moolenbroek 	if (waiter && waiter -> ready)
532*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
533*83ee113eSDavid van Moolenbroek 
534*83ee113eSDavid van Moolenbroek       again:
535*83ee113eSDavid van Moolenbroek 	/* If we have no I/O state, we can't proceed. */
536*83ee113eSDavid van Moolenbroek 	if (!(io = omapi_io_states.next))
537*83ee113eSDavid van Moolenbroek 		return ISC_R_NOMORE;
538*83ee113eSDavid van Moolenbroek 
539*83ee113eSDavid van Moolenbroek 	/* Set up the read and write masks. */
540*83ee113eSDavid van Moolenbroek 	FD_ZERO (&r);
541*83ee113eSDavid van Moolenbroek 	FD_ZERO (&w);
542*83ee113eSDavid van Moolenbroek 
543*83ee113eSDavid van Moolenbroek 	for (; io; io = io -> next) {
544*83ee113eSDavid van Moolenbroek 		/* Check for a read socket.   If we shouldn't be
545*83ee113eSDavid van Moolenbroek 		   trying to read for this I/O object, either there
546*83ee113eSDavid van Moolenbroek 		   won't be a readfd function, or it'll return -1. */
547*83ee113eSDavid van Moolenbroek 		if (io -> readfd && io -> inner &&
548*83ee113eSDavid van Moolenbroek 		    (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
549*83ee113eSDavid van Moolenbroek 			FD_SET (desc, &r);
550*83ee113eSDavid van Moolenbroek 			if (desc > max)
551*83ee113eSDavid van Moolenbroek 				max = desc;
552*83ee113eSDavid van Moolenbroek 		}
553*83ee113eSDavid van Moolenbroek 
554*83ee113eSDavid van Moolenbroek 		/* Same deal for write fdets. */
555*83ee113eSDavid van Moolenbroek 		if (io -> writefd && io -> inner &&
556*83ee113eSDavid van Moolenbroek 		    (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
557*83ee113eSDavid van Moolenbroek 			FD_SET (desc, &w);
558*83ee113eSDavid van Moolenbroek 			if (desc > max)
559*83ee113eSDavid van Moolenbroek 				max = desc;
560*83ee113eSDavid van Moolenbroek 		}
561*83ee113eSDavid van Moolenbroek 	}
562*83ee113eSDavid van Moolenbroek 
563*83ee113eSDavid van Moolenbroek 	/* poll if all reader are dry */
564*83ee113eSDavid van Moolenbroek 	now.tv_sec = 0;
565*83ee113eSDavid van Moolenbroek 	now.tv_usec = 0;
566*83ee113eSDavid van Moolenbroek 	rr=r;
567*83ee113eSDavid van Moolenbroek 	ww=w;
568*83ee113eSDavid van Moolenbroek 	xx=x;
569*83ee113eSDavid van Moolenbroek 
570*83ee113eSDavid van Moolenbroek 	/* poll once */
571*83ee113eSDavid van Moolenbroek 	count = select(max + 1, &r, &w, &x, &now);
572*83ee113eSDavid van Moolenbroek 	if (!count) {
573*83ee113eSDavid van Moolenbroek 		/* We are dry now */
574*83ee113eSDavid van Moolenbroek 		trigger_event(&rw_queue_empty);
575*83ee113eSDavid van Moolenbroek 		/* Wait for a packet or a timeout... XXX */
576*83ee113eSDavid van Moolenbroek 		r = rr;
577*83ee113eSDavid van Moolenbroek 		w = ww;
578*83ee113eSDavid van Moolenbroek 		x = xx;
579*83ee113eSDavid van Moolenbroek 		count = select(max + 1, &r, &w, &x, t ? &to : NULL);
580*83ee113eSDavid van Moolenbroek 	}
581*83ee113eSDavid van Moolenbroek 
582*83ee113eSDavid van Moolenbroek 	/* Get the current time... */
583*83ee113eSDavid van Moolenbroek 	gettimeofday (&cur_tv, (struct timezone *)0);
584*83ee113eSDavid van Moolenbroek 
585*83ee113eSDavid van Moolenbroek 	/* We probably have a bad file descriptor.   Figure out which one.
586*83ee113eSDavid van Moolenbroek 	   When we find it, call the reaper function on it, which will
587*83ee113eSDavid van Moolenbroek 	   maybe make it go away, and then try again. */
588*83ee113eSDavid van Moolenbroek 	if (count < 0) {
589*83ee113eSDavid van Moolenbroek 		struct timeval t0;
590*83ee113eSDavid van Moolenbroek 		omapi_io_object_t *prev = (omapi_io_object_t *)0;
591*83ee113eSDavid van Moolenbroek 		io = (omapi_io_object_t *)0;
592*83ee113eSDavid van Moolenbroek 		if (omapi_io_states.next)
593*83ee113eSDavid van Moolenbroek 			omapi_io_reference (&io, omapi_io_states.next, MDL);
594*83ee113eSDavid van Moolenbroek 
595*83ee113eSDavid van Moolenbroek 		while (io) {
596*83ee113eSDavid van Moolenbroek 			omapi_object_t *obj;
597*83ee113eSDavid van Moolenbroek 			FD_ZERO (&r);
598*83ee113eSDavid van Moolenbroek 			FD_ZERO (&w);
599*83ee113eSDavid van Moolenbroek 			t0.tv_sec = t0.tv_usec = 0;
600*83ee113eSDavid van Moolenbroek 
601*83ee113eSDavid van Moolenbroek 			if (io -> readfd && io -> inner &&
602*83ee113eSDavid van Moolenbroek 			    (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
603*83ee113eSDavid van Moolenbroek 			    FD_SET (desc, &r);
604*83ee113eSDavid van Moolenbroek 			    count = select (desc + 1, &r, &w, &x, &t0);
605*83ee113eSDavid van Moolenbroek 			   bogon:
606*83ee113eSDavid van Moolenbroek 			    if (count < 0) {
607*83ee113eSDavid van Moolenbroek 				log_error ("Bad descriptor %d.", desc);
608*83ee113eSDavid van Moolenbroek 				for (obj = (omapi_object_t *)io;
609*83ee113eSDavid van Moolenbroek 				     obj -> outer;
610*83ee113eSDavid van Moolenbroek 				     obj = obj -> outer)
611*83ee113eSDavid van Moolenbroek 					;
612*83ee113eSDavid van Moolenbroek 				for (; obj; obj = obj -> inner) {
613*83ee113eSDavid van Moolenbroek 				    omapi_value_t *ov;
614*83ee113eSDavid van Moolenbroek 				    int len;
615*83ee113eSDavid van Moolenbroek 				    const char *s;
616*83ee113eSDavid van Moolenbroek 				    ov = (omapi_value_t *)0;
617*83ee113eSDavid van Moolenbroek 				    omapi_get_value_str (obj,
618*83ee113eSDavid van Moolenbroek 							 (omapi_object_t *)0,
619*83ee113eSDavid van Moolenbroek 							 "name", &ov);
620*83ee113eSDavid van Moolenbroek 				    if (ov && ov -> value &&
621*83ee113eSDavid van Moolenbroek 					(ov -> value -> type ==
622*83ee113eSDavid van Moolenbroek 					 omapi_datatype_string)) {
623*83ee113eSDavid van Moolenbroek 					s = (char *)
624*83ee113eSDavid van Moolenbroek 						ov -> value -> u.buffer.value;
625*83ee113eSDavid van Moolenbroek 					len = ov -> value -> u.buffer.len;
626*83ee113eSDavid van Moolenbroek 				    } else {
627*83ee113eSDavid van Moolenbroek 					s = "";
628*83ee113eSDavid van Moolenbroek 					len = 0;
629*83ee113eSDavid van Moolenbroek 				    }
630*83ee113eSDavid van Moolenbroek 				    log_error ("Object %lx %s%s%.*s",
631*83ee113eSDavid van Moolenbroek 					       (unsigned long)obj,
632*83ee113eSDavid van Moolenbroek 					       obj -> type -> name,
633*83ee113eSDavid van Moolenbroek 					       len ? " " : "",
634*83ee113eSDavid van Moolenbroek 					       len, s);
635*83ee113eSDavid van Moolenbroek 				    if (len)
636*83ee113eSDavid van Moolenbroek 					omapi_value_dereference (&ov, MDL);
637*83ee113eSDavid van Moolenbroek 				}
638*83ee113eSDavid van Moolenbroek 				(*(io -> reaper)) (io -> inner);
639*83ee113eSDavid van Moolenbroek 				if (prev) {
640*83ee113eSDavid van Moolenbroek 				    omapi_io_dereference (&prev -> next, MDL);
641*83ee113eSDavid van Moolenbroek 				    if (io -> next)
642*83ee113eSDavid van Moolenbroek 					omapi_io_reference (&prev -> next,
643*83ee113eSDavid van Moolenbroek 							    io -> next, MDL);
644*83ee113eSDavid van Moolenbroek 				} else {
645*83ee113eSDavid van Moolenbroek 				    omapi_io_dereference
646*83ee113eSDavid van Moolenbroek 					    (&omapi_io_states.next, MDL);
647*83ee113eSDavid van Moolenbroek 				    if (io -> next)
648*83ee113eSDavid van Moolenbroek 					omapi_io_reference
649*83ee113eSDavid van Moolenbroek 						(&omapi_io_states.next,
650*83ee113eSDavid van Moolenbroek 						 io -> next, MDL);
651*83ee113eSDavid van Moolenbroek 				}
652*83ee113eSDavid van Moolenbroek 				omapi_io_dereference (&io, MDL);
653*83ee113eSDavid van Moolenbroek 				goto again;
654*83ee113eSDavid van Moolenbroek 			    }
655*83ee113eSDavid van Moolenbroek 			}
656*83ee113eSDavid van Moolenbroek 
657*83ee113eSDavid van Moolenbroek 			FD_ZERO (&r);
658*83ee113eSDavid van Moolenbroek 			FD_ZERO (&w);
659*83ee113eSDavid van Moolenbroek 			t0.tv_sec = t0.tv_usec = 0;
660*83ee113eSDavid van Moolenbroek 
661*83ee113eSDavid van Moolenbroek 			/* Same deal for write fdets. */
662*83ee113eSDavid van Moolenbroek 			if (io -> writefd && io -> inner &&
663*83ee113eSDavid van Moolenbroek 			    (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
664*83ee113eSDavid van Moolenbroek 				FD_SET (desc, &w);
665*83ee113eSDavid van Moolenbroek 				count = select (desc + 1, &r, &w, &x, &t0);
666*83ee113eSDavid van Moolenbroek 				if (count < 0)
667*83ee113eSDavid van Moolenbroek 					goto bogon;
668*83ee113eSDavid van Moolenbroek 			}
669*83ee113eSDavid van Moolenbroek 			if (prev)
670*83ee113eSDavid van Moolenbroek 				omapi_io_dereference (&prev, MDL);
671*83ee113eSDavid van Moolenbroek 			omapi_io_reference (&prev, io, MDL);
672*83ee113eSDavid van Moolenbroek 			omapi_io_dereference (&io, MDL);
673*83ee113eSDavid van Moolenbroek 			if (prev -> next)
674*83ee113eSDavid van Moolenbroek 			    omapi_io_reference (&io, prev -> next, MDL);
675*83ee113eSDavid van Moolenbroek 		}
676*83ee113eSDavid van Moolenbroek 		if (prev)
677*83ee113eSDavid van Moolenbroek 			omapi_io_dereference (&prev, MDL);
678*83ee113eSDavid van Moolenbroek 
679*83ee113eSDavid van Moolenbroek 	}
680*83ee113eSDavid van Moolenbroek 
681*83ee113eSDavid van Moolenbroek 	for (io = omapi_io_states.next; io; io = io -> next) {
682*83ee113eSDavid van Moolenbroek 		if (!io -> inner)
683*83ee113eSDavid van Moolenbroek 			continue;
684*83ee113eSDavid van Moolenbroek 		omapi_object_reference (&tmp, io -> inner, MDL);
685*83ee113eSDavid van Moolenbroek 		/* Check for a read descriptor, and if there is one,
686*83ee113eSDavid van Moolenbroek 		   see if we got input on that socket. */
687*83ee113eSDavid van Moolenbroek 		if (io -> readfd &&
688*83ee113eSDavid van Moolenbroek 		    (desc = (*(io -> readfd)) (tmp)) >= 0) {
689*83ee113eSDavid van Moolenbroek 			if (FD_ISSET (desc, &r))
690*83ee113eSDavid van Moolenbroek 				((*(io -> reader)) (tmp));
691*83ee113eSDavid van Moolenbroek 		}
692*83ee113eSDavid van Moolenbroek 
693*83ee113eSDavid van Moolenbroek 		/* Same deal for write descriptors. */
694*83ee113eSDavid van Moolenbroek 		if (io -> writefd &&
695*83ee113eSDavid van Moolenbroek 		    (desc = (*(io -> writefd)) (tmp)) >= 0)
696*83ee113eSDavid van Moolenbroek 		{
697*83ee113eSDavid van Moolenbroek 			if (FD_ISSET (desc, &w))
698*83ee113eSDavid van Moolenbroek 				((*(io -> writer)) (tmp));
699*83ee113eSDavid van Moolenbroek 		}
700*83ee113eSDavid van Moolenbroek 		omapi_object_dereference (&tmp, MDL);
701*83ee113eSDavid van Moolenbroek 	}
702*83ee113eSDavid van Moolenbroek 
703*83ee113eSDavid van Moolenbroek 	/* Now check for I/O handles that are no longer valid,
704*83ee113eSDavid van Moolenbroek 	   and remove them from the list. */
705*83ee113eSDavid van Moolenbroek 	prev = NULL;
706*83ee113eSDavid van Moolenbroek 	io = NULL;
707*83ee113eSDavid van Moolenbroek 	if (omapi_io_states.next != NULL) {
708*83ee113eSDavid van Moolenbroek 		omapi_io_reference(&io, omapi_io_states.next, MDL);
709*83ee113eSDavid van Moolenbroek 	}
710*83ee113eSDavid van Moolenbroek 	while (io != NULL) {
711*83ee113eSDavid van Moolenbroek 		if ((io->inner == NULL) ||
712*83ee113eSDavid van Moolenbroek 		    ((io->reaper != NULL) &&
713*83ee113eSDavid van Moolenbroek 		     ((io->reaper)(io->inner) != ISC_R_SUCCESS)))
714*83ee113eSDavid van Moolenbroek 		{
715*83ee113eSDavid van Moolenbroek 
716*83ee113eSDavid van Moolenbroek 			omapi_io_object_t *tmp = NULL;
717*83ee113eSDavid van Moolenbroek 			/* Save a reference to the next
718*83ee113eSDavid van Moolenbroek 			   pointer, if there is one. */
719*83ee113eSDavid van Moolenbroek 			if (io->next != NULL) {
720*83ee113eSDavid van Moolenbroek 				omapi_io_reference(&tmp, io->next, MDL);
721*83ee113eSDavid van Moolenbroek 				omapi_io_dereference(&io->next, MDL);
722*83ee113eSDavid van Moolenbroek 			}
723*83ee113eSDavid van Moolenbroek 			if (prev != NULL) {
724*83ee113eSDavid van Moolenbroek 				omapi_io_dereference(&prev->next, MDL);
725*83ee113eSDavid van Moolenbroek 				if (tmp != NULL)
726*83ee113eSDavid van Moolenbroek 					omapi_io_reference(&prev->next,
727*83ee113eSDavid van Moolenbroek 							   tmp, MDL);
728*83ee113eSDavid van Moolenbroek 			} else {
729*83ee113eSDavid van Moolenbroek 				omapi_io_dereference(&omapi_io_states.next,
730*83ee113eSDavid van Moolenbroek 						     MDL);
731*83ee113eSDavid van Moolenbroek 				if (tmp != NULL)
732*83ee113eSDavid van Moolenbroek 					omapi_io_reference
733*83ee113eSDavid van Moolenbroek 					    (&omapi_io_states.next,
734*83ee113eSDavid van Moolenbroek 					     tmp, MDL);
735*83ee113eSDavid van Moolenbroek 				else
736*83ee113eSDavid van Moolenbroek 					omapi_signal_in(
737*83ee113eSDavid van Moolenbroek 							(omapi_object_t *)
738*83ee113eSDavid van Moolenbroek 						 	&omapi_io_states,
739*83ee113eSDavid van Moolenbroek 							"ready");
740*83ee113eSDavid van Moolenbroek 			}
741*83ee113eSDavid van Moolenbroek 			if (tmp != NULL)
742*83ee113eSDavid van Moolenbroek 				omapi_io_dereference(&tmp, MDL);
743*83ee113eSDavid van Moolenbroek 
744*83ee113eSDavid van Moolenbroek 		} else {
745*83ee113eSDavid van Moolenbroek 
746*83ee113eSDavid van Moolenbroek 			if (prev != NULL) {
747*83ee113eSDavid van Moolenbroek 				omapi_io_dereference(&prev, MDL);
748*83ee113eSDavid van Moolenbroek 			}
749*83ee113eSDavid van Moolenbroek 			omapi_io_reference(&prev, io, MDL);
750*83ee113eSDavid van Moolenbroek 		}
751*83ee113eSDavid van Moolenbroek 
752*83ee113eSDavid van Moolenbroek 		/*
753*83ee113eSDavid van Moolenbroek 		 * Equivalent to:
754*83ee113eSDavid van Moolenbroek 		 *   io = io->next
755*83ee113eSDavid van Moolenbroek 		 * But using our reference counting voodoo.
756*83ee113eSDavid van Moolenbroek 		 */
757*83ee113eSDavid van Moolenbroek 		next = NULL;
758*83ee113eSDavid van Moolenbroek 		if (io->next != NULL) {
759*83ee113eSDavid van Moolenbroek 			omapi_io_reference(&next, io->next, MDL);
760*83ee113eSDavid van Moolenbroek 		}
761*83ee113eSDavid van Moolenbroek 		omapi_io_dereference(&io, MDL);
762*83ee113eSDavid van Moolenbroek 		if (next != NULL) {
763*83ee113eSDavid van Moolenbroek 			omapi_io_reference(&io, next, MDL);
764*83ee113eSDavid van Moolenbroek 			omapi_io_dereference(&next, MDL);
765*83ee113eSDavid van Moolenbroek 		}
766*83ee113eSDavid van Moolenbroek 	}
767*83ee113eSDavid van Moolenbroek 	if (prev != NULL) {
768*83ee113eSDavid van Moolenbroek 		omapi_io_dereference(&prev, MDL);
769*83ee113eSDavid van Moolenbroek 	}
770*83ee113eSDavid van Moolenbroek 
771*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
772*83ee113eSDavid van Moolenbroek }
773*83ee113eSDavid van Moolenbroek 
omapi_io_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)774*83ee113eSDavid van Moolenbroek isc_result_t omapi_io_set_value (omapi_object_t *h,
775*83ee113eSDavid van Moolenbroek 				 omapi_object_t *id,
776*83ee113eSDavid van Moolenbroek 				 omapi_data_string_t *name,
777*83ee113eSDavid van Moolenbroek 				 omapi_typed_data_t *value)
778*83ee113eSDavid van Moolenbroek {
779*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_io_object)
780*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
781*83ee113eSDavid van Moolenbroek 
782*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> set_value)
783*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> set_value))
784*83ee113eSDavid van Moolenbroek 			(h -> inner, id, name, value);
785*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
786*83ee113eSDavid van Moolenbroek }
787*83ee113eSDavid van Moolenbroek 
omapi_io_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)788*83ee113eSDavid van Moolenbroek isc_result_t omapi_io_get_value (omapi_object_t *h,
789*83ee113eSDavid van Moolenbroek 				 omapi_object_t *id,
790*83ee113eSDavid van Moolenbroek 				 omapi_data_string_t *name,
791*83ee113eSDavid van Moolenbroek 				 omapi_value_t **value)
792*83ee113eSDavid van Moolenbroek {
793*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_io_object)
794*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
795*83ee113eSDavid van Moolenbroek 
796*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> get_value)
797*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> get_value))
798*83ee113eSDavid van Moolenbroek 			(h -> inner, id, name, value);
799*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
800*83ee113eSDavid van Moolenbroek }
801*83ee113eSDavid van Moolenbroek 
802*83ee113eSDavid van Moolenbroek /* omapi_io_destroy (object, MDL);
803*83ee113eSDavid van Moolenbroek  *
804*83ee113eSDavid van Moolenbroek  *	Find the requested IO [object] and remove it from the list of io
805*83ee113eSDavid van Moolenbroek  * states, causing the cleanup functions to destroy it.  Note that we must
806*83ee113eSDavid van Moolenbroek  * hold a reference on the object while moving its ->next reference and
807*83ee113eSDavid van Moolenbroek  * removing the reference in the chain to the target object...otherwise it
808*83ee113eSDavid van Moolenbroek  * may be cleaned up from under us.
809*83ee113eSDavid van Moolenbroek  */
omapi_io_destroy(omapi_object_t * h,const char * file,int line)810*83ee113eSDavid van Moolenbroek isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
811*83ee113eSDavid van Moolenbroek {
812*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder;
813*83ee113eSDavid van Moolenbroek 
814*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_io_object)
815*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
816*83ee113eSDavid van Moolenbroek 
817*83ee113eSDavid van Moolenbroek 	/* remove from the list of I/O states */
818*83ee113eSDavid van Moolenbroek 	for (p = omapi_io_states.next; p; p = p -> next) {
819*83ee113eSDavid van Moolenbroek 		if (p == (omapi_io_object_t *)h) {
820*83ee113eSDavid van Moolenbroek 			omapi_io_reference (&obj, p, MDL);
821*83ee113eSDavid van Moolenbroek 
822*83ee113eSDavid van Moolenbroek 			if (last)
823*83ee113eSDavid van Moolenbroek 				holder = &last -> next;
824*83ee113eSDavid van Moolenbroek 			else
825*83ee113eSDavid van Moolenbroek 				holder = &omapi_io_states.next;
826*83ee113eSDavid van Moolenbroek 
827*83ee113eSDavid van Moolenbroek 			omapi_io_dereference (holder, MDL);
828*83ee113eSDavid van Moolenbroek 
829*83ee113eSDavid van Moolenbroek 			if (obj -> next) {
830*83ee113eSDavid van Moolenbroek 				omapi_io_reference (holder, obj -> next, MDL);
831*83ee113eSDavid van Moolenbroek 				omapi_io_dereference (&obj -> next, MDL);
832*83ee113eSDavid van Moolenbroek 			}
833*83ee113eSDavid van Moolenbroek 
834*83ee113eSDavid van Moolenbroek 			return omapi_io_dereference (&obj, MDL);
835*83ee113eSDavid van Moolenbroek 		}
836*83ee113eSDavid van Moolenbroek 		last = p;
837*83ee113eSDavid van Moolenbroek 	}
838*83ee113eSDavid van Moolenbroek 
839*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
840*83ee113eSDavid van Moolenbroek }
841*83ee113eSDavid van Moolenbroek 
omapi_io_signal_handler(omapi_object_t * h,const char * name,va_list ap)842*83ee113eSDavid van Moolenbroek isc_result_t omapi_io_signal_handler (omapi_object_t *h,
843*83ee113eSDavid van Moolenbroek 				      const char *name, va_list ap)
844*83ee113eSDavid van Moolenbroek {
845*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_io_object)
846*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
847*83ee113eSDavid van Moolenbroek 
848*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> signal_handler)
849*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> signal_handler)) (h -> inner,
850*83ee113eSDavid van Moolenbroek 								  name, ap);
851*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
852*83ee113eSDavid van Moolenbroek }
853*83ee113eSDavid van Moolenbroek 
omapi_io_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * i)854*83ee113eSDavid van Moolenbroek isc_result_t omapi_io_stuff_values (omapi_object_t *c,
855*83ee113eSDavid van Moolenbroek 				    omapi_object_t *id,
856*83ee113eSDavid van Moolenbroek 				    omapi_object_t *i)
857*83ee113eSDavid van Moolenbroek {
858*83ee113eSDavid van Moolenbroek 	if (i -> type != omapi_type_io_object)
859*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
860*83ee113eSDavid van Moolenbroek 
861*83ee113eSDavid van Moolenbroek 	if (i -> inner && i -> inner -> type -> stuff_values)
862*83ee113eSDavid van Moolenbroek 		return (*(i -> inner -> type -> stuff_values)) (c, id,
863*83ee113eSDavid van Moolenbroek 								i -> inner);
864*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
865*83ee113eSDavid van Moolenbroek }
866*83ee113eSDavid van Moolenbroek 
omapi_waiter_signal_handler(omapi_object_t * h,const char * name,va_list ap)867*83ee113eSDavid van Moolenbroek isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
868*83ee113eSDavid van Moolenbroek 					  const char *name, va_list ap)
869*83ee113eSDavid van Moolenbroek {
870*83ee113eSDavid van Moolenbroek 	omapi_waiter_object_t *waiter;
871*83ee113eSDavid van Moolenbroek 
872*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_waiter)
873*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
874*83ee113eSDavid van Moolenbroek 
875*83ee113eSDavid van Moolenbroek 	if (!strcmp (name, "ready")) {
876*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)h;
877*83ee113eSDavid van Moolenbroek 		waiter -> ready = 1;
878*83ee113eSDavid van Moolenbroek 		waiter -> waitstatus = ISC_R_SUCCESS;
879*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
880*83ee113eSDavid van Moolenbroek 	}
881*83ee113eSDavid van Moolenbroek 
882*83ee113eSDavid van Moolenbroek 	if (!strcmp(name, "status")) {
883*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)h;
884*83ee113eSDavid van Moolenbroek 		waiter->ready = 1;
885*83ee113eSDavid van Moolenbroek 		waiter->waitstatus = va_arg(ap, isc_result_t);
886*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
887*83ee113eSDavid van Moolenbroek 	}
888*83ee113eSDavid van Moolenbroek 
889*83ee113eSDavid van Moolenbroek 	if (!strcmp (name, "disconnect")) {
890*83ee113eSDavid van Moolenbroek 		waiter = (omapi_waiter_object_t *)h;
891*83ee113eSDavid van Moolenbroek 		waiter -> ready = 1;
892*83ee113eSDavid van Moolenbroek 		waiter -> waitstatus = DHCP_R_CONNRESET;
893*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
894*83ee113eSDavid van Moolenbroek 	}
895*83ee113eSDavid van Moolenbroek 
896*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> signal_handler)
897*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> signal_handler)) (h -> inner,
898*83ee113eSDavid van Moolenbroek 								  name, ap);
899*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
900*83ee113eSDavid van Moolenbroek }
901*83ee113eSDavid van Moolenbroek 
902*83ee113eSDavid van Moolenbroek /** @brief calls a given function on every object
903*83ee113eSDavid van Moolenbroek  *
904*83ee113eSDavid van Moolenbroek  * @param func function to be called
905*83ee113eSDavid van Moolenbroek  * @param p parameter to be passed to each function instance
906*83ee113eSDavid van Moolenbroek  *
907*83ee113eSDavid van Moolenbroek  * @return result (ISC_R_SUCCESS if successful, error code otherwise)
908*83ee113eSDavid van Moolenbroek  */
omapi_io_state_foreach(isc_result_t (* func)(omapi_object_t *,void *),void * p)909*83ee113eSDavid van Moolenbroek isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
910*83ee113eSDavid van Moolenbroek 							   void *),
911*83ee113eSDavid van Moolenbroek 				     void *p)
912*83ee113eSDavid van Moolenbroek {
913*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *io = NULL;
914*83ee113eSDavid van Moolenbroek 	isc_result_t status;
915*83ee113eSDavid van Moolenbroek 	omapi_io_object_t *next = NULL;
916*83ee113eSDavid van Moolenbroek 
917*83ee113eSDavid van Moolenbroek 	/*
918*83ee113eSDavid van Moolenbroek 	 * This just calls func on every inner object on the list. It would
919*83ee113eSDavid van Moolenbroek 	 * be much simpler in general case, but one of the operations could be
920*83ee113eSDavid van Moolenbroek 	 * release of the objects. Therefore we need to ref count the io and
921*83ee113eSDavid van Moolenbroek 	 * io->next pointers.
922*83ee113eSDavid van Moolenbroek 	 */
923*83ee113eSDavid van Moolenbroek 
924*83ee113eSDavid van Moolenbroek 	if (omapi_io_states.next) {
925*83ee113eSDavid van Moolenbroek 		omapi_object_reference((omapi_object_t**)&io,
926*83ee113eSDavid van Moolenbroek 				       (omapi_object_t*)omapi_io_states.next,
927*83ee113eSDavid van Moolenbroek 				       MDL);
928*83ee113eSDavid van Moolenbroek 	}
929*83ee113eSDavid van Moolenbroek 
930*83ee113eSDavid van Moolenbroek 	while(io) {
931*83ee113eSDavid van Moolenbroek 	    /* If there's a next object, save it */
932*83ee113eSDavid van Moolenbroek 	    if (io->next) {
933*83ee113eSDavid van Moolenbroek 		omapi_object_reference((omapi_object_t**)&next,
934*83ee113eSDavid van Moolenbroek 				       (omapi_object_t*)io->next, MDL);
935*83ee113eSDavid van Moolenbroek 	    }
936*83ee113eSDavid van Moolenbroek 	    if (io->inner) {
937*83ee113eSDavid van Moolenbroek 		status = (*func) (io->inner, p);
938*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
939*83ee113eSDavid van Moolenbroek 		    /* Something went wrong. Let's stop using io & next pointer
940*83ee113eSDavid van Moolenbroek 		     * and bail out */
941*83ee113eSDavid van Moolenbroek 		    omapi_object_dereference((omapi_object_t**)&io, MDL);
942*83ee113eSDavid van Moolenbroek 		    if (next) {
943*83ee113eSDavid van Moolenbroek 			omapi_object_dereference((omapi_object_t**)&next, MDL);
944*83ee113eSDavid van Moolenbroek 		    }
945*83ee113eSDavid van Moolenbroek 		    return status;
946*83ee113eSDavid van Moolenbroek 		}
947*83ee113eSDavid van Moolenbroek 	    }
948*83ee113eSDavid van Moolenbroek 	    /* Update the io pointer and free the next pointer */
949*83ee113eSDavid van Moolenbroek 	    omapi_object_dereference((omapi_object_t**)&io, MDL);
950*83ee113eSDavid van Moolenbroek 	    if (next) {
951*83ee113eSDavid van Moolenbroek 		omapi_object_reference((omapi_object_t**)&io,
952*83ee113eSDavid van Moolenbroek 				       (omapi_object_t*)next,
953*83ee113eSDavid van Moolenbroek 				       MDL);
954*83ee113eSDavid van Moolenbroek 		omapi_object_dereference((omapi_object_t**)&next, MDL);
955*83ee113eSDavid van Moolenbroek 	    }
956*83ee113eSDavid van Moolenbroek 	}
957*83ee113eSDavid van Moolenbroek 
958*83ee113eSDavid van Moolenbroek 	/*
959*83ee113eSDavid van Moolenbroek 	 * The only way to get here is when next is NULL. There's no need
960*83ee113eSDavid van Moolenbroek 	 * to dereference it.
961*83ee113eSDavid van Moolenbroek 	 */
962*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
963*83ee113eSDavid van Moolenbroek }
964