📄 failover.c
字号:
/* failover.c Failover protocol support code... *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * <info@isc.org> * http://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems 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.32 2004/06/22 20:46:23 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"#include "version.h"#include <omapip/omapip_p.h>#if defined (FAILOVER_PROTOCOL)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, (unsigned long)link -> imsg -> xid);#endif /* Skip over any portions of the message header that we don't understand. */ if (link -> imsg_payoff - link -> imsg_count) { omapi_connection_copyout ((unsigned char *)0, c, (link -> imsg_payoff - link -> imsg_count)); link -> imsg_count = link -> imsg_payoff; } /* Now start sucking options off the wire. */ while (link -> imsg_count < link -> imsg_len) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -