File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / omapip / connection.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>