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