File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / omapip / listener.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:30:18 2012 UTC (12 years, 5 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* listener.c
    2: 
    3:    Subroutines that support the generic listener object. */
    4: 
    5: /*
    6:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 1999-2003 by Internet Software Consortium
    8:  *
    9:  * Permission to use, copy, modify, and distribute this software for any
   10:  * purpose with or without fee is hereby granted, provided that the above
   11:  * copyright notice and this permission notice appear in all copies.
   12:  *
   13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20:  *
   21:  *   Internet Systems Consortium, Inc.
   22:  *   950 Charter Street
   23:  *   Redwood City, CA 94063
   24:  *   <info@isc.org>
   25:  *   https://www.isc.org/
   26:  *
   27:  * This software has been written for Internet Systems Consortium
   28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   29:  * To learn more about Internet Systems Consortium, see
   30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
   31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
   32:  * ``http://www.nominum.com''.
   33:  */
   34: 
   35: #include "dhcpd.h"
   36: 
   37: #include <omapip/omapip_p.h>
   38: #include <errno.h>
   39: 
   40: #if defined (TRACING)
   41: omapi_array_t *trace_listeners;
   42: static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
   43: static void trace_listener_remember (omapi_listener_object_t *,
   44: 				     const char *, int);
   45: static void trace_listener_accept_stop (trace_type_t *);
   46: trace_type_t *trace_listener_accept;
   47: #endif
   48: 
   49: OMAPI_OBJECT_ALLOC (omapi_listener,
   50: 		    omapi_listener_object_t, omapi_type_listener)
   51: 
   52: isc_result_t omapi_listen (omapi_object_t *h,
   53: 			   unsigned port,
   54: 			   int max)
   55: {
   56: 	omapi_addr_t addr;
   57: 
   58: #ifdef DEBUG_PROTOCOL
   59: 	log_debug ("omapi_listen(port=%d, max=%d)", port, max);
   60: #endif
   61: 
   62: 	addr.addrtype = AF_INET;
   63: 	addr.addrlen = sizeof (struct in_addr);
   64: 	memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
   65: 	addr.port = port;
   66: 
   67: 	return omapi_listen_addr (h, &addr, max);
   68: }
   69: 
   70: isc_result_t omapi_listen_addr (omapi_object_t *h,
   71: 				omapi_addr_t *addr,
   72: 				int max)
   73: {
   74: 	isc_result_t status;
   75: 	omapi_listener_object_t *obj;
   76: 	int i;
   77: 
   78: 	/* Currently only support IPv4 addresses. */
   79: 	if (addr->addrtype != AF_INET)
   80: 		return ISC_R_INVALIDARG;
   81: 
   82: 	/* Get the handle. */
   83: 	obj = (omapi_listener_object_t *)0;
   84: 	status = omapi_listener_allocate (&obj, MDL);
   85: 	if (status != ISC_R_SUCCESS)
   86: 		return status;
   87: 	obj->socket = -1;
   88: 
   89: 	/* Connect this object to the inner object. */
   90: 	status = omapi_object_reference (&h -> outer,
   91: 					 (omapi_object_t *)obj, MDL);
   92: 	if (status != ISC_R_SUCCESS)
   93: 		goto error_exit;
   94: 	status = omapi_object_reference (&obj -> inner, h, MDL);
   95: 	if (status != ISC_R_SUCCESS)
   96: 		goto error_exit;
   97: 
   98: 	/* Set up the address on which we will listen... */
   99: 	obj -> address.sin_port = htons (addr -> port);
  100: 	memcpy (&obj -> address.sin_addr,
  101: 		addr -> address, sizeof obj -> address.sin_addr);
  102: #if defined (HAVE_SA_LEN)
  103: 	obj -> address.sin_len =
  104: 		sizeof (struct sockaddr_in);
  105: #endif
  106: 	obj -> address.sin_family = AF_INET;
  107: 	memset (&(obj -> address.sin_zero), 0,
  108: 		sizeof obj -> address.sin_zero);
  109: 
  110: #if defined (TRACING)
  111: 	/* If we're playing back a trace file, we remember the object
  112: 	   on the trace listener queue. */
  113: 	if (trace_playback ()) {
  114: 		trace_listener_remember (obj, MDL);
  115: 	}  else {
  116: #endif
  117: 		/* Create a socket on which to listen. */
  118: 		obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
  119: 		if (obj->socket == -1) {
  120: 			if (errno == EMFILE
  121: 			    || errno == ENFILE || errno == ENOBUFS)
  122: 				status = ISC_R_NORESOURCES;
  123: 			else
  124: 				status = ISC_R_UNEXPECTED;
  125: 			goto error_exit;
  126: 		}
  127: 	
  128: #if defined (HAVE_SETFD)
  129: 		if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
  130: 			status = ISC_R_UNEXPECTED;
  131: 			goto error_exit;
  132: 		}
  133: #endif
  134: 
  135: 		/* Set the REUSEADDR option so that we don't fail to start if
  136: 		   we're being restarted. */
  137: 		i = 1;
  138: 		if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
  139: 				(char *)&i, sizeof i) < 0) {
  140: 			status = ISC_R_UNEXPECTED;
  141: 			goto error_exit;
  142: 		}
  143: 		
  144: 		/* Try to bind to the wildcard address using the port number
  145: 		   we were given. */
  146: 		i = bind (obj -> socket,
  147: 			  (struct sockaddr *)&obj -> address,
  148: 			  sizeof obj -> address);
  149: 		if (i < 0) {
  150: 			if (errno == EADDRINUSE)
  151: 				status = ISC_R_ADDRNOTAVAIL;
  152: 			else if (errno == EPERM)
  153: 				status = ISC_R_NOPERM;
  154: 			else
  155: 				status = ISC_R_UNEXPECTED;
  156: 			goto error_exit;
  157: 		}
  158: 
  159: 		/* Now tell the kernel to listen for connections. */
  160: 		if (listen (obj -> socket, max)) {
  161: 			status = ISC_R_UNEXPECTED;
  162: 			goto error_exit;
  163: 		}
  164: 
  165: 		if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
  166: 			status = ISC_R_UNEXPECTED;
  167: 			goto error_exit;
  168: 		}
  169: 
  170: 		status = omapi_register_io_object ((omapi_object_t *)obj,
  171: 						   omapi_listener_readfd, 0,
  172: 						   omapi_accept, 0, 0);
  173: #if defined (TRACING)
  174: 	}
  175: #endif
  176: 
  177: 	omapi_listener_dereference (&obj, MDL);
  178: 	return status;
  179: 
  180: error_exit:
  181: 	if (obj != NULL) {
  182: 		if (h->outer == (omapi_object_t *)obj) {
  183: 			omapi_object_dereference((omapi_object_t **)&h->outer, 
  184: 						 MDL);
  185: 		}
  186: 		if (obj->inner == h) {
  187: 			omapi_object_dereference((omapi_object_t **)&obj->inner,
  188: 						 MDL);
  189: 		}
  190: 		if (obj->socket != -1) {
  191: 			close(obj->socket);
  192: 		}
  193: 		omapi_listener_dereference(&obj, MDL);
  194: 	}
  195: 	return status;
  196: }
  197: 
  198: /* Return the socket on which the dispatcher should wait for readiness
  199:    to read, for a listener object. */
  200: int omapi_listener_readfd (omapi_object_t *h)
  201: {
  202: 	omapi_listener_object_t *l;
  203: 
  204: 	if (h -> type != omapi_type_listener)
  205: 		return -1;
  206: 	l = (omapi_listener_object_t *)h;
  207: 	
  208: 	return l -> socket;
  209: }
  210: 
  211: /* Reader callback for a listener object.   Accept an incoming connection. */
  212: isc_result_t omapi_accept (omapi_object_t *h)
  213: {
  214: 	isc_result_t status;
  215: 	socklen_t len;
  216: 	omapi_connection_object_t *obj;
  217: 	omapi_listener_object_t *listener;
  218: 	struct sockaddr_in addr;
  219: 	int socket;
  220: 
  221: 	if (h -> type != omapi_type_listener)
  222: 		return ISC_R_INVALIDARG;
  223: 	listener = (omapi_listener_object_t *)h;
  224: 
  225: 	/* Accept the connection. */
  226: 	len = sizeof addr;
  227: 	socket = accept (listener -> socket,
  228: 			 ((struct sockaddr *)&(addr)), &len);
  229: 	if (socket < 0) {
  230: 		if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
  231: 			return ISC_R_NORESOURCES;
  232: 		return ISC_R_UNEXPECTED;
  233: 	}
  234: 	
  235: #if defined (TRACING)
  236: 	/* If we're recording a trace, remember the connection. */
  237: 	if (trace_record ()) {
  238: 		trace_iov_t iov [3];
  239: 		iov [0].buf = (char *)&addr.sin_port;
  240: 		iov [0].len = sizeof addr.sin_port;
  241: 		iov [1].buf = (char *)&addr.sin_addr;
  242: 		iov [1].len = sizeof addr.sin_addr;
  243: 		iov [2].buf = (char *)&listener -> address.sin_port;
  244: 		iov [2].len = sizeof listener -> address.sin_port;
  245: 		trace_write_packet_iov (trace_listener_accept,
  246: 					3, iov, MDL);
  247: 	}
  248: #endif
  249: 
  250: 	obj = (omapi_connection_object_t *)0;
  251: 	status = omapi_listener_connect (&obj, listener, socket, &addr);
  252: 	if (status != ISC_R_SUCCESS) {
  253: 		close (socket);
  254: 		return status;
  255: 	}
  256: 
  257: 	status = omapi_register_io_object ((omapi_object_t *)obj,
  258: 					   omapi_connection_readfd,
  259: 					   omapi_connection_writefd,
  260: 					   omapi_connection_reader,
  261: 					   omapi_connection_writer,
  262: 					   omapi_connection_reaper);
  263: 
  264: 	/* Lose our reference to the connection, so it'll be gc'd when it's
  265: 	   reaped. */
  266: 	omapi_connection_dereference (&obj, MDL);
  267: 	if (status != ISC_R_SUCCESS)
  268: 		omapi_disconnect ((omapi_object_t *)(obj), 1);
  269: 	return status;
  270: }
  271: 
  272: isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
  273: 				     omapi_listener_object_t *listener,
  274: 				     int socket,
  275: 				     struct sockaddr_in *remote_addr)
  276: {
  277: 	isc_result_t status;
  278: 	omapi_object_t *h = (omapi_object_t *)listener;
  279: 	omapi_addr_t addr;
  280: 
  281: #ifdef DEBUG_PROTOCOL
  282: 	log_debug ("omapi_accept()");
  283: #endif
  284: 	
  285: 	/* Get the handle. */
  286: 	status = omapi_connection_allocate (obj, MDL);
  287: 	if (status != ISC_R_SUCCESS)
  288: 		return status;
  289: 
  290: 	(*obj) -> state = omapi_connection_connected;
  291: 	(*obj) -> remote_addr = *remote_addr;
  292: 	(*obj) -> socket = socket;
  293: 
  294: 	/* Verify that this host is allowed to connect. */
  295: 	if (listener -> verify_addr) {
  296: 		addr.addrtype = AF_INET;
  297: 		addr.addrlen = sizeof (remote_addr -> sin_addr);
  298: 		memcpy (addr.address, &remote_addr -> sin_addr,
  299: 			sizeof (remote_addr -> sin_addr));
  300: 		addr.port = ntohs(remote_addr -> sin_port);
  301: 
  302: 		status = (listener -> verify_addr) (h, &addr);
  303: 		if (status != ISC_R_SUCCESS) {
  304: 			omapi_disconnect ((omapi_object_t *)(*obj), 1);
  305: 			omapi_connection_dereference (obj, MDL);
  306: 			return status;
  307: 		}
  308: 	}
  309: 
  310: 	omapi_listener_reference (&(*obj) -> listener, listener, MDL);
  311: #if defined (TRACING)
  312: 	omapi_connection_register (*obj, MDL);
  313: #endif
  314: 	status = omapi_signal (h, "connect", (*obj));
  315: 	return status;
  316: }
  317: 
  318: #if defined (TRACING)
  319: OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
  320: 
  321: void omapi_listener_trace_setup (void) {
  322: 	trace_listener_accept =
  323: 		trace_type_register ("listener-accept", (void *)0,
  324: 				     trace_listener_accept_input,
  325: 				     trace_listener_accept_stop, MDL);
  326: }
  327: 
  328: static void trace_listener_remember (omapi_listener_object_t *obj,
  329: 				     const char *file, int line)
  330: {
  331: 	isc_result_t status;
  332: 	if (!trace_listeners) {
  333: 		status = omapi_listener_array_allocate (&trace_listeners,
  334: 							file, line);
  335: 		if (status != ISC_R_SUCCESS) {
  336: 		      foo:
  337: 			log_error ("trace_listener_remember: %s",
  338: 				   isc_result_totext (status));
  339: 			return;
  340: 		}
  341: 	}
  342: 	status = omapi_listener_array_extend (trace_listeners, obj,
  343: 					      &obj -> index, MDL);
  344: 	if (status != ISC_R_SUCCESS)
  345: 		goto foo;
  346: }
  347: 
  348: static void trace_listener_accept_input (trace_type_t *ttype,
  349: 					 unsigned length, char *buf)
  350: {
  351: 	struct in_addr *addr;
  352: 	u_int16_t *remote_port;
  353: 	u_int16_t *local_port;
  354: 	omapi_connection_object_t *obj;
  355: 	isc_result_t status;
  356: 	struct sockaddr_in remote_addr;
  357: 
  358: 	addr = (struct in_addr *)buf;
  359: 	remote_port = (u_int16_t *)(addr + 1);
  360: 	local_port = remote_port + 1;
  361: 
  362: 	memset (&remote_addr, 0, sizeof remote_addr);
  363: 	remote_addr.sin_addr = *addr;
  364: 	remote_addr.sin_port = *remote_port;
  365: 
  366: 	omapi_array_foreach_begin (trace_listeners,
  367: 				   omapi_listener_object_t, lp) {
  368: 		if (lp -> address.sin_port == *local_port) {
  369: 			obj = (omapi_connection_object_t *)0;
  370: 			status = omapi_listener_connect (&obj,
  371: 							 lp, 0, &remote_addr);
  372: 			omapi_listener_dereference (&lp, MDL);
  373: 			return;
  374: 		}
  375: 	} omapi_array_foreach_end (trace_listeners,
  376: 				   omapi_listener_object_t, lp);
  377: 	log_error ("trace_listener_accept: %s from %s/%d to port %d",
  378: 		   "unexpected connect",
  379: 		   inet_ntoa (*addr), *remote_port, *local_port);
  380: }
  381: 
  382: static void trace_listener_accept_stop (trace_type_t *ttype) { }
  383: 
  384: 
  385: #endif
  386: 
  387: isc_result_t omapi_listener_configure_security (omapi_object_t *h,
  388: 						isc_result_t (*verify_addr)
  389: 						 (omapi_object_t *,
  390: 						  omapi_addr_t *))
  391: {
  392: 	omapi_listener_object_t *l;
  393: 
  394: 	if (h -> type != omapi_type_listener)
  395: 		return ISC_R_INVALIDARG;
  396: 	l = (omapi_listener_object_t *)h;
  397: 
  398: 	l -> verify_addr = verify_addr;
  399: 
  400: 	return ISC_R_SUCCESS;
  401: }
  402: 
  403: isc_result_t omapi_listener_set_value (omapi_object_t *h,
  404: 				      omapi_object_t *id,
  405: 				      omapi_data_string_t *name,
  406: 				      omapi_typed_data_t *value)
  407: {
  408: 	if (h -> type != omapi_type_listener)
  409: 		return ISC_R_INVALIDARG;
  410: 	
  411: 	if (h -> inner && h -> inner -> type -> set_value)
  412: 		return (*(h -> inner -> type -> set_value))
  413: 			(h -> inner, id, name, value);
  414: 	return ISC_R_NOTFOUND;
  415: }
  416: 
  417: isc_result_t omapi_listener_get_value (omapi_object_t *h,
  418: 				       omapi_object_t *id,
  419: 				       omapi_data_string_t *name,
  420: 				       omapi_value_t **value)
  421: {
  422: 	if (h -> type != omapi_type_listener)
  423: 		return ISC_R_INVALIDARG;
  424: 	
  425: 	if (h -> inner && h -> inner -> type -> get_value)
  426: 		return (*(h -> inner -> type -> get_value))
  427: 			(h -> inner, id, name, value);
  428: 	return ISC_R_NOTFOUND;
  429: }
  430: 
  431: isc_result_t omapi_listener_destroy (omapi_object_t *h,
  432: 				     const char *file, int line)
  433: {
  434: 	omapi_listener_object_t *l;
  435: 
  436: 	if (h -> type != omapi_type_listener)
  437: 		return ISC_R_INVALIDARG;
  438: 	l = (omapi_listener_object_t *)h;
  439: 
  440: #ifdef DEBUG_PROTOCOL
  441: 	log_debug ("omapi_listener_destroy()");
  442: #endif
  443: 	
  444: 	if (l -> socket != -1) {
  445: 		close (l -> socket);
  446: 		l -> socket = -1;
  447: 	}
  448: 	return ISC_R_SUCCESS;
  449: }
  450: 
  451: isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
  452: 					    const char *name, va_list ap)
  453: {
  454: 	if (h -> type != omapi_type_listener)
  455: 		return ISC_R_INVALIDARG;
  456: 	
  457: 	if (h -> inner && h -> inner -> type -> signal_handler)
  458: 		return (*(h -> inner -> type -> signal_handler)) (h -> inner,
  459: 								  name, ap);
  460: 	return ISC_R_NOTFOUND;
  461: }
  462: 
  463: /* Write all the published values associated with the object through the
  464:    specified connection. */
  465: 
  466: isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
  467: 					  omapi_object_t *id,
  468: 					  omapi_object_t *l)
  469: {
  470: 	if (l -> type != omapi_type_listener)
  471: 		return ISC_R_INVALIDARG;
  472: 
  473: 	if (l -> inner && l -> inner -> type -> stuff_values)
  474: 		return (*(l -> inner -> type -> stuff_values)) (c, id,
  475: 								l -> inner);
  476: 	return ISC_R_SUCCESS;
  477: }
  478: 

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