From d50d0b8289befe1f7d3d0ac06b8edb240963ab7e Mon Sep 17 00:00:00 2001 From: Ted Lemon Date: Sun, 14 Nov 1999 00:42:57 +0000 Subject: [PATCH] Backup commit - code isn't yet working. --- server/failover.c | 881 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 879 insertions(+), 2 deletions(-) diff --git a/server/failover.c b/server/failover.c index d2aa3f1d..4c221979 100644 --- a/server/failover.c +++ b/server/failover.c @@ -3,7 +3,7 @@ Failover protocol support code... */ /* - * Copyright (c) 1996-1999 Internet Software Consortium. + * Copyright (c) 1999-1999 Internet Software Consortium. * Use is subject to license terms which appear in the file named * ISC-LICENSE that should have accompanied this file when you * received it. If a file named ISC-LICENSE did not accompany this @@ -22,13 +22,15 @@ #ifndef lint static char copyright[] = -"$Id: failover.c,v 1.2 1999/03/16 05:50:46 mellon Exp $ Copyright (c) 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: failover.c,v 1.3 1999/11/14 00:42:57 mellon Exp $ Copyright (c) 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" #if defined (FAILOVER_PROTOCOL) static struct hash_table *failover_hash; +static isc_result_t do_a_failover_option (omapi_connection_object_t *, + dhcp_failover_link_t *); void enter_failover_peer (peer) struct failover_peer *peer; @@ -46,4 +48,879 @@ struct failover_peer *find_failover_peer (name) return peer; } +/* 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; + char *peer_name; + unsigned long port; + omapi_typed_data_t *value = (omapi_typed_data_t *)0; + + status = omapi_get_value_str (h, (omapi_object_t *)0, + "remote-port", &value); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_get_int_value (&port, value); + omapi_typed_data_dereference (&value, "dhcp_failover_link_initiate"); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_get_value_str (h, (omapi_object_t *)0, + "remote-peer", &value); + if (status != ISC_R_SUCCESS) + return status; + if (value -> type != omapi_datatype_string && + value -> type != omapu_datatype_data) { + omapi_typed_data_dereference (&value, + "dhcp_failover_link_initiate"); + return ISC_R_INVALIDARG; + } + + /* Save the name. */ + peer_name = malloc (value -> u.buffer.len + 1); + if (!peer_name) { + omapi_typed_data_dereference (&value, + "dhcp_failover_link_initiate"); + return ISC_R_NOMEMORY; + } + + memcpy (peer_name, value -> u.buffer.data, value -> u.buffer.len); + peer_name [value -> u.buffer.len] = 0; + omapi_typed_data_dereference (&value, "dhcp_failover_link_initiate"); + + obj = (dhcp_failover_link_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = dhcp_type_failover_link; + obj -> peer_name = peer_name; + obj -> port = port; + + status = omapi_connect ((omapi_object_t *)obj, server_name, port); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_link_initiate"); + return status; + } + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "dhcp_failover_link_initiate"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_link_initiate"); + return status; + } + status = omapi_object_reference (&obj -> inner, h, + "dhcp_failover_link_initiate"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_link_initiate"); + return status; + } + + /* Send the introductory message. */ + status = dhcp_failover_send_connect ((omapi_object_t *)obj); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_link_initiate"); + return status; + } + + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_accept"); + return ISC_R_SUCCESS; +} + +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; + + 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; + + /* Not a signal we recognize? */ + if (strcmp (name, "ready")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) (h, + name, + ap); + return ISC_R_NOTFOUND; + } + + if (!p -> outer || p -> outer -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = p -> 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 (p -> state) { + case dhcp_flink_start: + p -> state = dhcp_flink_message_length_wait; + if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS) + break; + case dhcp_flink_message_length_wait: + p -> state = dhcp_flink_message_wait; + memset (link -> incoming_message, 0, sizeof (link -> imsg)); + /* 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) { + dhcp_flink_fail: + link -> state = dhcp_flink_disconnected; + omapi_disconnect (c, 1); + /* XXX just blow away the protocol state now? + XXX or will disconnect blow it away? */ + return ISC_R_UNEXPECTED; + } + + if ((omapi_connection_require (c, link -> imsg_len)) != + 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; + + /* Skip over any portions of the message header that we + don't understand. */ + if (link -> payoff - link -> imsg_count) { + omapi_connection_copyout ((unsigned char *)0, c, + (link -> payoff - + link -> imsg_count)); + link -> imsg_count = link -> payoff; + } + + /* Get transaction ID. */ + omapi_connection_get_uint32 (c, &link -> imsg -> xid); + link -> imsg_count += 4; + + /* Now start sucking options off the wire. */ + while (link -> imsg_count < link -> imsg_len) { + if (do_a_failover_option (c, link) != ISC_R_SUCCESS) + goto dhcp_flink_fail; + } + + /* Once we have the entire message, and we've validated + it as best we can here, pass it to the parent. */ + omapi_signal_in (h -> outer, "message", link); + break; + + default: + /* XXX should never get here. Assertion? */ + break; + } + return ISC_R_SUCCESS; +} + +static isc_result_t do_a_failover_option (c, link) + omapi_connection_object_t *c; + dhcp_failover_link_t *link; +{ + u_int16_t option_code; + u_int16_t option_len; + char *op; + int op_size; + int op_count; + + if (link -> imsg_count + 2 > link -> imsg_len) { + log_error ("FAILOVER: message overflow at option code."); + return ISC_R_PROTOCOLERROR; + } + + /* Get option code. */ + omapi_connection_get_uint16 (c, &option_code); + link -> imsg_count += 2; + + /* Get option length. */ + omapi_connection_get_uint16 (c, &option_len); + link -> imsg_count += 2; + + if (link -> imsg_count + option_len > link -> imsg_len) { + log_error ("FAILOVER: message overflow at %s", + " length."); + return ISC_R_PROTOCOLERROR; + } + + /* If it's an unknown code, skip over it. */ + if (option_code > FTO_MAX) { +#if defined (FAILOVER_PROTOCOL_DEBUG) && defined (FAILOVER_DEBUG_VERBOSE) + log_debug (" option code %d len %d (not recognized)", + option_code, option_len); +#endif + omapi_connection_copyout ((unsigned char *)0, c, option_len); + link -> imsg_count = += option_len; + return ISC_R_SUCCESS; + } + + /* If it's the digest, do it now. */ + if (ft_options [option_code].type == FT_DIGEST) { + link -> imsg_count += option_len; + if (link -> imsg_count != link -> imsg_len) { + log_error ("FAILOVER: digest not at end of message"); + return ISC_R_PROTOCOLERROR; + } +#if defined (FAILOVER_PROTOCOL_DEBUG) && defined (FAILOVER_DEBUG_VERBOSE) + log_debug (" option %s len %d", + ft_options [option_code].name, option_len); +#endif + /* For now, just dump it. */ + omapi_connection_copyout ((unsigned char *)0, c, option_len); + return ISC_R_SUCCESS; + } + + /* Only accept an option once. */ + if (imsg -> options_present & ft_options [option_code].bit) { + log_error ("FAILOVER: duplicate option %s", + ft_options [option_code].name); + return ISC_R_PROTOCOLERROR; + } + + /* Make sure the option is appropriate for this type of message. + Really, any option is generally allowed for any message, and the + cases where this is not true are too complicated to represent in + this way - what this code is doing is to just avoid saving the + value of an option we don't have any way to use, which allows + us to make the failover_message structure smaller. */ + if (ft_options [option_code].bit && + !(fto_allowed [option_code] & ft_options [option_code].bit)) { + omapi_connection_copyout ((unsigned char *)0, c, option_len); + link -> imsg_count = += option_len; + return ISC_R_SUCCESS; + } + + /* Figure out how many elements, how big they are, and where + to store them. */ + if (ft_options [option_code].num_present) { + /* If this option takes a fixed number of elements, + we expect the space for them to be preallocated, + and we can just read the data in. */ + + op = ((char *)&link -> imsg) + ft_options [option_code].offset; + op_size = ft_sizes [ft_options [option_code].type]; + op_count = ft_options [option_code].num_present; + + if (option_length != op_size * op_count) { + log_error ("FAILOVER: option size (%d:%d), option %s", + option_length, + (ft_sizes [ft_options [option_code].type] * + ft_options [option_code].num_present), + ft_options [option_code].name); + return ISC_R_PROTOCOLERROR; + } + } else { + struct failover_option *fo; + + /* FT_DDNS* are special - one or two bytes of status + followed by the client FQDN. */ + if (ft_options [option_code].type == FT_DDNS1 || + ft_options [option_code].type == FT_DDNS1) { + struct failover_ddns *ddns = + ((struct failover_ddns *) + (((char *)&link -> imsg) + + ft_options [option_code].offset)); + + op_count = (ft_options [option_code].type == FT_DDNS1 + ? 1 : 2); + + omapi_connection_copyout (&ddns -> codes [0], + c, op_count); + if (op_count == 1) + ddns -> codes [1] = 0; + op_size = 1; + op_count = option_length - op_count; + + ddns -> length = op_count; + ddns -> data = malloc (op_count); + if (!ddns -> data) { + log_error ("FAILOVER: no memory getting%s(%d)", + " DNS data ", op_count); + + /* Actually, NO_MEMORY, but if we lose here + we have to drop the connection. */ + return ISC_R_PROTOCOLERROR; + } + omapi_connection_copyout (ddns -> data, c, op_count); + goto out; + } + } else { + /* A zero for num_present means that any number of + elements can appear, so we have to figure out how + many we got from the length of the option, and then + fill out a failover_option structure describing the + data. */ + op_size = ft_sizes [ft_options [option_code].type]; + + /* Make sure that option data length is a multiple of the + size of the data type being sent. */ + if (op_size > 1 && option_length % op_size) { + log_error ("FAILOVER: option_length %d not %s%d", + option_length, "multiple of ", option_size); + return ISC_R_PROTOCOLERROR; + } + + op_count = option_length / op_size; + + fo = ((struct failover_option *) + (((char *)&link -> imsg) + + ft_options [option_code].offset)); + + fo -> count = op_count; + fo -> data = malloc (option_length); + if (!fo -> data) { + log_error ("FAILOVER: no memory getting %s (%d)", + "option data", op_count); + + return ISC_R_PROTOCOLERROR; + } + op = fo -> data; + } + + /* For single-byte message values and multi-byte values that + don't need swapping, just read them in all at once. */ + if (op_size == 1 || ft_options [option_code].type == FT_IPADDR) { + omapi_connection_copyout ((unsigned char *)op, c, option_len); + goto out; + } + + /* For values that require swapping, read them in one at a time + using routines that swap bytes. */ + for (i = 0; i < op_count; i++) { + switch (ft_options [option_code].type) { + case FT_UINT32: + omapi_connection_get_uint32 (c, op); + op += 4; + break; + + case FT_UINT16: + omapi_connection_get_uint16 (c, op); + op += 2; + break; + + default: + /* Everything else should have been handled + already. */ + log_error ("FAILOVER: option %s: bad type %d", + ft_options [option_code].name, + ft_options [option_code].type); + return ISC_R_PROTOCOLERROR; + } + } + out: + /* Remember that we got this option. */ + link -> options_present |= ft_options [option_code].bit; + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_failover_link_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + /* Never valid to set these. */ + if (!omapi_ds_strcmp (name, "port") || + !omapi_ds_strcmp (name, "link-name") || + !omapi_ds_strcmp (name, "link-state")) + return ISC_R_NOPERM; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_failover_link_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + dhcp_failover_link_t *link; + + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + link = (dhcp_failover_link_t *)h; + + if (!omapi_ds_strcmp (name, "port")) { + return omapi_make_int_value (value, name, link -> port, + "dhcp_failover_link_get_value"); + } else if (!omapi_ds_strcmp (name, "link-name")) { + return omapi_make_string_value + (value, name, link -> peer_name, + "dhcp_failover_link_get_value"); + } else if (!omapi_ds_strcmp (name, "link-state")) { + if (link -> state < 0 || + link -> state >= dhcp_failover_link_state_max) + return omapi_make_string_value + (value, name, "invalid link state", + "dhcp_failover_link_get_value"); + return omapi_make_string_value + (value, name, + dhcp_failover_link_state_names [link -> state], + "dhcp_failover_link_get_value"); + } + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_failover_link_destroy (omapi_object_t *h, const char *name) +{ + dhcp_failover_link_t *p; + if (h -> type != dhcp_type_failover_link) + return ISC_R_INVALIDARG; + p = (dhcp_failover_link_object_t *)h; + if (p -> message) + omapi_object_dereference ((omapi_object_t **)&p -> message, + name); + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t dhcp_failover_link_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + dhcp_failover_link_t *link; + + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + link = (dhcp_failover_link_t *)h; + + status = omapi_connection_put_name (c, "port"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_put_uint32 (c, sizeof (int)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_put_uint32 (c, link -> port); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "link-name"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_string (c, link -> peer_name); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_name (c, "link-state"); + if (status != ISC_R_SUCCESS) + return status; + if (link -> state < 0 || + link -> state >= dhcp_failover_link_state_max) + status = omapi_connection_put_string (c, "invalid link state"); + else + status = (omapi_connection_put_string + (c, dhcp_failover_link_state_names [link -> state])); + if (status != ISC_R_SUCCESS) + return status; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + +/* Set up a listener for the omapi protocol. The handle stored points to + a listener object, not a protocol object. */ + +isc_result_t dhcp_failover_listen (omapi_object_t *h); +{ + isc_result_t status; + dhcp_failover_listener_object_t *obj; + unsigned long port; + omapi_value_t *value = (omapi_value_t *)0; + + status = omapi_get_value_str (h, (omapi_object_t *)0, + "local-port", &value); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_get_int_value (&port, value); + omapi_typed_data_dereference (&value, "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) + return status; + + obj = (dhcp_failover_listener_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = dhcp_type_failover_listener; + obj -> port = port; + + status = omapi_listen ((omapi_object_t *)obj, port, 1); + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listen"); + return status; + } + status = omapi_object_reference (&obj -> inner, h, + "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listen"); + return status; + } + + return status; +} + +/* Signal handler for protocol listener - if we get a connect signal, + create a new protocol connection, otherwise pass the signal down. */ + +isc_result_t dhcp_failover_listener_signal (omapi_object_t *o, + const char *name, va_list ap) +{ + isc_result_t status; + omapi_connection_object_t *c; + omapi_protocol_object_t *obj; + dhcp_failover_listener_object_t *p; + dhcp_failover_state_object_t *state; + char *peer_name; + + if (!o || o -> type != dhcp_type_failover_listener) + return ISC_R_INVALIDARG; + p = (dhcp_failover_listener_object_t *)o; + + /* Not a signal we recognize? */ + if (strcmp (name, "connect")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) + (p -> inner, name, ap); + return ISC_R_NOTFOUND; + } + + c = va_arg (ap, omapi_connection_object_t *); + if (!c || c -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + /* See if we can find a secondary failover_state object that + matches this connection. */ + for (state = states; state; state = state -> next) { + struct hostent *he; + int hix; + struct in_addr ia; + + if (inet_aton (state -> remote_peer, &ia)) { + if (ia == c -> remote_addr.sin_addr) + break; + } else { + he = gethostbyname (state -> remote_peer); + if (!he) + continue; + for (hix = 0; he -> h_addr_list [hix]; hix++) { + if (!memcmp (he -> h_addr_list [hix], + &c -> remote_addr.sin_addr, + sizeof c -> remote_addr.sin_addr)) + break; + } + if (he -> h_addr_list [hix]) + break; + } + } + + /* If we can't find a failover protocol state for this remote + host, drop the connection */ + if (!state) { + /* XXX Send a refusal message first? + XXX Look in protocol spec for guidance. */ + /* XXX An error message from a connect signal should + XXX drop the connection - make sure this is what + XXX actually happens! */ + return ISC_R_INVALIDARG; + } + + obj = (omapi_protocol_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = omapi_type_protocol; + peer_name = malloc (strlen (state -> remote_peer) + 1); + if (!peer_name) + return ISC_R_NOMEMORY; + strcpy (peer_name, state -> remote_peer); + obj -> peer_name = peer_name; + obj -> port = ntohs (c -> remote_addr.sin_port); + + status = omapi_object_reference (&obj -> outer, c, + "dhcp_failover_listener_signal"); + if (status != ISC_R_SUCCESS) { + lose: + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listener_signal"); + omapi_disconnect (c, 1); + return status; + } + + status = omapi_object_reference (&c -> inner, (omapi_object_t *)obj, + "dhcp_failover_listener_signal"); + if (status != ISC_R_SUCCESS) + goto lose; + + /* Notify the master state machine of the arrival of a new + connection. */ + status = omapi_signal (state, "connect", obj); + if (status != ISC_R_SUCCESS) + goto lose; + + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listener_signal"); + return status; +} + +isc_result_t dhcp_failover_listener_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != dhcp_type_failover_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_failover_listener_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != dhcp_type_failover_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_failover_listener_destroy (omapi_object_t *h, + const char *name) +{ + if (h -> type != dhcp_type_failover_listener) + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t dhcp_failover_listener_stuff (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + int i; + + if (p -> type != dhcp_type_failover_listener) + return ISC_R_INVALIDARG; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + +/* Set up master state machine for the failover protocol. */ + +isc_result_t dhcp_failover_register (omapi_object_t *h); +{ + isc_result_t status; + dhcp_failover_state_object_t *obj; + unsigned long port; + omapi_value_t *value = (omapi_value_t *)0; + + status = omapi_get_value_str (h, (omapi_object_t *)0, + "local-port", &value); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_get_int_value (&port, value); + omapi_typed_data_dereference (&value, "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) + return status; + + obj = (dhcp_failover_state_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = dhcp_type_failover_state; + obj -> port = port; + + status = omapi_listen ((omapi_object_t *)obj, port, 1); + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listen"); + return status; + } + status = omapi_object_reference (&obj -> inner, h, + "dhcp_failover_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "dhcp_failover_listen"); + return status; + } + + return status; +} + +/* Signal handler for protocol state machine. */ + +isc_result_t dhcp_failover_state_signal (omapi_object_t *o, + const char *name, va_list ap) +{ + isc_result_t status; + omapi_connection_object_t *c; + omapi_protocol_object_t *obj; + dhcp_failover_state_object_t *p; + dhcp_failover_state_object_t *state; + char *peer_name; + + if (!o || o -> type != dhcp_type_failover_state) + return ISC_R_INVALIDARG; + p = (dhcp_failover_state_object_t *)o; + + /* Not a signal we recognize? */ + if (strcmp (name, "connect") && + strcmp (name, "disconnect") && + strcmp (name, "message")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) + (p -> inner, name, ap); + return ISC_R_NOTFOUND; + } + + +} + +isc_result_t dhcp_failover_state_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != dhcp_type_failover_state) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_failover_state_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != dhcp_type_failover_state) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_failover_state_destroy (omapi_object_t *h, + const char *name) +{ + if (h -> type != dhcp_type_failover_state) + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t dhcp_failover_state_stuff (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + int i; + + if (p -> type != dhcp_type_failover_state) + return ISC_R_INVALIDARG; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + + #endif /* defined (FAILOVER_PROTOCOL) */