failover.c

来自「open source dhcp server client etc...」· C语言 代码 · 共 2,172 行 · 第 1/5 页

C
2,172
字号
/* failover.c   Failover protocol support code... *//* * Copyright (c) 1999-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names *    of its contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about the Internet Software Consortium, see * ``http://www.isc.org/''.  To learn more about Vixie Enterprises, * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */#ifndef lintstatic char copyright[] ="$Id: failover.c,v 1.53.2.14 2001/08/23 16:25:51 mellon Exp $ Copyright (c) 1999-2001 The Internet Software Consortium.  All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"#include "version.h"#include <omapip/omapip_p.h>#if defined (FAILOVER_PROTOCOL)static struct hash_table *failover_hash;dhcp_failover_state_t *failover_states;static isc_result_t do_a_failover_option (omapi_object_t *,					  dhcp_failover_link_t *);dhcp_failover_listener_t *failover_listeners;static isc_result_t failover_message_reference (failover_message_t **,						failover_message_t *,						const char *file, int line);static isc_result_t failover_message_dereference (failover_message_t **,						  const char *file, int line);void dhcp_failover_startup (){	dhcp_failover_state_t *state;	isc_result_t status;	dhcp_failover_listener_t *l;	for (state = failover_states; state; state = state -> next) {		dhcp_failover_state_transition (state, "startup");		if (state -> pool_count == 0) {			log_error ("failover peer declaration with no %s",				   "referring pools.");			log_error ("In order to use failover, you MUST %s",				   "refer to your main failover declaration");			log_error ("in each pool declaration.   You MUST %s",				   "NOT use range declarations outside");			log_fatal ("of pool declarations.");		}		/* In case the peer is already running, immediately try		   to establish a connection with it. */		status = dhcp_failover_link_initiate ((omapi_object_t *)state);		if (status != ISC_R_SUCCESS && status != ISC_R_INCOMPLETE) {#if defined (DEBUG_FAILOVER_TIMING)			log_info ("add_timeout +90 dhcp_failover_reconnect");#endif			add_timeout (cur_time + 90,				     dhcp_failover_reconnect, state,				     (tvref_t)				     dhcp_failover_state_reference,				     (tvunref_t)				     dhcp_failover_state_dereference);			log_error ("failover peer %s: %s", state -> name,				   isc_result_totext (status));		}		status = (dhcp_failover_listen			  ((omapi_object_t *)state));		if (status != ISC_R_SUCCESS) {#if defined (DEBUG_FAILOVER_TIMING)			log_info ("add_timeout +90 %s",				  "dhcp_failover_listener_restart");#endif			add_timeout (cur_time + 90,				     dhcp_failover_listener_restart,				     state,				     (tvref_t)omapi_object_reference,				     (tvunref_t)omapi_object_dereference);		}	}}int dhcp_failover_write_all_states (){	dhcp_failover_state_t *state;	for (state = failover_states; state; state = state -> next) {		if (!write_failover_state (state))			return 0;	}	return 1;}isc_result_t enter_failover_peer (peer)	dhcp_failover_state_t *peer;{	dhcp_failover_state_t *dup = (dhcp_failover_state_t *)0;	isc_result_t status;	status = find_failover_peer (&dup, peer -> name, MDL);	if (status == ISC_R_NOTFOUND) {		if (failover_states) {			dhcp_failover_state_reference (&peer -> next,						      failover_states, MDL);			dhcp_failover_state_dereference (&failover_states,							 MDL);		}		dhcp_failover_state_reference (&failover_states, peer, MDL);		return ISC_R_SUCCESS;	}	dhcp_failover_state_dereference (&dup, MDL);	if (status == ISC_R_SUCCESS)		return ISC_R_EXISTS;	return status;}isc_result_t find_failover_peer (peer, name, file, line)	dhcp_failover_state_t **peer;	const char *name;	const char *file;	int line;{	dhcp_failover_state_t *p;	for (p = failover_states; p; p = p -> next)		if (!strcmp (name, p -> name))			break;	if (p)		return dhcp_failover_state_reference (peer, p, file, line);	return ISC_R_NOTFOUND;}/* The failover protocol has three objects associated with it.  For   each failover partner declaration in the dhcpd.conf file, primary   or secondary, there is a failover_state object.  For any primary or   secondary state object that has a connection to its peer, there is   also a failover_link object, which has its own input state seperate   from the failover protocol state for managing the actual bytes   coming in off the wire.  Finally, there will be one listener object   for every distinct port number associated with a secondary   failover_state object.  Normally all secondary failover_state   objects are expected to listen on the same port number, so there   need be only one listener object, but if different port numbers are   specified for each failover object, there could be as many as one   listener object for each secondary failover_state object. *//* This, then, is the implemention of the failover link object. */isc_result_t dhcp_failover_link_initiate (omapi_object_t *h){	isc_result_t status;	dhcp_failover_link_t *obj;	omapi_value_t *value = (omapi_value_t *)0;	dhcp_failover_state_t *state;	omapi_object_t *o;	int i;	struct data_string ds;	omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;	omapi_addr_t local_addr;	/* Find the failover state in the object chain. */	for (o = h; o -> outer; o = o -> outer)		;	for (; o; o = o -> inner) {		if (o -> type == dhcp_type_failover_state)			break;	}	if (!o)		return ISC_R_INVALIDARG;	state = (dhcp_failover_state_t *)o;	obj = (dhcp_failover_link_t *)0;	status = dhcp_failover_link_allocate (&obj, MDL);	if (status != ISC_R_SUCCESS)		return status;	option_cache_reference (&obj -> peer_address,				state -> partner.address, MDL);	obj -> peer_port = state -> partner.port;	dhcp_failover_state_reference (&obj -> state_object, state, MDL);	memset (&ds, 0, sizeof ds);	if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,				    (struct client_state *)0,				    (struct option_state *)0,				    (struct option_state *)0,				    &global_scope, obj -> peer_address, MDL)) {		dhcp_failover_link_dereference (&obj, MDL);		return ISC_R_UNEXPECTED;	}	/* Make an omapi address list out of a buffer containing zero or more	   IPv4 addresses. */	status = omapi_addr_list_new (&addrs, ds.len / 4, MDL);	if (status != ISC_R_SUCCESS) {		dhcp_failover_link_dereference (&obj, MDL);		return status;	}	for (i = 0; i  < addrs -> count; i++) {		addrs -> addresses [i].addrtype = AF_INET;		addrs -> addresses [i].addrlen = sizeof (struct in_addr);		memcpy (addrs -> addresses [i].address,			&ds.data [i * 4], sizeof (struct in_addr));		addrs -> addresses [i].port = obj -> peer_port;	}	data_string_forget (&ds, MDL);	/* Now figure out the local address that we're supposed to use. */	if (!state -> me.address ||	    !evaluate_option_cache (&ds, (struct packet *)0,				    (struct lease *)0,				    (struct client_state *)0,				    (struct option_state *)0,				    (struct option_state *)0,				    &global_scope, state -> me.address,				    MDL)) {		memset (&local_addr, 0, sizeof local_addr);		local_addr.addrtype = AF_INET;		local_addr.addrlen = sizeof (struct in_addr);		if (!state -> server_identifier.len) {			log_fatal ("failover peer %s: no local address.",				   state -> name);		}	} else {		if (ds.len != sizeof (struct in_addr)) {			data_string_forget (&ds, MDL);			dhcp_failover_link_dereference (&obj, MDL);			omapi_addr_list_dereference (&addrs, MDL);			return ISC_R_INVALIDARG;		}		local_addr.addrtype = AF_INET;		local_addr.addrlen = ds.len;		memcpy (local_addr.address, ds.data, ds.len);		if (!state -> server_identifier.len)			data_string_copy (&state -> server_identifier,					  &ds, MDL);		data_string_forget (&ds, MDL);		local_addr.port = 0;  /* Let the O.S. choose. */	}	status = omapi_connect_list ((omapi_object_t *)obj,				     addrs, &local_addr);	omapi_addr_list_dereference (&addrs, MDL);	dhcp_failover_link_dereference (&obj, MDL);	return status;}isc_result_t dhcp_failover_link_signal (omapi_object_t *h,					const char *name, va_list ap){	isc_result_t status;	dhcp_failover_link_t *link;	omapi_object_t *c;	u_int16_t nlen;	u_int32_t vlen;	dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0;	if (h -> type != dhcp_type_failover_link) {		/* XXX shouldn't happen.   Put an assert here? */		return ISC_R_UNEXPECTED;	}	link = (dhcp_failover_link_t *)h;	if (!strcmp (name, "connect")) {	    if (link -> state_object -> i_am == primary) {		status = dhcp_failover_send_connect (h);		if (status != ISC_R_SUCCESS) {		    log_info ("dhcp_failover_send_connect: %s",			      isc_result_totext (status));		    omapi_disconnect (h -> outer, 1);		}	    } else		status = ISC_R_SUCCESS;	    /* Allow the peer fifteen seconds to send us a	       startup message. */#if defined (DEBUG_FAILOVER_TIMING)	    log_info ("add_timeout +15 %s",		      "dhcp_failover_link_startup_timeout");#endif	    add_timeout (cur_time + 15,			 dhcp_failover_link_startup_timeout,			 link,			 (tvref_t)dhcp_failover_link_reference,			 (tvunref_t)dhcp_failover_link_dereference);	    return status;	}	if (!strcmp (name, "disconnect")) {	    if (link -> state_object) {		dhcp_failover_state_reference (&state,					       link -> state_object, MDL);		link -> state = dhcp_flink_disconnected;		/* Make the transition. */		if (state -> link_to_peer == link) {		    dhcp_failover_state_transition (link -> state_object,						    name);		    /* Start trying to reconnect. */#if defined (DEBUG_FAILOVER_TIMING)		    log_info ("add_timeout +5 %s",			      "dhcp_failover_reconnect");#endif		    add_timeout (cur_time + 5, dhcp_failover_reconnect,				 state,				 (tvref_t)dhcp_failover_state_reference,				 (tvunref_t)dhcp_failover_state_dereference);		}		dhcp_failover_state_dereference (&state, MDL);	    }	    return ISC_R_SUCCESS;	}	/* Not a signal we recognize? */	if (strcmp (name, "ready")) {		if (h -> inner && h -> inner -> type -> signal_handler)			return (*(h -> inner -> type -> signal_handler))				(h -> inner, name, ap);		return ISC_R_NOTFOUND;	}	if (!h -> outer || h -> outer -> type != omapi_type_connection)		return ISC_R_INVALIDARG;	c = h -> outer;	/* We get here because we requested that we be woken up after           some number of bytes were read, and that number of bytes           has in fact been read. */	switch (link -> state) {	      case dhcp_flink_start:		link -> state = dhcp_flink_message_length_wait;		if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)			break;	      case dhcp_flink_message_length_wait:	      next_message:		link -> state = dhcp_flink_message_wait;		link -> imsg = dmalloc (sizeof (failover_message_t), MDL);		if (!link -> imsg) {			status = ISC_R_NOMEMORY;		      dhcp_flink_fail:			if (link -> imsg) {				failover_message_dereference (&link->imsg,							      MDL);			}			link -> state = dhcp_flink_disconnected;			log_info ("message length wait: %s",				  isc_result_totext (status));			omapi_disconnect (c, 1);			/* XXX just blow away the protocol state now?			   XXX or will disconnect blow it away? */			return ISC_R_UNEXPECTED;		}		memset (link -> imsg, 0, sizeof (failover_message_t));		link -> imsg -> refcnt = 1;		/* Get the length: */		omapi_connection_get_uint16 (c, &link -> imsg_len);		link -> imsg_count = 0;	/* Bytes read. */				/* Maximum of 2048 bytes in any failover message. */		if (link -> imsg_len > DHCP_FAILOVER_MAX_MESSAGE_SIZE) {			status = ISC_R_UNEXPECTED;			goto dhcp_flink_fail;		}		if ((omapi_connection_require (c, link -> imsg_len - 2U)) !=		    ISC_R_SUCCESS)			break;	      case dhcp_flink_message_wait:		/* Read in the message.  At this point we have the		   entire message in the input buffer.  For each		   incoming value ID, set a bit in the bitmask		   indicating that we've gotten it.  Maybe flag an		   error message if the bit is already set.  Once		   we're done reading, we can check the bitmask to		   make sure that the required fields for each message		   have been included. */		link -> imsg_count += 2;	/* Count the length as read. */		/* Get message type. */		omapi_connection_copyout (&link -> imsg -> type, c, 1);		link -> imsg_count++;		/* Get message payload offset. */		omapi_connection_copyout (&link -> imsg_payoff, c, 1);		link -> imsg_count++;		/* Get message time. */		omapi_connection_get_uint32 (c, &link -> imsg -> time);		link -> imsg_count += 4;		/* Get transaction ID. */		omapi_connection_get_uint32 (c, &link -> imsg -> xid);		link -> imsg_count += 4;#if defined (DEBUG_FAILOVER_MESSAGES)		log_info ("link: message %s  payoff %d  time %ld  xid %ld",			  dhcp_failover_message_name (link -> imsg -> type),			  link -> imsg_payoff,			  (unsigned long)link -> imsg -> time,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?