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