xref: /minix3/external/bsd/dhcp/dist/omapip/connection.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: connection.c,v 1.1.1.3 2014/07/12 11:57:58 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* connection.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    Subroutines for dealing with connections. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
9*83ee113eSDavid van Moolenbroek  * Copyright (c) 1999-2003 by Internet Software Consortium
10*83ee113eSDavid van Moolenbroek  *
11*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
12*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
13*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
14*83ee113eSDavid van Moolenbroek  *
15*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22*83ee113eSDavid van Moolenbroek  *
23*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
24*83ee113eSDavid van Moolenbroek  *   950 Charter Street
25*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
26*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
27*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
28*83ee113eSDavid van Moolenbroek  *
29*83ee113eSDavid van Moolenbroek  */
30*83ee113eSDavid van Moolenbroek 
31*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
32*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: connection.c,v 1.1.1.3 2014/07/12 11:57:58 spz Exp $");
33*83ee113eSDavid van Moolenbroek 
34*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
35*83ee113eSDavid van Moolenbroek 
36*83ee113eSDavid van Moolenbroek #include <omapip/omapip_p.h>
37*83ee113eSDavid van Moolenbroek #include <arpa/inet.h>
38*83ee113eSDavid van Moolenbroek #include <arpa/nameser.h>
39*83ee113eSDavid van Moolenbroek #include <errno.h>
40*83ee113eSDavid van Moolenbroek 
41*83ee113eSDavid van Moolenbroek #if defined (TRACING)
42*83ee113eSDavid van Moolenbroek static void trace_connect_input (trace_type_t *, unsigned, char *);
43*83ee113eSDavid van Moolenbroek static void trace_connect_stop (trace_type_t *);
44*83ee113eSDavid van Moolenbroek static void trace_disconnect_input (trace_type_t *, unsigned, char *);
45*83ee113eSDavid van Moolenbroek static void trace_disconnect_stop (trace_type_t *);
46*83ee113eSDavid van Moolenbroek trace_type_t *trace_connect;
47*83ee113eSDavid van Moolenbroek trace_type_t *trace_disconnect;
48*83ee113eSDavid van Moolenbroek extern omapi_array_t *trace_listeners;
49*83ee113eSDavid van Moolenbroek #endif
50*83ee113eSDavid van Moolenbroek static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
51*83ee113eSDavid van Moolenbroek 
OMAPI_OBJECT_ALLOC(omapi_connection,omapi_connection_object_t,omapi_type_connection)52*83ee113eSDavid van Moolenbroek OMAPI_OBJECT_ALLOC (omapi_connection,
53*83ee113eSDavid van Moolenbroek 		    omapi_connection_object_t, omapi_type_connection)
54*83ee113eSDavid van Moolenbroek 
55*83ee113eSDavid van Moolenbroek isc_result_t omapi_connect (omapi_object_t *c,
56*83ee113eSDavid van Moolenbroek 			    const char *server_name,
57*83ee113eSDavid van Moolenbroek 			    unsigned port)
58*83ee113eSDavid van Moolenbroek {
59*83ee113eSDavid van Moolenbroek 	struct hostent *he;
60*83ee113eSDavid van Moolenbroek 	unsigned i, hix;
61*83ee113eSDavid van Moolenbroek 	omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
62*83ee113eSDavid van Moolenbroek 	struct in_addr foo;
63*83ee113eSDavid van Moolenbroek 	isc_result_t status;
64*83ee113eSDavid van Moolenbroek 
65*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PROTOCOL
66*83ee113eSDavid van Moolenbroek 	log_debug ("omapi_connect(%s, port=%d)", server_name, port);
67*83ee113eSDavid van Moolenbroek #endif
68*83ee113eSDavid van Moolenbroek 
69*83ee113eSDavid van Moolenbroek 	if (!inet_aton (server_name, &foo)) {
70*83ee113eSDavid van Moolenbroek 		/* If we didn't get a numeric address, try for a domain
71*83ee113eSDavid van Moolenbroek 		   name.  It's okay for this call to block. */
72*83ee113eSDavid van Moolenbroek 		he = gethostbyname (server_name);
73*83ee113eSDavid van Moolenbroek 		if (!he)
74*83ee113eSDavid van Moolenbroek 			return DHCP_R_HOSTUNKNOWN;
75*83ee113eSDavid van Moolenbroek 		for (i = 0; he -> h_addr_list [i]; i++)
76*83ee113eSDavid van Moolenbroek 			;
77*83ee113eSDavid van Moolenbroek 		if (i == 0)
78*83ee113eSDavid van Moolenbroek 			return DHCP_R_HOSTUNKNOWN;
79*83ee113eSDavid van Moolenbroek 		hix = i;
80*83ee113eSDavid van Moolenbroek 
81*83ee113eSDavid van Moolenbroek 		status = omapi_addr_list_new (&addrs, hix, MDL);
82*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
83*83ee113eSDavid van Moolenbroek 			return status;
84*83ee113eSDavid van Moolenbroek 		for (i = 0; i < hix; i++) {
85*83ee113eSDavid van Moolenbroek 			addrs -> addresses [i].addrtype = he -> h_addrtype;
86*83ee113eSDavid van Moolenbroek 			addrs -> addresses [i].addrlen = he -> h_length;
87*83ee113eSDavid van Moolenbroek 			memcpy (addrs -> addresses [i].address,
88*83ee113eSDavid van Moolenbroek 				he -> h_addr_list [i],
89*83ee113eSDavid van Moolenbroek 				(unsigned)he -> h_length);
90*83ee113eSDavid van Moolenbroek 			addrs -> addresses [i].port = port;
91*83ee113eSDavid van Moolenbroek 		}
92*83ee113eSDavid van Moolenbroek 	} else {
93*83ee113eSDavid van Moolenbroek 		status = omapi_addr_list_new (&addrs, 1, MDL);
94*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
95*83ee113eSDavid van Moolenbroek 			return status;
96*83ee113eSDavid van Moolenbroek 		addrs -> addresses [0].addrtype = AF_INET;
97*83ee113eSDavid van Moolenbroek 		addrs -> addresses [0].addrlen = sizeof foo;
98*83ee113eSDavid van Moolenbroek 		memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
99*83ee113eSDavid van Moolenbroek 		addrs -> addresses [0].port = port;
100*83ee113eSDavid van Moolenbroek 	}
101*83ee113eSDavid van Moolenbroek 	status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
102*83ee113eSDavid van Moolenbroek 	omapi_addr_list_dereference (&addrs, MDL);
103*83ee113eSDavid van Moolenbroek 	return status;
104*83ee113eSDavid van Moolenbroek }
105*83ee113eSDavid van Moolenbroek 
omapi_connect_list(omapi_object_t * c,omapi_addr_list_t * remote_addrs,omapi_addr_t * local_addr)106*83ee113eSDavid van Moolenbroek isc_result_t omapi_connect_list (omapi_object_t *c,
107*83ee113eSDavid van Moolenbroek 				 omapi_addr_list_t *remote_addrs,
108*83ee113eSDavid van Moolenbroek 				 omapi_addr_t *local_addr)
109*83ee113eSDavid van Moolenbroek {
110*83ee113eSDavid van Moolenbroek 	isc_result_t status;
111*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *obj;
112*83ee113eSDavid van Moolenbroek 	int flag;
113*83ee113eSDavid van Moolenbroek 	struct sockaddr_in local_sin;
114*83ee113eSDavid van Moolenbroek 
115*83ee113eSDavid van Moolenbroek 	obj = (omapi_connection_object_t *)0;
116*83ee113eSDavid van Moolenbroek 	status = omapi_connection_allocate (&obj, MDL);
117*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
118*83ee113eSDavid van Moolenbroek 		return status;
119*83ee113eSDavid van Moolenbroek 
120*83ee113eSDavid van Moolenbroek 	status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
121*83ee113eSDavid van Moolenbroek 					 MDL);
122*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
123*83ee113eSDavid van Moolenbroek 		omapi_connection_dereference (&obj, MDL);
124*83ee113eSDavid van Moolenbroek 		return status;
125*83ee113eSDavid van Moolenbroek 	}
126*83ee113eSDavid van Moolenbroek 	status = omapi_object_reference (&obj -> inner, c, MDL);
127*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
128*83ee113eSDavid van Moolenbroek 		omapi_connection_dereference (&obj, MDL);
129*83ee113eSDavid van Moolenbroek 		return status;
130*83ee113eSDavid van Moolenbroek 	}
131*83ee113eSDavid van Moolenbroek 
132*83ee113eSDavid van Moolenbroek 	/* Store the address list on the object. */
133*83ee113eSDavid van Moolenbroek 	omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
134*83ee113eSDavid van Moolenbroek 	obj -> cptr = 0;
135*83ee113eSDavid van Moolenbroek 	obj -> state = omapi_connection_unconnected;
136*83ee113eSDavid van Moolenbroek 
137*83ee113eSDavid van Moolenbroek #if defined (TRACING)
138*83ee113eSDavid van Moolenbroek 	/* If we're playing back, don't actually try to connect - just leave
139*83ee113eSDavid van Moolenbroek 	   the object available for a subsequent connect or disconnect. */
140*83ee113eSDavid van Moolenbroek 	if (!trace_playback ()) {
141*83ee113eSDavid van Moolenbroek #endif
142*83ee113eSDavid van Moolenbroek 		/* Create a socket on which to communicate. */
143*83ee113eSDavid van Moolenbroek 		obj -> socket =
144*83ee113eSDavid van Moolenbroek 			socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
145*83ee113eSDavid van Moolenbroek 		if (obj -> socket < 0) {
146*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&obj, MDL);
147*83ee113eSDavid van Moolenbroek 			if (errno == EMFILE || errno == ENFILE
148*83ee113eSDavid van Moolenbroek 			    || errno == ENOBUFS)
149*83ee113eSDavid van Moolenbroek 				return ISC_R_NORESOURCES;
150*83ee113eSDavid van Moolenbroek 			return ISC_R_UNEXPECTED;
151*83ee113eSDavid van Moolenbroek 		}
152*83ee113eSDavid van Moolenbroek 
153*83ee113eSDavid van Moolenbroek 		/* Set up the local address, if any. */
154*83ee113eSDavid van Moolenbroek 		if (local_addr) {
155*83ee113eSDavid van Moolenbroek 			/* Only do TCPv4 so far. */
156*83ee113eSDavid van Moolenbroek 			if (local_addr -> addrtype != AF_INET) {
157*83ee113eSDavid van Moolenbroek 				omapi_connection_dereference (&obj, MDL);
158*83ee113eSDavid van Moolenbroek 				return DHCP_R_INVALIDARG;
159*83ee113eSDavid van Moolenbroek 			}
160*83ee113eSDavid van Moolenbroek 			local_sin.sin_port = htons (local_addr -> port);
161*83ee113eSDavid van Moolenbroek 			memcpy (&local_sin.sin_addr,
162*83ee113eSDavid van Moolenbroek 				local_addr -> address,
163*83ee113eSDavid van Moolenbroek 				local_addr -> addrlen);
164*83ee113eSDavid van Moolenbroek #if defined (HAVE_SA_LEN)
165*83ee113eSDavid van Moolenbroek 			local_sin.sin_len = sizeof local_addr;
166*83ee113eSDavid van Moolenbroek #endif
167*83ee113eSDavid van Moolenbroek 			local_sin.sin_family = AF_INET;
168*83ee113eSDavid van Moolenbroek 			memset (&local_sin.sin_zero, 0,
169*83ee113eSDavid van Moolenbroek 				sizeof local_sin.sin_zero);
170*83ee113eSDavid van Moolenbroek 
171*83ee113eSDavid van Moolenbroek 			if (bind (obj -> socket, (struct sockaddr *)&local_sin,
172*83ee113eSDavid van Moolenbroek 				  sizeof local_sin) < 0) {
173*83ee113eSDavid van Moolenbroek 				omapi_connection_object_t **objp = &obj;
174*83ee113eSDavid van Moolenbroek 				omapi_object_t **o = (omapi_object_t **)objp;
175*83ee113eSDavid van Moolenbroek 				omapi_object_dereference(o, MDL);
176*83ee113eSDavid van Moolenbroek 				if (errno == EADDRINUSE)
177*83ee113eSDavid van Moolenbroek 					return ISC_R_ADDRINUSE;
178*83ee113eSDavid van Moolenbroek 				if (errno == EADDRNOTAVAIL)
179*83ee113eSDavid van Moolenbroek 					return ISC_R_ADDRNOTAVAIL;
180*83ee113eSDavid van Moolenbroek 				if (errno == EACCES)
181*83ee113eSDavid van Moolenbroek 					return ISC_R_NOPERM;
182*83ee113eSDavid van Moolenbroek 				return ISC_R_UNEXPECTED;
183*83ee113eSDavid van Moolenbroek 			}
184*83ee113eSDavid van Moolenbroek 			obj -> local_addr = local_sin;
185*83ee113eSDavid van Moolenbroek 		}
186*83ee113eSDavid van Moolenbroek 
187*83ee113eSDavid van Moolenbroek #if defined(F_SETFD)
188*83ee113eSDavid van Moolenbroek 		if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
189*83ee113eSDavid van Moolenbroek 			close (obj -> socket);
190*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&obj, MDL);
191*83ee113eSDavid van Moolenbroek 			return ISC_R_UNEXPECTED;
192*83ee113eSDavid van Moolenbroek 		}
193*83ee113eSDavid van Moolenbroek #endif
194*83ee113eSDavid van Moolenbroek 
195*83ee113eSDavid van Moolenbroek 		/* Set the SO_REUSEADDR flag (this should not fail). */
196*83ee113eSDavid van Moolenbroek 		flag = 1;
197*83ee113eSDavid van Moolenbroek 		if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
198*83ee113eSDavid van Moolenbroek 				(char *)&flag, sizeof flag) < 0) {
199*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&obj, MDL);
200*83ee113eSDavid van Moolenbroek 			return ISC_R_UNEXPECTED;
201*83ee113eSDavid van Moolenbroek 		}
202*83ee113eSDavid van Moolenbroek 
203*83ee113eSDavid van Moolenbroek 		/* Set the file to nonblocking mode. */
204*83ee113eSDavid van Moolenbroek 		if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
205*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&obj, MDL);
206*83ee113eSDavid van Moolenbroek 			return ISC_R_UNEXPECTED;
207*83ee113eSDavid van Moolenbroek 		}
208*83ee113eSDavid van Moolenbroek 
209*83ee113eSDavid van Moolenbroek #ifdef SO_NOSIGPIPE
210*83ee113eSDavid van Moolenbroek 		/*
211*83ee113eSDavid van Moolenbroek 		 * If available stop the OS from killing our
212*83ee113eSDavid van Moolenbroek 		 * program on a SIGPIPE failure
213*83ee113eSDavid van Moolenbroek 		 */
214*83ee113eSDavid van Moolenbroek 		flag = 1;
215*83ee113eSDavid van Moolenbroek 		if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
216*83ee113eSDavid van Moolenbroek 			       (char *)&flag, sizeof(flag)) < 0) {
217*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&obj, MDL);
218*83ee113eSDavid van Moolenbroek 			return ISC_R_UNEXPECTED;
219*83ee113eSDavid van Moolenbroek 		}
220*83ee113eSDavid van Moolenbroek #endif
221*83ee113eSDavid van Moolenbroek 
222*83ee113eSDavid van Moolenbroek 		status = (omapi_register_io_object
223*83ee113eSDavid van Moolenbroek 			  ((omapi_object_t *)obj,
224*83ee113eSDavid van Moolenbroek 			   0, omapi_connection_writefd,
225*83ee113eSDavid van Moolenbroek 			   0, omapi_connection_connect,
226*83ee113eSDavid van Moolenbroek 			   omapi_connection_reaper));
227*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
228*83ee113eSDavid van Moolenbroek 			goto out;
229*83ee113eSDavid van Moolenbroek 		status = omapi_connection_connect_internal ((omapi_object_t *)
230*83ee113eSDavid van Moolenbroek 							    obj);
231*83ee113eSDavid van Moolenbroek 		/*
232*83ee113eSDavid van Moolenbroek 		 * inprogress is the same as success but used
233*83ee113eSDavid van Moolenbroek 		 * to indicate to the dispatch code that we should
234*83ee113eSDavid van Moolenbroek 		 * mark the socket as requiring more attention.
235*83ee113eSDavid van Moolenbroek 		 * Routines calling this function should handle
236*83ee113eSDavid van Moolenbroek 		 * success properly.
237*83ee113eSDavid van Moolenbroek 		 */
238*83ee113eSDavid van Moolenbroek 		if (status == ISC_R_INPROGRESS) {
239*83ee113eSDavid van Moolenbroek 			status = ISC_R_SUCCESS;
240*83ee113eSDavid van Moolenbroek 		}
241*83ee113eSDavid van Moolenbroek #if defined (TRACING)
242*83ee113eSDavid van Moolenbroek 	}
243*83ee113eSDavid van Moolenbroek 	omapi_connection_register (obj, MDL);
244*83ee113eSDavid van Moolenbroek #endif
245*83ee113eSDavid van Moolenbroek 
246*83ee113eSDavid van Moolenbroek       out:
247*83ee113eSDavid van Moolenbroek 	omapi_connection_dereference (&obj, MDL);
248*83ee113eSDavid van Moolenbroek 	return status;
249*83ee113eSDavid van Moolenbroek }
250*83ee113eSDavid van Moolenbroek 
251*83ee113eSDavid van Moolenbroek #if defined (TRACING)
252*83ee113eSDavid van Moolenbroek omapi_array_t *omapi_connections;
253*83ee113eSDavid van Moolenbroek 
OMAPI_ARRAY_TYPE(omapi_connection,omapi_connection_object_t)254*83ee113eSDavid van Moolenbroek OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
255*83ee113eSDavid van Moolenbroek 
256*83ee113eSDavid van Moolenbroek void omapi_connection_trace_setup (void) {
257*83ee113eSDavid van Moolenbroek 	trace_connect = trace_type_register ("connect", (void *)0,
258*83ee113eSDavid van Moolenbroek 					     trace_connect_input,
259*83ee113eSDavid van Moolenbroek 					     trace_connect_stop, MDL);
260*83ee113eSDavid van Moolenbroek 	trace_disconnect = trace_type_register ("disconnect", (void *)0,
261*83ee113eSDavid van Moolenbroek 						trace_disconnect_input,
262*83ee113eSDavid van Moolenbroek 						trace_disconnect_stop, MDL);
263*83ee113eSDavid van Moolenbroek }
264*83ee113eSDavid van Moolenbroek 
omapi_connection_register(omapi_connection_object_t * obj,const char * file,int line)265*83ee113eSDavid van Moolenbroek void omapi_connection_register (omapi_connection_object_t *obj,
266*83ee113eSDavid van Moolenbroek 				const char *file, int line)
267*83ee113eSDavid van Moolenbroek {
268*83ee113eSDavid van Moolenbroek 	isc_result_t status;
269*83ee113eSDavid van Moolenbroek 	trace_iov_t iov [6];
270*83ee113eSDavid van Moolenbroek 	int iov_count = 0;
271*83ee113eSDavid van Moolenbroek 	int32_t connect_index, listener_index;
272*83ee113eSDavid van Moolenbroek 	static int32_t index;
273*83ee113eSDavid van Moolenbroek 
274*83ee113eSDavid van Moolenbroek 	if (!omapi_connections) {
275*83ee113eSDavid van Moolenbroek 		status = omapi_connection_array_allocate (&omapi_connections,
276*83ee113eSDavid van Moolenbroek 							  file, line);
277*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
278*83ee113eSDavid van Moolenbroek 			return;
279*83ee113eSDavid van Moolenbroek 	}
280*83ee113eSDavid van Moolenbroek 
281*83ee113eSDavid van Moolenbroek 	status = omapi_connection_array_extend (omapi_connections, obj,
282*83ee113eSDavid van Moolenbroek 						(int *)0, file, line);
283*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
284*83ee113eSDavid van Moolenbroek 		obj -> index = -1;
285*83ee113eSDavid van Moolenbroek 		return;
286*83ee113eSDavid van Moolenbroek 	}
287*83ee113eSDavid van Moolenbroek 
288*83ee113eSDavid van Moolenbroek #if defined (TRACING)
289*83ee113eSDavid van Moolenbroek 	if (trace_record ()) {
290*83ee113eSDavid van Moolenbroek 		/* Connection registration packet:
291*83ee113eSDavid van Moolenbroek 
292*83ee113eSDavid van Moolenbroek 		     int32_t index
293*83ee113eSDavid van Moolenbroek 		     int32_t listener_index [-1 means no listener]
294*83ee113eSDavid van Moolenbroek 		   u_int16_t remote_port
295*83ee113eSDavid van Moolenbroek 		   u_int16_t local_port
296*83ee113eSDavid van Moolenbroek 		   u_int32_t remote_addr
297*83ee113eSDavid van Moolenbroek 		   u_int32_t local_addr */
298*83ee113eSDavid van Moolenbroek 
299*83ee113eSDavid van Moolenbroek 		connect_index = htonl (index);
300*83ee113eSDavid van Moolenbroek 		index++;
301*83ee113eSDavid van Moolenbroek 		if (obj -> listener)
302*83ee113eSDavid van Moolenbroek 			listener_index = htonl (obj -> listener -> index);
303*83ee113eSDavid van Moolenbroek 		else
304*83ee113eSDavid van Moolenbroek 			listener_index = htonl (-1);
305*83ee113eSDavid van Moolenbroek 		iov [iov_count].buf = (char *)&connect_index;
306*83ee113eSDavid van Moolenbroek 		iov [iov_count++].len = sizeof connect_index;
307*83ee113eSDavid van Moolenbroek 		iov [iov_count].buf = (char *)&listener_index;
308*83ee113eSDavid van Moolenbroek 		iov [iov_count++].len = sizeof listener_index;
309*83ee113eSDavid van Moolenbroek 		iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
310*83ee113eSDavid van Moolenbroek 		iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
311*83ee113eSDavid van Moolenbroek 		iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
312*83ee113eSDavid van Moolenbroek 		iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
313*83ee113eSDavid van Moolenbroek 		iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
314*83ee113eSDavid van Moolenbroek 		iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
315*83ee113eSDavid van Moolenbroek 		iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
316*83ee113eSDavid van Moolenbroek 		iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
317*83ee113eSDavid van Moolenbroek 
318*83ee113eSDavid van Moolenbroek 		status = trace_write_packet_iov (trace_connect,
319*83ee113eSDavid van Moolenbroek 						 iov_count, iov, file, line);
320*83ee113eSDavid van Moolenbroek 	}
321*83ee113eSDavid van Moolenbroek #endif
322*83ee113eSDavid van Moolenbroek }
323*83ee113eSDavid van Moolenbroek 
trace_connect_input(trace_type_t * ttype,unsigned length,char * buf)324*83ee113eSDavid van Moolenbroek static void trace_connect_input (trace_type_t *ttype,
325*83ee113eSDavid van Moolenbroek 				 unsigned length, char *buf)
326*83ee113eSDavid van Moolenbroek {
327*83ee113eSDavid van Moolenbroek 	struct sockaddr_in remote, local;
328*83ee113eSDavid van Moolenbroek 	int32_t connect_index, listener_index;
329*83ee113eSDavid van Moolenbroek 	char *s = buf;
330*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *obj;
331*83ee113eSDavid van Moolenbroek 	isc_result_t status;
332*83ee113eSDavid van Moolenbroek 	int i;
333*83ee113eSDavid van Moolenbroek 
334*83ee113eSDavid van Moolenbroek 	if (length != ((sizeof connect_index) +
335*83ee113eSDavid van Moolenbroek 		       (sizeof remote.sin_port) +
336*83ee113eSDavid van Moolenbroek 		       (sizeof remote.sin_addr)) * 2) {
337*83ee113eSDavid van Moolenbroek 		log_error ("Trace connect: invalid length %d", length);
338*83ee113eSDavid van Moolenbroek 		return;
339*83ee113eSDavid van Moolenbroek 	}
340*83ee113eSDavid van Moolenbroek 
341*83ee113eSDavid van Moolenbroek 	memset (&remote, 0, sizeof remote);
342*83ee113eSDavid van Moolenbroek 	memset (&local, 0, sizeof local);
343*83ee113eSDavid van Moolenbroek 	memcpy (&connect_index, s, sizeof connect_index);
344*83ee113eSDavid van Moolenbroek 	s += sizeof connect_index;
345*83ee113eSDavid van Moolenbroek 	memcpy (&listener_index, s, sizeof listener_index);
346*83ee113eSDavid van Moolenbroek 	s += sizeof listener_index;
347*83ee113eSDavid van Moolenbroek 	memcpy (&remote.sin_port, s, sizeof remote.sin_port);
348*83ee113eSDavid van Moolenbroek 	s += sizeof remote.sin_port;
349*83ee113eSDavid van Moolenbroek 	memcpy (&local.sin_port, s, sizeof local.sin_port);
350*83ee113eSDavid van Moolenbroek 	s += sizeof local.sin_port;
351*83ee113eSDavid van Moolenbroek 	memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
352*83ee113eSDavid van Moolenbroek 	s += sizeof remote.sin_addr;
353*83ee113eSDavid van Moolenbroek 	memcpy (&local.sin_addr, s, sizeof local.sin_addr);
354*83ee113eSDavid van Moolenbroek 	s += sizeof local.sin_addr;
355*83ee113eSDavid van Moolenbroek 	POST(s);
356*83ee113eSDavid van Moolenbroek 
357*83ee113eSDavid van Moolenbroek 	connect_index = ntohl (connect_index);
358*83ee113eSDavid van Moolenbroek 	listener_index = ntohl (listener_index);
359*83ee113eSDavid van Moolenbroek 
360*83ee113eSDavid van Moolenbroek 	/* If this was a connect to a listener, then we just slap together
361*83ee113eSDavid van Moolenbroek 	   a new connection. */
362*83ee113eSDavid van Moolenbroek 	if (listener_index != -1) {
363*83ee113eSDavid van Moolenbroek 		omapi_listener_object_t *listener;
364*83ee113eSDavid van Moolenbroek 		listener = (omapi_listener_object_t *)0;
365*83ee113eSDavid van Moolenbroek 		omapi_array_foreach_begin (trace_listeners,
366*83ee113eSDavid van Moolenbroek 					   omapi_listener_object_t, lp) {
367*83ee113eSDavid van Moolenbroek 			if (lp -> address.sin_port == local.sin_port) {
368*83ee113eSDavid van Moolenbroek 				omapi_listener_reference (&listener, lp, MDL);
369*83ee113eSDavid van Moolenbroek 				omapi_listener_dereference (&lp, MDL);
370*83ee113eSDavid van Moolenbroek 				break;
371*83ee113eSDavid van Moolenbroek 			}
372*83ee113eSDavid van Moolenbroek 		} omapi_array_foreach_end (trace_listeners,
373*83ee113eSDavid van Moolenbroek 					   omapi_listener_object_t, lp);
374*83ee113eSDavid van Moolenbroek 		if (!listener) {
375*83ee113eSDavid van Moolenbroek 			log_error ("%s%ld, addr %s, port %d",
376*83ee113eSDavid van Moolenbroek 				   "Spurious traced listener connect - index ",
377*83ee113eSDavid van Moolenbroek 				   (long int)listener_index,
378*83ee113eSDavid van Moolenbroek 				   inet_ntoa (local.sin_addr),
379*83ee113eSDavid van Moolenbroek 				   ntohs (local.sin_port));
380*83ee113eSDavid van Moolenbroek 			return;
381*83ee113eSDavid van Moolenbroek 		}
382*83ee113eSDavid van Moolenbroek 		obj = (omapi_connection_object_t *)0;
383*83ee113eSDavid van Moolenbroek 		status = omapi_listener_connect (&obj, listener, -1, &remote);
384*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
385*83ee113eSDavid van Moolenbroek 			log_error ("traced listener connect: %s",
386*83ee113eSDavid van Moolenbroek 				   isc_result_totext (status));
387*83ee113eSDavid van Moolenbroek 		}
388*83ee113eSDavid van Moolenbroek 		if (obj)
389*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&obj, MDL);
390*83ee113eSDavid van Moolenbroek 		omapi_listener_dereference (&listener, MDL);
391*83ee113eSDavid van Moolenbroek 		return;
392*83ee113eSDavid van Moolenbroek 	}
393*83ee113eSDavid van Moolenbroek 
394*83ee113eSDavid van Moolenbroek 	/* Find the matching connect object, if there is one. */
395*83ee113eSDavid van Moolenbroek 	omapi_array_foreach_begin (omapi_connections,
396*83ee113eSDavid van Moolenbroek 				   omapi_connection_object_t, lp) {
397*83ee113eSDavid van Moolenbroek 	    for (i = 0; (lp->connect_list &&
398*83ee113eSDavid van Moolenbroek 			 i < lp->connect_list->count); i++) {
399*83ee113eSDavid van Moolenbroek 		    if (!memcmp (&remote.sin_addr,
400*83ee113eSDavid van Moolenbroek 				 &lp->connect_list->addresses[i].address,
401*83ee113eSDavid van Moolenbroek 				 sizeof remote.sin_addr) &&
402*83ee113eSDavid van Moolenbroek 			(ntohs (remote.sin_port) ==
403*83ee113eSDavid van Moolenbroek 			 lp->connect_list->addresses[i].port)) {
404*83ee113eSDavid van Moolenbroek 			    lp->state = omapi_connection_connected;
405*83ee113eSDavid van Moolenbroek 			    lp->remote_addr = remote;
406*83ee113eSDavid van Moolenbroek 			    lp->remote_addr.sin_family = AF_INET;
407*83ee113eSDavid van Moolenbroek 			    omapi_addr_list_dereference(&lp->connect_list, MDL);
408*83ee113eSDavid van Moolenbroek 			    lp->index = connect_index;
409*83ee113eSDavid van Moolenbroek 			    status = omapi_signal_in((omapi_object_t *)lp,
410*83ee113eSDavid van Moolenbroek 						     "connect");
411*83ee113eSDavid van Moolenbroek 			    omapi_connection_dereference (&lp, MDL);
412*83ee113eSDavid van Moolenbroek 			    return;
413*83ee113eSDavid van Moolenbroek 		    }
414*83ee113eSDavid van Moolenbroek 		}
415*83ee113eSDavid van Moolenbroek 	} omapi_array_foreach_end (omapi_connections,
416*83ee113eSDavid van Moolenbroek 				   omapi_connection_object_t, lp);
417*83ee113eSDavid van Moolenbroek 
418*83ee113eSDavid van Moolenbroek 	log_error ("Spurious traced connect - index %ld, addr %s, port %d",
419*83ee113eSDavid van Moolenbroek 		   (long int)connect_index, inet_ntoa (remote.sin_addr),
420*83ee113eSDavid van Moolenbroek 		   ntohs (remote.sin_port));
421*83ee113eSDavid van Moolenbroek 	return;
422*83ee113eSDavid van Moolenbroek }
423*83ee113eSDavid van Moolenbroek 
trace_connect_stop(trace_type_t * ttype)424*83ee113eSDavid van Moolenbroek static void trace_connect_stop (trace_type_t *ttype) { }
425*83ee113eSDavid van Moolenbroek 
trace_disconnect_input(trace_type_t * ttype,unsigned length,char * buf)426*83ee113eSDavid van Moolenbroek static void trace_disconnect_input (trace_type_t *ttype,
427*83ee113eSDavid van Moolenbroek 				    unsigned length, char *buf)
428*83ee113eSDavid van Moolenbroek {
429*83ee113eSDavid van Moolenbroek 	int32_t *index;
430*83ee113eSDavid van Moolenbroek 	if (length != sizeof *index) {
431*83ee113eSDavid van Moolenbroek 		log_error ("trace disconnect: wrong length %d", length);
432*83ee113eSDavid van Moolenbroek 		return;
433*83ee113eSDavid van Moolenbroek 	}
434*83ee113eSDavid van Moolenbroek 
435*83ee113eSDavid van Moolenbroek 	index = (int32_t *)buf;
436*83ee113eSDavid van Moolenbroek 
437*83ee113eSDavid van Moolenbroek 	omapi_array_foreach_begin (omapi_connections,
438*83ee113eSDavid van Moolenbroek 				   omapi_connection_object_t, lp) {
439*83ee113eSDavid van Moolenbroek 		if (lp -> index == ntohl (*index)) {
440*83ee113eSDavid van Moolenbroek 			omapi_disconnect ((omapi_object_t *)lp, 1);
441*83ee113eSDavid van Moolenbroek 			omapi_connection_dereference (&lp, MDL);
442*83ee113eSDavid van Moolenbroek 			return;
443*83ee113eSDavid van Moolenbroek 		}
444*83ee113eSDavid van Moolenbroek 	} omapi_array_foreach_end (omapi_connections,
445*83ee113eSDavid van Moolenbroek 				   omapi_connection_object_t, lp);
446*83ee113eSDavid van Moolenbroek 
447*83ee113eSDavid van Moolenbroek 	log_error ("trace disconnect: no connection matching index %ld",
448*83ee113eSDavid van Moolenbroek 		   (long int)ntohl (*index));
449*83ee113eSDavid van Moolenbroek }
450*83ee113eSDavid van Moolenbroek 
trace_disconnect_stop(trace_type_t * ttype)451*83ee113eSDavid van Moolenbroek static void trace_disconnect_stop (trace_type_t *ttype) { }
452*83ee113eSDavid van Moolenbroek #endif
453*83ee113eSDavid van Moolenbroek 
454*83ee113eSDavid van Moolenbroek /* Disconnect a connection object from the remote end.   If force is nonzero,
455*83ee113eSDavid van Moolenbroek    close the connection immediately.   Otherwise, shut down the receiving end
456*83ee113eSDavid van Moolenbroek    but allow any unsent data to be sent before actually closing the socket. */
457*83ee113eSDavid van Moolenbroek 
omapi_disconnect(omapi_object_t * h,int force)458*83ee113eSDavid van Moolenbroek isc_result_t omapi_disconnect (omapi_object_t *h,
459*83ee113eSDavid van Moolenbroek 			       int force)
460*83ee113eSDavid van Moolenbroek {
461*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
462*83ee113eSDavid van Moolenbroek 
463*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PROTOCOL
464*83ee113eSDavid van Moolenbroek 	log_debug ("omapi_disconnect(%s)", force ? "force" : "");
465*83ee113eSDavid van Moolenbroek #endif
466*83ee113eSDavid van Moolenbroek 
467*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
468*83ee113eSDavid van Moolenbroek 	if (c -> type != omapi_type_connection)
469*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
470*83ee113eSDavid van Moolenbroek 
471*83ee113eSDavid van Moolenbroek #if defined (TRACING)
472*83ee113eSDavid van Moolenbroek 	if (trace_record ()) {
473*83ee113eSDavid van Moolenbroek 		isc_result_t status;
474*83ee113eSDavid van Moolenbroek 		int32_t index;
475*83ee113eSDavid van Moolenbroek 
476*83ee113eSDavid van Moolenbroek 		index = htonl (c -> index);
477*83ee113eSDavid van Moolenbroek 		status = trace_write_packet (trace_disconnect,
478*83ee113eSDavid van Moolenbroek 					     sizeof index, (char *)&index,
479*83ee113eSDavid van Moolenbroek 					     MDL);
480*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
481*83ee113eSDavid van Moolenbroek 			trace_stop ();
482*83ee113eSDavid van Moolenbroek 			log_error ("trace_write_packet: %s",
483*83ee113eSDavid van Moolenbroek 				   isc_result_totext (status));
484*83ee113eSDavid van Moolenbroek 		}
485*83ee113eSDavid van Moolenbroek 	}
486*83ee113eSDavid van Moolenbroek 	if (!trace_playback ()) {
487*83ee113eSDavid van Moolenbroek #endif
488*83ee113eSDavid van Moolenbroek 		if (!force) {
489*83ee113eSDavid van Moolenbroek 			/* If we're already disconnecting, we don't have to do
490*83ee113eSDavid van Moolenbroek 			   anything. */
491*83ee113eSDavid van Moolenbroek 			if (c -> state == omapi_connection_disconnecting)
492*83ee113eSDavid van Moolenbroek 				return ISC_R_SUCCESS;
493*83ee113eSDavid van Moolenbroek 
494*83ee113eSDavid van Moolenbroek 			/* Try to shut down the socket - this sends a FIN to
495*83ee113eSDavid van Moolenbroek 			   the remote end, so that it won't send us any more
496*83ee113eSDavid van Moolenbroek 			   data.   If the shutdown succeeds, and we still
497*83ee113eSDavid van Moolenbroek 			   have bytes left to write, defer closing the socket
498*83ee113eSDavid van Moolenbroek 			   until that's done. */
499*83ee113eSDavid van Moolenbroek 			if (!shutdown (c -> socket, SHUT_RD)) {
500*83ee113eSDavid van Moolenbroek 				if (c -> out_bytes > 0) {
501*83ee113eSDavid van Moolenbroek 					c -> state =
502*83ee113eSDavid van Moolenbroek 						omapi_connection_disconnecting;
503*83ee113eSDavid van Moolenbroek 					return ISC_R_SUCCESS;
504*83ee113eSDavid van Moolenbroek 				}
505*83ee113eSDavid van Moolenbroek 			}
506*83ee113eSDavid van Moolenbroek 		}
507*83ee113eSDavid van Moolenbroek 		close (c -> socket);
508*83ee113eSDavid van Moolenbroek #if defined (TRACING)
509*83ee113eSDavid van Moolenbroek 	}
510*83ee113eSDavid van Moolenbroek #endif
511*83ee113eSDavid van Moolenbroek 	c -> state = omapi_connection_closed;
512*83ee113eSDavid van Moolenbroek 
513*83ee113eSDavid van Moolenbroek #if 0
514*83ee113eSDavid van Moolenbroek 	/*
515*83ee113eSDavid van Moolenbroek 	 * Disconnecting from the I/O object seems incorrect as it doesn't
516*83ee113eSDavid van Moolenbroek 	 * cause the I/O object to be cleaned and released.  Previous to
517*83ee113eSDavid van Moolenbroek 	 * using the isc socket library this wouldn't have caused a problem
518*83ee113eSDavid van Moolenbroek 	 * with the socket library we would have a reference to a closed
519*83ee113eSDavid van Moolenbroek 	 * socket.  Instead we now do an unregister to properly free the
520*83ee113eSDavid van Moolenbroek 	 * I/O object.
521*83ee113eSDavid van Moolenbroek 	 */
522*83ee113eSDavid van Moolenbroek 
523*83ee113eSDavid van Moolenbroek 	/* Disconnect from I/O object, if any. */
524*83ee113eSDavid van Moolenbroek 	if (h -> outer) {
525*83ee113eSDavid van Moolenbroek 		if (h -> outer -> inner)
526*83ee113eSDavid van Moolenbroek 			omapi_object_dereference (&h -> outer -> inner, MDL);
527*83ee113eSDavid van Moolenbroek 		omapi_object_dereference (&h -> outer, MDL);
528*83ee113eSDavid van Moolenbroek 	}
529*83ee113eSDavid van Moolenbroek #else
530*83ee113eSDavid van Moolenbroek 	if (h->outer) {
531*83ee113eSDavid van Moolenbroek 		omapi_unregister_io_object(h);
532*83ee113eSDavid van Moolenbroek 	}
533*83ee113eSDavid van Moolenbroek #endif
534*83ee113eSDavid van Moolenbroek 
535*83ee113eSDavid van Moolenbroek 	/* If whatever created us registered a signal handler, send it
536*83ee113eSDavid van Moolenbroek 	   a disconnect signal. */
537*83ee113eSDavid van Moolenbroek 	omapi_signal (h, "disconnect", h);
538*83ee113eSDavid van Moolenbroek 
539*83ee113eSDavid van Moolenbroek 	/* Disconnect from protocol object, if any. */
540*83ee113eSDavid van Moolenbroek 	if (h->inner != NULL) {
541*83ee113eSDavid van Moolenbroek 		if (h->inner->outer != NULL) {
542*83ee113eSDavid van Moolenbroek 			omapi_object_dereference(&h->inner->outer, MDL);
543*83ee113eSDavid van Moolenbroek 		}
544*83ee113eSDavid van Moolenbroek 		omapi_object_dereference(&h->inner, MDL);
545*83ee113eSDavid van Moolenbroek 	}
546*83ee113eSDavid van Moolenbroek 
547*83ee113eSDavid van Moolenbroek 	/* XXX: the code to free buffers should be in the dereference
548*83ee113eSDavid van Moolenbroek 		function, but there is no special-purpose function to
549*83ee113eSDavid van Moolenbroek 		dereference connections, so these just get leaked */
550*83ee113eSDavid van Moolenbroek 	/* Free any buffers */
551*83ee113eSDavid van Moolenbroek 	if (c->inbufs != NULL) {
552*83ee113eSDavid van Moolenbroek 		omapi_buffer_dereference(&c->inbufs, MDL);
553*83ee113eSDavid van Moolenbroek 	}
554*83ee113eSDavid van Moolenbroek 	c->in_bytes = 0;
555*83ee113eSDavid van Moolenbroek 	if (c->outbufs != NULL) {
556*83ee113eSDavid van Moolenbroek 		omapi_buffer_dereference(&c->outbufs, MDL);
557*83ee113eSDavid van Moolenbroek 	}
558*83ee113eSDavid van Moolenbroek 	c->out_bytes = 0;
559*83ee113eSDavid van Moolenbroek 
560*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
561*83ee113eSDavid van Moolenbroek }
562*83ee113eSDavid van Moolenbroek 
omapi_connection_require(omapi_object_t * h,unsigned bytes)563*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
564*83ee113eSDavid van Moolenbroek {
565*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
566*83ee113eSDavid van Moolenbroek 
567*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
568*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
569*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
570*83ee113eSDavid van Moolenbroek 
571*83ee113eSDavid van Moolenbroek 	c -> bytes_needed = bytes;
572*83ee113eSDavid van Moolenbroek 	if (c -> bytes_needed <= c -> in_bytes) {
573*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
574*83ee113eSDavid van Moolenbroek 	}
575*83ee113eSDavid van Moolenbroek 	return DHCP_R_NOTYET;
576*83ee113eSDavid van Moolenbroek }
577*83ee113eSDavid van Moolenbroek 
578*83ee113eSDavid van Moolenbroek /* Return the socket on which the dispatcher should wait for readiness
579*83ee113eSDavid van Moolenbroek    to read, for a connection object.  */
omapi_connection_readfd(omapi_object_t * h)580*83ee113eSDavid van Moolenbroek int omapi_connection_readfd (omapi_object_t *h)
581*83ee113eSDavid van Moolenbroek {
582*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
583*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
584*83ee113eSDavid van Moolenbroek 		return -1;
585*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
586*83ee113eSDavid van Moolenbroek 	if (c -> state != omapi_connection_connected)
587*83ee113eSDavid van Moolenbroek 		return -1;
588*83ee113eSDavid van Moolenbroek 	return c -> socket;
589*83ee113eSDavid van Moolenbroek }
590*83ee113eSDavid van Moolenbroek 
591*83ee113eSDavid van Moolenbroek /*
592*83ee113eSDavid van Moolenbroek  * Return the socket on which the dispatcher should wait for readiness
593*83ee113eSDavid van Moolenbroek  * to write, for a connection object.  When bytes are buffered we should
594*83ee113eSDavid van Moolenbroek  * also poke the dispatcher to tell it to start or re-start watching the
595*83ee113eSDavid van Moolenbroek  * socket.
596*83ee113eSDavid van Moolenbroek  */
omapi_connection_writefd(omapi_object_t * h)597*83ee113eSDavid van Moolenbroek int omapi_connection_writefd (omapi_object_t *h)
598*83ee113eSDavid van Moolenbroek {
599*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
600*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
601*83ee113eSDavid van Moolenbroek 		return -1;
602*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
603*83ee113eSDavid van Moolenbroek 	return c->socket;
604*83ee113eSDavid van Moolenbroek }
605*83ee113eSDavid van Moolenbroek 
omapi_connection_connect(omapi_object_t * h)606*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_connect (omapi_object_t *h)
607*83ee113eSDavid van Moolenbroek {
608*83ee113eSDavid van Moolenbroek 	isc_result_t status;
609*83ee113eSDavid van Moolenbroek 
610*83ee113eSDavid van Moolenbroek 	/*
611*83ee113eSDavid van Moolenbroek 	 * We use the INPROGRESS status to indicate that
612*83ee113eSDavid van Moolenbroek 	 * we want more from the socket.  In this case we
613*83ee113eSDavid van Moolenbroek 	 * have now connected and are trying to write to
614*83ee113eSDavid van Moolenbroek 	 * the socket for the first time.  For the signaling
615*83ee113eSDavid van Moolenbroek 	 * code this is the same as a SUCCESS so we don't
616*83ee113eSDavid van Moolenbroek 	 * pass it on as a signal.
617*83ee113eSDavid van Moolenbroek 	 */
618*83ee113eSDavid van Moolenbroek 	status = omapi_connection_connect_internal (h);
619*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_INPROGRESS)
620*83ee113eSDavid van Moolenbroek 		return ISC_R_INPROGRESS;
621*83ee113eSDavid van Moolenbroek 
622*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
623*83ee113eSDavid van Moolenbroek 		omapi_signal (h, "status", status);
624*83ee113eSDavid van Moolenbroek 
625*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
626*83ee113eSDavid van Moolenbroek }
627*83ee113eSDavid van Moolenbroek 
omapi_connection_connect_internal(omapi_object_t * h)628*83ee113eSDavid van Moolenbroek static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
629*83ee113eSDavid van Moolenbroek {
630*83ee113eSDavid van Moolenbroek 	int error = 0;
631*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
632*83ee113eSDavid van Moolenbroek 	socklen_t sl;
633*83ee113eSDavid van Moolenbroek 	isc_result_t status;
634*83ee113eSDavid van Moolenbroek 
635*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
636*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
637*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
638*83ee113eSDavid van Moolenbroek 
639*83ee113eSDavid van Moolenbroek 	if (c -> state == omapi_connection_connecting) {
640*83ee113eSDavid van Moolenbroek 		sl = sizeof error;
641*83ee113eSDavid van Moolenbroek 		if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
642*83ee113eSDavid van Moolenbroek 				(char *)&error, &sl) < 0) {
643*83ee113eSDavid van Moolenbroek 			omapi_disconnect (h, 1);
644*83ee113eSDavid van Moolenbroek 			return ISC_R_SUCCESS;
645*83ee113eSDavid van Moolenbroek 		}
646*83ee113eSDavid van Moolenbroek 		if (!error)
647*83ee113eSDavid van Moolenbroek 			c -> state = omapi_connection_connected;
648*83ee113eSDavid van Moolenbroek 	}
649*83ee113eSDavid van Moolenbroek 	if (c -> state == omapi_connection_connecting ||
650*83ee113eSDavid van Moolenbroek 	    c -> state == omapi_connection_unconnected) {
651*83ee113eSDavid van Moolenbroek 		if (c -> cptr >= c -> connect_list -> count) {
652*83ee113eSDavid van Moolenbroek 			switch (error) {
653*83ee113eSDavid van Moolenbroek 			      case ECONNREFUSED:
654*83ee113eSDavid van Moolenbroek 				status = ISC_R_CONNREFUSED;
655*83ee113eSDavid van Moolenbroek 				break;
656*83ee113eSDavid van Moolenbroek 			      case ENETUNREACH:
657*83ee113eSDavid van Moolenbroek 				status = ISC_R_NETUNREACH;
658*83ee113eSDavid van Moolenbroek 				break;
659*83ee113eSDavid van Moolenbroek 			      default:
660*83ee113eSDavid van Moolenbroek 				status = uerr2isc (error);
661*83ee113eSDavid van Moolenbroek 				break;
662*83ee113eSDavid van Moolenbroek 			}
663*83ee113eSDavid van Moolenbroek 			omapi_disconnect (h, 1);
664*83ee113eSDavid van Moolenbroek 			return status;
665*83ee113eSDavid van Moolenbroek 		}
666*83ee113eSDavid van Moolenbroek 
667*83ee113eSDavid van Moolenbroek 		if (c -> connect_list -> addresses [c -> cptr].addrtype !=
668*83ee113eSDavid van Moolenbroek 		    AF_INET) {
669*83ee113eSDavid van Moolenbroek 			omapi_disconnect (h, 1);
670*83ee113eSDavid van Moolenbroek 			return DHCP_R_INVALIDARG;
671*83ee113eSDavid van Moolenbroek 		}
672*83ee113eSDavid van Moolenbroek 
673*83ee113eSDavid van Moolenbroek 		memcpy (&c -> remote_addr.sin_addr,
674*83ee113eSDavid van Moolenbroek 			&c -> connect_list -> addresses [c -> cptr].address,
675*83ee113eSDavid van Moolenbroek 			sizeof c -> remote_addr.sin_addr);
676*83ee113eSDavid van Moolenbroek 		c -> remote_addr.sin_family = AF_INET;
677*83ee113eSDavid van Moolenbroek 		c -> remote_addr.sin_port =
678*83ee113eSDavid van Moolenbroek 		       htons (c -> connect_list -> addresses [c -> cptr].port);
679*83ee113eSDavid van Moolenbroek #if defined (HAVE_SA_LEN)
680*83ee113eSDavid van Moolenbroek 		c -> remote_addr.sin_len = sizeof c -> remote_addr;
681*83ee113eSDavid van Moolenbroek #endif
682*83ee113eSDavid van Moolenbroek 		memset (&c -> remote_addr.sin_zero, 0,
683*83ee113eSDavid van Moolenbroek 			sizeof c -> remote_addr.sin_zero);
684*83ee113eSDavid van Moolenbroek 		++c -> cptr;
685*83ee113eSDavid van Moolenbroek 
686*83ee113eSDavid van Moolenbroek 		error = connect (c -> socket,
687*83ee113eSDavid van Moolenbroek 				 (struct sockaddr *)&c -> remote_addr,
688*83ee113eSDavid van Moolenbroek 				 sizeof c -> remote_addr);
689*83ee113eSDavid van Moolenbroek 		if (error < 0) {
690*83ee113eSDavid van Moolenbroek 			error = errno;
691*83ee113eSDavid van Moolenbroek 			if (error != EINPROGRESS) {
692*83ee113eSDavid van Moolenbroek 				omapi_disconnect (h, 1);
693*83ee113eSDavid van Moolenbroek 				switch (error) {
694*83ee113eSDavid van Moolenbroek 				      case ECONNREFUSED:
695*83ee113eSDavid van Moolenbroek 					status = ISC_R_CONNREFUSED;
696*83ee113eSDavid van Moolenbroek 					break;
697*83ee113eSDavid van Moolenbroek 				      case ENETUNREACH:
698*83ee113eSDavid van Moolenbroek 					status = ISC_R_NETUNREACH;
699*83ee113eSDavid van Moolenbroek 					break;
700*83ee113eSDavid van Moolenbroek 				      default:
701*83ee113eSDavid van Moolenbroek 					status = uerr2isc (error);
702*83ee113eSDavid van Moolenbroek 					break;
703*83ee113eSDavid van Moolenbroek 				}
704*83ee113eSDavid van Moolenbroek 				return status;
705*83ee113eSDavid van Moolenbroek 			}
706*83ee113eSDavid van Moolenbroek 			c -> state = omapi_connection_connecting;
707*83ee113eSDavid van Moolenbroek 			return DHCP_R_INCOMPLETE;
708*83ee113eSDavid van Moolenbroek 		}
709*83ee113eSDavid van Moolenbroek 		c -> state = omapi_connection_connected;
710*83ee113eSDavid van Moolenbroek 	}
711*83ee113eSDavid van Moolenbroek 
712*83ee113eSDavid van Moolenbroek 	/* I don't know why this would fail, so I'm tempted not to test
713*83ee113eSDavid van Moolenbroek 	   the return value. */
714*83ee113eSDavid van Moolenbroek 	sl = sizeof (c -> local_addr);
715*83ee113eSDavid van Moolenbroek 	if (getsockname (c -> socket,
716*83ee113eSDavid van Moolenbroek 			 (struct sockaddr *)&c -> local_addr, &sl) < 0) {
717*83ee113eSDavid van Moolenbroek 	}
718*83ee113eSDavid van Moolenbroek 
719*83ee113eSDavid van Moolenbroek 	/* Reregister with the I/O object.  If we don't already have an
720*83ee113eSDavid van Moolenbroek 	   I/O object this turns into a register call, otherwise we simply
721*83ee113eSDavid van Moolenbroek 	   modify the pointers in the I/O object. */
722*83ee113eSDavid van Moolenbroek 
723*83ee113eSDavid van Moolenbroek 	status = omapi_reregister_io_object (h,
724*83ee113eSDavid van Moolenbroek 					     omapi_connection_readfd,
725*83ee113eSDavid van Moolenbroek 					     omapi_connection_writefd,
726*83ee113eSDavid van Moolenbroek 					     omapi_connection_reader,
727*83ee113eSDavid van Moolenbroek 					     omapi_connection_writer,
728*83ee113eSDavid van Moolenbroek 					     omapi_connection_reaper);
729*83ee113eSDavid van Moolenbroek 
730*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
731*83ee113eSDavid van Moolenbroek 		omapi_disconnect (h, 1);
732*83ee113eSDavid van Moolenbroek 		return status;
733*83ee113eSDavid van Moolenbroek 	}
734*83ee113eSDavid van Moolenbroek 
735*83ee113eSDavid van Moolenbroek 	omapi_signal_in (h, "connect");
736*83ee113eSDavid van Moolenbroek 	omapi_addr_list_dereference (&c -> connect_list, MDL);
737*83ee113eSDavid van Moolenbroek 	return ISC_R_INPROGRESS;
738*83ee113eSDavid van Moolenbroek }
739*83ee113eSDavid van Moolenbroek 
740*83ee113eSDavid van Moolenbroek /* Reaper function for connection - if the connection is completely closed,
741*83ee113eSDavid van Moolenbroek    reap it.   If it's in the disconnecting state, there were bytes left
742*83ee113eSDavid van Moolenbroek    to write when the user closed it, so if there are now no bytes left to
743*83ee113eSDavid van Moolenbroek    write, we can close it. */
omapi_connection_reaper(omapi_object_t * h)744*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_reaper (omapi_object_t *h)
745*83ee113eSDavid van Moolenbroek {
746*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
747*83ee113eSDavid van Moolenbroek 
748*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
749*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
750*83ee113eSDavid van Moolenbroek 
751*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
752*83ee113eSDavid van Moolenbroek 	if (c -> state == omapi_connection_disconnecting &&
753*83ee113eSDavid van Moolenbroek 	    c -> out_bytes == 0) {
754*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PROTOCOL
755*83ee113eSDavid van Moolenbroek 		log_debug ("omapi_connection_reaper(): disconnect");
756*83ee113eSDavid van Moolenbroek #endif
757*83ee113eSDavid van Moolenbroek 		omapi_disconnect (h, 1);
758*83ee113eSDavid van Moolenbroek 	}
759*83ee113eSDavid van Moolenbroek 	if (c -> state == omapi_connection_closed) {
760*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PROTOCOL
761*83ee113eSDavid van Moolenbroek 		log_debug ("omapi_connection_reaper(): closed");
762*83ee113eSDavid van Moolenbroek #endif
763*83ee113eSDavid van Moolenbroek 		return ISC_R_NOTCONNECTED;
764*83ee113eSDavid van Moolenbroek 	}
765*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
766*83ee113eSDavid van Moolenbroek }
767*83ee113eSDavid van Moolenbroek 
make_dst_key(dst_key_t ** dst_key,omapi_object_t * a)768*83ee113eSDavid van Moolenbroek static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
769*83ee113eSDavid van Moolenbroek 	omapi_value_t *name      = (omapi_value_t *)0;
770*83ee113eSDavid van Moolenbroek 	omapi_value_t *algorithm = (omapi_value_t *)0;
771*83ee113eSDavid van Moolenbroek 	omapi_value_t *key       = (omapi_value_t *)0;
772*83ee113eSDavid van Moolenbroek 	char *name_str = NULL;
773*83ee113eSDavid van Moolenbroek 	isc_result_t status = ISC_R_SUCCESS;
774*83ee113eSDavid van Moolenbroek 
775*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_SUCCESS)
776*83ee113eSDavid van Moolenbroek 		status = omapi_get_value_str
777*83ee113eSDavid van Moolenbroek 			(a, (omapi_object_t *)0, "name", &name);
778*83ee113eSDavid van Moolenbroek 
779*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_SUCCESS)
780*83ee113eSDavid van Moolenbroek 		status = omapi_get_value_str
781*83ee113eSDavid van Moolenbroek 			(a, (omapi_object_t *)0, "algorithm", &algorithm);
782*83ee113eSDavid van Moolenbroek 
783*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_SUCCESS)
784*83ee113eSDavid van Moolenbroek 		status = omapi_get_value_str
785*83ee113eSDavid van Moolenbroek 			(a, (omapi_object_t *)0, "key", &key);
786*83ee113eSDavid van Moolenbroek 
787*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_SUCCESS) {
788*83ee113eSDavid van Moolenbroek 		if ((algorithm->value->type != omapi_datatype_data &&
789*83ee113eSDavid van Moolenbroek 		     algorithm->value->type != omapi_datatype_string) ||
790*83ee113eSDavid van Moolenbroek 		    strncasecmp((char *)algorithm->value->u.buffer.value,
791*83ee113eSDavid van Moolenbroek 				NS_TSIG_ALG_HMAC_MD5 ".",
792*83ee113eSDavid van Moolenbroek 				algorithm->value->u.buffer.len) != 0) {
793*83ee113eSDavid van Moolenbroek 			status = DHCP_R_INVALIDARG;
794*83ee113eSDavid van Moolenbroek 		}
795*83ee113eSDavid van Moolenbroek 	}
796*83ee113eSDavid van Moolenbroek 
797*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_SUCCESS) {
798*83ee113eSDavid van Moolenbroek 		name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
799*83ee113eSDavid van Moolenbroek 		if (!name_str)
800*83ee113eSDavid van Moolenbroek 			status = ISC_R_NOMEMORY;
801*83ee113eSDavid van Moolenbroek 	}
802*83ee113eSDavid van Moolenbroek 
803*83ee113eSDavid van Moolenbroek 	if (status == ISC_R_SUCCESS) {
804*83ee113eSDavid van Moolenbroek 		memcpy (name_str,
805*83ee113eSDavid van Moolenbroek 			name -> value -> u.buffer.value,
806*83ee113eSDavid van Moolenbroek 			name -> value -> u.buffer.len);
807*83ee113eSDavid van Moolenbroek 		name_str [name -> value -> u.buffer.len] = 0;
808*83ee113eSDavid van Moolenbroek 
809*83ee113eSDavid van Moolenbroek 		status = isclib_make_dst_key(name_str,
810*83ee113eSDavid van Moolenbroek 					     DHCP_HMAC_MD5_NAME,
811*83ee113eSDavid van Moolenbroek 					     key->value->u.buffer.value,
812*83ee113eSDavid van Moolenbroek 					     key->value->u.buffer.len,
813*83ee113eSDavid van Moolenbroek 					     dst_key);
814*83ee113eSDavid van Moolenbroek 
815*83ee113eSDavid van Moolenbroek 		if (*dst_key == NULL)
816*83ee113eSDavid van Moolenbroek 			status = ISC_R_NOMEMORY;
817*83ee113eSDavid van Moolenbroek 	}
818*83ee113eSDavid van Moolenbroek 
819*83ee113eSDavid van Moolenbroek 	if (name_str)
820*83ee113eSDavid van Moolenbroek 		dfree (name_str, MDL);
821*83ee113eSDavid van Moolenbroek 	if (key)
822*83ee113eSDavid van Moolenbroek 		omapi_value_dereference (&key, MDL);
823*83ee113eSDavid van Moolenbroek 	if (algorithm)
824*83ee113eSDavid van Moolenbroek 		omapi_value_dereference (&algorithm, MDL);
825*83ee113eSDavid van Moolenbroek 	if (name)
826*83ee113eSDavid van Moolenbroek 		omapi_value_dereference (&name, MDL);
827*83ee113eSDavid van Moolenbroek 
828*83ee113eSDavid van Moolenbroek 	return status;
829*83ee113eSDavid van Moolenbroek }
830*83ee113eSDavid van Moolenbroek 
omapi_connection_sign_data(int mode,dst_key_t * key,void ** context,const unsigned char * data,const unsigned len,omapi_typed_data_t ** result)831*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_sign_data (int mode,
832*83ee113eSDavid van Moolenbroek 					 dst_key_t *key,
833*83ee113eSDavid van Moolenbroek 					 void **context,
834*83ee113eSDavid van Moolenbroek 					 const unsigned char *data,
835*83ee113eSDavid van Moolenbroek 					 const unsigned len,
836*83ee113eSDavid van Moolenbroek 					 omapi_typed_data_t **result)
837*83ee113eSDavid van Moolenbroek {
838*83ee113eSDavid van Moolenbroek 	omapi_typed_data_t *td = (omapi_typed_data_t *)0;
839*83ee113eSDavid van Moolenbroek 	isc_result_t status;
840*83ee113eSDavid van Moolenbroek 	dst_context_t **dctx = (dst_context_t **)context;
841*83ee113eSDavid van Moolenbroek 
842*83ee113eSDavid van Moolenbroek 	/* Create the context for the dst module */
843*83ee113eSDavid van Moolenbroek 	if (mode & SIG_MODE_INIT) {
844*83ee113eSDavid van Moolenbroek 		status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
845*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
846*83ee113eSDavid van Moolenbroek 			return status;
847*83ee113eSDavid van Moolenbroek 		}
848*83ee113eSDavid van Moolenbroek 	}
849*83ee113eSDavid van Moolenbroek 
850*83ee113eSDavid van Moolenbroek 	/* If we have any data add it to the context */
851*83ee113eSDavid van Moolenbroek 	if (len != 0) {
852*83ee113eSDavid van Moolenbroek 		isc_region_t region;
853*83ee113eSDavid van Moolenbroek 		region.base   = (unsigned char *)data;
854*83ee113eSDavid van Moolenbroek 		region.length = len;
855*83ee113eSDavid van Moolenbroek 		dst_context_adddata(*dctx, &region);
856*83ee113eSDavid van Moolenbroek 	}
857*83ee113eSDavid van Moolenbroek 
858*83ee113eSDavid van Moolenbroek 	/* Finish the signature and clean up the context */
859*83ee113eSDavid van Moolenbroek 	if (mode & SIG_MODE_FINAL) {
860*83ee113eSDavid van Moolenbroek 		unsigned int sigsize;
861*83ee113eSDavid van Moolenbroek 		isc_buffer_t sigbuf;
862*83ee113eSDavid van Moolenbroek 
863*83ee113eSDavid van Moolenbroek 		status = dst_key_sigsize(key, &sigsize);
864*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
865*83ee113eSDavid van Moolenbroek 			goto cleanup;
866*83ee113eSDavid van Moolenbroek 		}
867*83ee113eSDavid van Moolenbroek 
868*83ee113eSDavid van Moolenbroek 		status = omapi_typed_data_new (MDL, &td,
869*83ee113eSDavid van Moolenbroek 					       omapi_datatype_data,
870*83ee113eSDavid van Moolenbroek 					       sigsize);
871*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
872*83ee113eSDavid van Moolenbroek 			goto cleanup;
873*83ee113eSDavid van Moolenbroek 		}
874*83ee113eSDavid van Moolenbroek 
875*83ee113eSDavid van Moolenbroek 		isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
876*83ee113eSDavid van Moolenbroek 		status = dst_context_sign(*dctx, &sigbuf);
877*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
878*83ee113eSDavid van Moolenbroek 			goto cleanup;
879*83ee113eSDavid van Moolenbroek 		}
880*83ee113eSDavid van Moolenbroek 
881*83ee113eSDavid van Moolenbroek 		if (result) {
882*83ee113eSDavid van Moolenbroek 			omapi_typed_data_reference (result, td, MDL);
883*83ee113eSDavid van Moolenbroek 		}
884*83ee113eSDavid van Moolenbroek 
885*83ee113eSDavid van Moolenbroek 	cleanup:
886*83ee113eSDavid van Moolenbroek 		/* We are done with the context and the td.  On success
887*83ee113eSDavid van Moolenbroek 		 * the td is now referenced from result, on failure we
888*83ee113eSDavid van Moolenbroek 		 * don't need it any more */
889*83ee113eSDavid van Moolenbroek 		if (td) {
890*83ee113eSDavid van Moolenbroek 			omapi_typed_data_dereference (&td, MDL);
891*83ee113eSDavid van Moolenbroek 		}
892*83ee113eSDavid van Moolenbroek 		dst_context_destroy(dctx);
893*83ee113eSDavid van Moolenbroek 		return status;
894*83ee113eSDavid van Moolenbroek 	}
895*83ee113eSDavid van Moolenbroek 
896*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
897*83ee113eSDavid van Moolenbroek }
898*83ee113eSDavid van Moolenbroek 
omapi_connection_output_auth_length(omapi_object_t * h,unsigned * l)899*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
900*83ee113eSDavid van Moolenbroek 						  unsigned *l)
901*83ee113eSDavid van Moolenbroek {
902*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
903*83ee113eSDavid van Moolenbroek 
904*83ee113eSDavid van Moolenbroek 	if (h->type != omapi_type_connection)
905*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
906*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
907*83ee113eSDavid van Moolenbroek 
908*83ee113eSDavid van Moolenbroek 	if (c->out_key == NULL)
909*83ee113eSDavid van Moolenbroek 		return ISC_R_NOTFOUND;
910*83ee113eSDavid van Moolenbroek 
911*83ee113eSDavid van Moolenbroek 	return(dst_key_sigsize(c->out_key, l));
912*83ee113eSDavid van Moolenbroek }
913*83ee113eSDavid van Moolenbroek 
omapi_connection_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)914*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_set_value (omapi_object_t *h,
915*83ee113eSDavid van Moolenbroek 					 omapi_object_t *id,
916*83ee113eSDavid van Moolenbroek 					 omapi_data_string_t *name,
917*83ee113eSDavid van Moolenbroek 					 omapi_typed_data_t *value)
918*83ee113eSDavid van Moolenbroek {
919*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
920*83ee113eSDavid van Moolenbroek 	isc_result_t status;
921*83ee113eSDavid van Moolenbroek 
922*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
923*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
924*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
925*83ee113eSDavid van Moolenbroek 
926*83ee113eSDavid van Moolenbroek 	if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
927*83ee113eSDavid van Moolenbroek 		if (value && value -> type != omapi_datatype_object)
928*83ee113eSDavid van Moolenbroek 			return DHCP_R_INVALIDARG;
929*83ee113eSDavid van Moolenbroek 
930*83ee113eSDavid van Moolenbroek 		if (c -> in_context) {
931*83ee113eSDavid van Moolenbroek 			omapi_connection_sign_data (SIG_MODE_FINAL,
932*83ee113eSDavid van Moolenbroek 						    c -> in_key,
933*83ee113eSDavid van Moolenbroek 						    &c -> in_context,
934*83ee113eSDavid van Moolenbroek 						    0, 0,
935*83ee113eSDavid van Moolenbroek 						    (omapi_typed_data_t **) 0);
936*83ee113eSDavid van Moolenbroek 		}
937*83ee113eSDavid van Moolenbroek 
938*83ee113eSDavid van Moolenbroek 		if (c->in_key != NULL) {
939*83ee113eSDavid van Moolenbroek 			dst_key_free(&c->in_key);
940*83ee113eSDavid van Moolenbroek 		}
941*83ee113eSDavid van Moolenbroek 
942*83ee113eSDavid van Moolenbroek 		if (value) {
943*83ee113eSDavid van Moolenbroek 			status = make_dst_key (&c -> in_key,
944*83ee113eSDavid van Moolenbroek 					       value -> u.object);
945*83ee113eSDavid van Moolenbroek 			if (status != ISC_R_SUCCESS)
946*83ee113eSDavid van Moolenbroek 				return status;
947*83ee113eSDavid van Moolenbroek 		}
948*83ee113eSDavid van Moolenbroek 
949*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
950*83ee113eSDavid van Moolenbroek 	}
951*83ee113eSDavid van Moolenbroek 	else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
952*83ee113eSDavid van Moolenbroek 		if (value && value -> type != omapi_datatype_object)
953*83ee113eSDavid van Moolenbroek 			return DHCP_R_INVALIDARG;
954*83ee113eSDavid van Moolenbroek 
955*83ee113eSDavid van Moolenbroek 		if (c -> out_context) {
956*83ee113eSDavid van Moolenbroek 			omapi_connection_sign_data (SIG_MODE_FINAL,
957*83ee113eSDavid van Moolenbroek 						    c -> out_key,
958*83ee113eSDavid van Moolenbroek 						    &c -> out_context,
959*83ee113eSDavid van Moolenbroek 						    0, 0,
960*83ee113eSDavid van Moolenbroek 						    (omapi_typed_data_t **) 0);
961*83ee113eSDavid van Moolenbroek 		}
962*83ee113eSDavid van Moolenbroek 
963*83ee113eSDavid van Moolenbroek 		if (c->out_key != NULL) {
964*83ee113eSDavid van Moolenbroek 			dst_key_free(&c->out_key);
965*83ee113eSDavid van Moolenbroek 		}
966*83ee113eSDavid van Moolenbroek 
967*83ee113eSDavid van Moolenbroek 		if (value) {
968*83ee113eSDavid van Moolenbroek 			status = make_dst_key (&c -> out_key,
969*83ee113eSDavid van Moolenbroek 					       value -> u.object);
970*83ee113eSDavid van Moolenbroek 			if (status != ISC_R_SUCCESS)
971*83ee113eSDavid van Moolenbroek 				return status;
972*83ee113eSDavid van Moolenbroek 		}
973*83ee113eSDavid van Moolenbroek 
974*83ee113eSDavid van Moolenbroek 		return ISC_R_SUCCESS;
975*83ee113eSDavid van Moolenbroek 	}
976*83ee113eSDavid van Moolenbroek 
977*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> set_value)
978*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> set_value))
979*83ee113eSDavid van Moolenbroek 			(h -> inner, id, name, value);
980*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
981*83ee113eSDavid van Moolenbroek }
982*83ee113eSDavid van Moolenbroek 
omapi_connection_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)983*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_get_value (omapi_object_t *h,
984*83ee113eSDavid van Moolenbroek 					 omapi_object_t *id,
985*83ee113eSDavid van Moolenbroek 					 omapi_data_string_t *name,
986*83ee113eSDavid van Moolenbroek 					 omapi_value_t **value)
987*83ee113eSDavid van Moolenbroek {
988*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
989*83ee113eSDavid van Moolenbroek 	omapi_typed_data_t *td = (omapi_typed_data_t *)0;
990*83ee113eSDavid van Moolenbroek 	isc_result_t status;
991*83ee113eSDavid van Moolenbroek 	unsigned int sigsize;
992*83ee113eSDavid van Moolenbroek 
993*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
994*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
995*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)h;
996*83ee113eSDavid van Moolenbroek 
997*83ee113eSDavid van Moolenbroek 	if (omapi_ds_strcmp (name, "input-signature") == 0) {
998*83ee113eSDavid van Moolenbroek 		if (!c -> in_key || !c -> in_context)
999*83ee113eSDavid van Moolenbroek 			return ISC_R_NOTFOUND;
1000*83ee113eSDavid van Moolenbroek 
1001*83ee113eSDavid van Moolenbroek 		status = omapi_connection_sign_data (SIG_MODE_FINAL,
1002*83ee113eSDavid van Moolenbroek 						     c -> in_key,
1003*83ee113eSDavid van Moolenbroek 						     &c -> in_context,
1004*83ee113eSDavid van Moolenbroek 						     0, 0, &td);
1005*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
1006*83ee113eSDavid van Moolenbroek 			return status;
1007*83ee113eSDavid van Moolenbroek 
1008*83ee113eSDavid van Moolenbroek 		status = omapi_make_value (value, name, td, MDL);
1009*83ee113eSDavid van Moolenbroek 		omapi_typed_data_dereference (&td, MDL);
1010*83ee113eSDavid van Moolenbroek 		return status;
1011*83ee113eSDavid van Moolenbroek 
1012*83ee113eSDavid van Moolenbroek 	} else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
1013*83ee113eSDavid van Moolenbroek 		if (c->in_key == NULL)
1014*83ee113eSDavid van Moolenbroek 			return ISC_R_NOTFOUND;
1015*83ee113eSDavid van Moolenbroek 
1016*83ee113eSDavid van Moolenbroek 		status = dst_key_sigsize(c->in_key, &sigsize);
1017*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
1018*83ee113eSDavid van Moolenbroek 			return(status);
1019*83ee113eSDavid van Moolenbroek 		}
1020*83ee113eSDavid van Moolenbroek 
1021*83ee113eSDavid van Moolenbroek 		return omapi_make_int_value(value, name, sigsize, MDL);
1022*83ee113eSDavid van Moolenbroek 
1023*83ee113eSDavid van Moolenbroek 	} else if (omapi_ds_strcmp (name, "output-signature") == 0) {
1024*83ee113eSDavid van Moolenbroek 		if (!c -> out_key || !c -> out_context)
1025*83ee113eSDavid van Moolenbroek 			return ISC_R_NOTFOUND;
1026*83ee113eSDavid van Moolenbroek 
1027*83ee113eSDavid van Moolenbroek 		status = omapi_connection_sign_data (SIG_MODE_FINAL,
1028*83ee113eSDavid van Moolenbroek 						     c -> out_key,
1029*83ee113eSDavid van Moolenbroek 						     &c -> out_context,
1030*83ee113eSDavid van Moolenbroek 						     0, 0, &td);
1031*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
1032*83ee113eSDavid van Moolenbroek 			return status;
1033*83ee113eSDavid van Moolenbroek 
1034*83ee113eSDavid van Moolenbroek 		status = omapi_make_value (value, name, td, MDL);
1035*83ee113eSDavid van Moolenbroek 		omapi_typed_data_dereference (&td, MDL);
1036*83ee113eSDavid van Moolenbroek 		return status;
1037*83ee113eSDavid van Moolenbroek 
1038*83ee113eSDavid van Moolenbroek 	} else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
1039*83ee113eSDavid van Moolenbroek 		if (c->out_key == NULL)
1040*83ee113eSDavid van Moolenbroek 			return ISC_R_NOTFOUND;
1041*83ee113eSDavid van Moolenbroek 
1042*83ee113eSDavid van Moolenbroek 
1043*83ee113eSDavid van Moolenbroek 		status = dst_key_sigsize(c->out_key, &sigsize);
1044*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
1045*83ee113eSDavid van Moolenbroek 			return(status);
1046*83ee113eSDavid van Moolenbroek 		}
1047*83ee113eSDavid van Moolenbroek 
1048*83ee113eSDavid van Moolenbroek 		return omapi_make_int_value(value, name, sigsize, MDL);
1049*83ee113eSDavid van Moolenbroek 	}
1050*83ee113eSDavid van Moolenbroek 
1051*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> get_value)
1052*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> get_value))
1053*83ee113eSDavid van Moolenbroek 			(h -> inner, id, name, value);
1054*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
1055*83ee113eSDavid van Moolenbroek }
1056*83ee113eSDavid van Moolenbroek 
omapi_connection_destroy(omapi_object_t * h,const char * file,int line)1057*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_destroy (omapi_object_t *h,
1058*83ee113eSDavid van Moolenbroek 				       const char *file, int line)
1059*83ee113eSDavid van Moolenbroek {
1060*83ee113eSDavid van Moolenbroek 	omapi_connection_object_t *c;
1061*83ee113eSDavid van Moolenbroek 
1062*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PROTOCOL
1063*83ee113eSDavid van Moolenbroek 	log_debug ("omapi_connection_destroy()");
1064*83ee113eSDavid van Moolenbroek #endif
1065*83ee113eSDavid van Moolenbroek 
1066*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
1067*83ee113eSDavid van Moolenbroek 		return ISC_R_UNEXPECTED;
1068*83ee113eSDavid van Moolenbroek 	c = (omapi_connection_object_t *)(h);
1069*83ee113eSDavid van Moolenbroek 	if (c -> state == omapi_connection_connected)
1070*83ee113eSDavid van Moolenbroek 		omapi_disconnect (h, 1);
1071*83ee113eSDavid van Moolenbroek 	if (c -> listener)
1072*83ee113eSDavid van Moolenbroek 		omapi_listener_dereference (&c -> listener, file, line);
1073*83ee113eSDavid van Moolenbroek 	if (c -> connect_list)
1074*83ee113eSDavid van Moolenbroek 		omapi_addr_list_dereference (&c -> connect_list, file, line);
1075*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
1076*83ee113eSDavid van Moolenbroek }
1077*83ee113eSDavid van Moolenbroek 
omapi_connection_signal_handler(omapi_object_t * h,const char * name,va_list ap)1078*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
1079*83ee113eSDavid van Moolenbroek 					      const char *name, va_list ap)
1080*83ee113eSDavid van Moolenbroek {
1081*83ee113eSDavid van Moolenbroek 	if (h -> type != omapi_type_connection)
1082*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
1083*83ee113eSDavid van Moolenbroek 
1084*83ee113eSDavid van Moolenbroek #ifdef DEBUG_PROTOCOL
1085*83ee113eSDavid van Moolenbroek 	log_debug ("omapi_connection_signal_handler(%s)", name);
1086*83ee113eSDavid van Moolenbroek #endif
1087*83ee113eSDavid van Moolenbroek 
1088*83ee113eSDavid van Moolenbroek 	if (h -> inner && h -> inner -> type -> signal_handler)
1089*83ee113eSDavid van Moolenbroek 		return (*(h -> inner -> type -> signal_handler)) (h -> inner,
1090*83ee113eSDavid van Moolenbroek 								  name, ap);
1091*83ee113eSDavid van Moolenbroek 	return ISC_R_NOTFOUND;
1092*83ee113eSDavid van Moolenbroek }
1093*83ee113eSDavid van Moolenbroek 
1094*83ee113eSDavid van Moolenbroek /* Write all the published values associated with the object through the
1095*83ee113eSDavid van Moolenbroek    specified connection. */
1096*83ee113eSDavid van Moolenbroek 
omapi_connection_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * m)1097*83ee113eSDavid van Moolenbroek isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
1098*83ee113eSDavid van Moolenbroek 					    omapi_object_t *id,
1099*83ee113eSDavid van Moolenbroek 					    omapi_object_t *m)
1100*83ee113eSDavid van Moolenbroek {
1101*83ee113eSDavid van Moolenbroek 	if (m -> type != omapi_type_connection)
1102*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
1103*83ee113eSDavid van Moolenbroek 
1104*83ee113eSDavid van Moolenbroek 	if (m -> inner && m -> inner -> type -> stuff_values)
1105*83ee113eSDavid van Moolenbroek 		return (*(m -> inner -> type -> stuff_values)) (c, id,
1106*83ee113eSDavid van Moolenbroek 								m -> inner);
1107*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
1108*83ee113eSDavid van Moolenbroek }
1109