File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / omapip / listener.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, 9 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

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

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