diff --git a/exec/mainconfig.c b/exec/mainconfig.c index 7dc7a280..a11fc50a 100644 --- a/exec/mainconfig.c +++ b/exec/mainconfig.c @@ -1,517 +1,517 @@ /* * Copyright (c) 2002-2005 MontaVista Software, Inc. * Copyright (c) 2006-2009 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "mainconfig.h" #include "mempool.h" static char error_string_response[512]; static struct objdb_iface_ver0 *global_objdb; static void add_logsys_config_notification( struct objdb_iface_ver0 *objdb, struct main_config *main_config); /* This just makes the code below a little neater */ static inline int objdb_get_string ( - struct objdb_iface_ver0 *objdb, + const struct objdb_iface_ver0 *objdb, hdb_handle_t object_service_handle, const char *key, char **value) { int res; *value = NULL; if ( !(res = objdb->object_key_get (object_service_handle, key, strlen (key), (void *)value, NULL))) { if (*value) { return 0; } } return -1; } static inline void objdb_get_int ( - struct objdb_iface_ver0 *objdb, + const struct objdb_iface_ver0 *objdb, hdb_handle_t object_service_handle, char *key, unsigned int *intvalue) { char *value = NULL; if (!objdb->object_key_get (object_service_handle, key, strlen (key), (void *)&value, NULL)) { if (value) { *intvalue = atoi(value); } } } /** * insert_into_buffer * @target_buffer: a buffer where to write results * @bufferlen: tell us the size of the buffer to avoid overflows * @entry: entry that needs to be added to the buffer * @after: can either be NULL or set to a string. * if NULL, @entry is prependend to logsys_format_get buffer. * if set, @entry is added immediately after @after. * * Since the function is specific to logsys_format_get handling, it is implicit * that source is logsys_format_get(); * * In case of failure, target_buffer could be left dirty. So don't trust * any data leftover in it. * * Searching for "after" assumes that there is only entry of "after" * in the source. Afterall we control the string here and for logging format * it makes little to no sense to have duplicate format entries. * * Returns: 0 on success, -1 on failure **/ static int insert_into_buffer( char *target_buffer, size_t bufferlen, const char *entry, const char *after) { const char *current_format = NULL; current_format = logsys_format_get(); /* if the entry is already in the format we don't add it again */ if (strstr(current_format, entry) != NULL) { return -1; } /* if there is no "after", simply prepend the requested entry * otherwise go for beautiful string manipulation.... */ if (!after) { if (snprintf(target_buffer, bufferlen - 1, "%s%s", entry, current_format) >= bufferlen - 1) { return -1; } } else { const char *afterpos; size_t afterlen; size_t templen; /* check if after is contained in the format * and afterlen has a meaning or return an error */ afterpos = strstr(current_format, after); afterlen = strlen(after); if ((!afterpos) || (!afterlen)) { return -1; } templen = afterpos - current_format + afterlen; if (snprintf(target_buffer, templen + 1, "%s", current_format) >= bufferlen - 1) { return -1; } if (snprintf(target_buffer + templen, bufferlen - ( templen + 1 ), "%s%s", entry, current_format + templen) >= bufferlen - ( templen + 1 )) { return -1; } } return 0; } static struct logsys_config_struct { char subsys[6]; unsigned int priority; unsigned int tags; } logsys_logger; int corosync_main_config_read_logging ( struct objdb_iface_ver0 *objdb, const char **error_string, struct main_config *main_config) { hdb_handle_t object_service_handle; hdb_handle_t object_logger_subsys_handle; char *value; const char *error_reason = error_string_response; hdb_handle_t object_find_handle; hdb_handle_t object_find_logsys_handle; char new_format_buffer[PATH_MAX]; int err = 0; objdb->object_find_create ( OBJECT_PARENT_HANDLE, "logging", strlen ("logging"), &object_find_handle); main_config->logmode = LOG_MODE_THREADED | LOG_MODE_FORK; if (objdb->object_find_next ( object_find_handle, &object_service_handle) == 0) { if (!objdb_get_string (objdb,object_service_handle, "to_file", &value)) { if (strcmp (value, "yes") == 0) { main_config->logmode |= LOG_MODE_OUTPUT_FILE; } else if (strcmp (value, "no") == 0) { main_config->logmode &= ~LOG_MODE_OUTPUT_FILE; } } if (!objdb_get_string (objdb,object_service_handle, "to_syslog", &value)) { if (strcmp (value, "yes") == 0) { main_config->logmode |= LOG_MODE_OUTPUT_SYSLOG; } else if (strcmp (value, "no") == 0) { main_config->logmode &= ~LOG_MODE_OUTPUT_SYSLOG; } } if (!objdb_get_string (objdb,object_service_handle, "to_stderr", &value)) { if (strcmp (value, "yes") == 0) { main_config->logmode |= LOG_MODE_OUTPUT_STDERR; } else if (strcmp (value, "no") == 0) { main_config->logmode &= ~LOG_MODE_OUTPUT_STDERR; } } if (!objdb_get_string (objdb,object_service_handle, "fileline", &value)) { if (strcmp (value, "on") == 0) { if (!insert_into_buffer(new_format_buffer, sizeof(new_format_buffer), " %f:%l", "s]")) { err = logsys_format_set(new_format_buffer); } else if (!insert_into_buffer(new_format_buffer, sizeof(new_format_buffer), "%f:%l", NULL)) { err = logsys_format_set(new_format_buffer); } } else if (strcmp (value, "off") == 0) { /* nothing to do here */ } else { goto parse_error; } } if (!objdb_get_string (objdb,object_service_handle, "function_name", &value)) { if (strcmp (value, "on") == 0) { if (!insert_into_buffer(new_format_buffer, sizeof(new_format_buffer), "%n:", "f:")) { err = logsys_format_set(new_format_buffer); } else if (!insert_into_buffer(new_format_buffer, sizeof(new_format_buffer), " %n", "s]")) { err = logsys_format_set(new_format_buffer); } } else if (strcmp (value, "off") == 0) { /* nothing to do here */ } else { goto parse_error; } } if (!objdb_get_string (objdb,object_service_handle, "timestamp", &value)) { if (strcmp (value, "on") == 0) { if(!insert_into_buffer(new_format_buffer, sizeof(new_format_buffer), "%t ", NULL)) { err = logsys_format_set(new_format_buffer); } } else if (strcmp (value, "off") == 0) { /* nothing to do here */ } else { goto parse_error; } } if (err) { error_reason = "exhausted virtual memory"; goto parse_error; } /* free old string on reload */ if (main_config->logfile) { free(main_config->logfile); main_config->logfile = NULL; } if (!objdb_get_string (objdb,object_service_handle, "logfile", &value)) { main_config->logfile = strdup (value); } if (!objdb_get_string (objdb,object_service_handle, "syslog_facility", &value)) { main_config->syslog_facility = logsys_facility_id_get(value); if (main_config->syslog_facility < 0) { error_reason = "unknown syslog facility specified"; goto parse_error; } } logsys_config_facility_set ("corosync", main_config->syslog_facility); logsys_config_mode_set (main_config->logmode); logsys_config_file_set (error_string, main_config->logfile); objdb->object_find_create ( object_service_handle, "logger_subsys", strlen ("logger_subsys"), &object_find_logsys_handle); while (objdb->object_find_next ( object_find_logsys_handle, &object_logger_subsys_handle) == 0) { if (!objdb_get_string (objdb, object_logger_subsys_handle, "subsys", &value)) { strncpy (logsys_logger.subsys, value, sizeof (logsys_logger.subsys)); } else { error_reason = "subsys required for logger directive"; goto parse_error; } if (!objdb_get_string (objdb, object_logger_subsys_handle, "syslog_level", &value)) { logsys_logger.priority = logsys_priority_id_get(value); if (logsys_logger.priority < 0) { error_reason = "unknown syslog priority specified"; goto parse_error; } } if (!objdb_get_string (objdb, object_logger_subsys_handle, "debug", &value)) { if (strcmp (value, "on") == 0) { logsys_logger.priority = LOG_LEVEL_DEBUG; } else if (strcmp (value, "off") == 0) { logsys_logger.priority &= ~LOG_LEVEL_DEBUG; } else { goto parse_error; } } if (!objdb_get_string (objdb, object_logger_subsys_handle, "tags", &value)) { char *token = strtok (value, "|"); while (token != NULL) { int val; val = logsys_tag_id_get(token); if (val < 0) { error_reason = "bad tags value"; goto parse_error; } logsys_logger.tags |= val; token = strtok(NULL, "|"); } } /* * set individual logger configurations */ logsys_config_subsys_set ( logsys_logger.subsys, logsys_logger.tags, logsys_logger.priority); } objdb->object_find_destroy (object_find_logsys_handle); } objdb->object_find_destroy (object_find_handle); return 0; parse_error: snprintf (error_string_response, sizeof(error_string_response), "parse error in config: %s.\n", error_reason); *error_string = error_string_response; return (-1); } static int uid_determine (const char *req_user) { struct passwd *passwd; int ais_uid = 0; passwd = getpwnam(req_user); if (passwd == 0) { log_printf (LOG_LEVEL_ERROR, "ERROR: The '%s' user is not found in /etc/passwd, please read the documentation.\n", req_user); corosync_exit_error (AIS_DONE_UID_DETERMINE); } ais_uid = passwd->pw_uid; endpwent (); return ais_uid; } static int gid_determine (const char *req_group) { struct group *group; int ais_gid = 0; group = getgrnam (req_group); if (group == 0) { log_printf (LOG_LEVEL_ERROR, "ERROR: The '%s' group is not found in /etc/group, please read the documentation.\n", req_group); corosync_exit_error (AIS_DONE_GID_DETERMINE); } ais_gid = group->gr_gid; endgrent (); return ais_gid; } int corosync_main_config_read ( struct objdb_iface_ver0 *objdb, const char **error_string, struct main_config *main_config) { hdb_handle_t object_service_handle; char *value; const char *error_reason = error_string_response; hdb_handle_t object_find_handle; memset (main_config, 0, sizeof (struct main_config)); corosync_main_config_read_logging(objdb, error_string, main_config); objdb->object_find_create ( OBJECT_PARENT_HANDLE, "aisexec", strlen ("aisexec"), &object_find_handle); main_config->uid = uid_determine("ais"); main_config->gid = gid_determine("ais"); if (objdb->object_find_next ( object_find_handle, &object_service_handle) == 0) { if (!objdb_get_string (objdb,object_service_handle, "user", &value)) { main_config->uid = uid_determine(value); } if (!objdb_get_string (objdb,object_service_handle, "group", &value)) { main_config->gid = gid_determine(value); } } objdb->object_find_destroy (object_find_handle); if ((main_config->logmode & LOG_MODE_OUTPUT_FILE) && (main_config->logfile == NULL)) { error_reason = "logmode set to 'file' but no logfile specified"; goto parse_error; } if (main_config->syslog_facility == 0) main_config->syslog_facility = LOG_DAEMON; add_logsys_config_notification(objdb, main_config); logsys_fork_completed (); return 0; parse_error: snprintf (error_string_response, sizeof(error_string_response), "parse error in config: %s.\n", error_reason); *error_string = error_string_response; return (-1); } static void main_objdb_reload_notify(objdb_reload_notify_type_t type, int flush, void *priv_data_pt) { struct main_config *main_config = priv_data_pt; const char *error_string; if (type == OBJDB_RELOAD_NOTIFY_END) { /* * Reload the logsys configuration */ logsys_format_set(NULL); corosync_main_config_read_logging(global_objdb, &error_string, main_config); } } static void add_logsys_config_notification( struct objdb_iface_ver0 *objdb, struct main_config *main_config) { global_objdb = objdb; objdb->object_track_start(OBJECT_PARENT_HANDLE, 1, NULL, NULL, NULL, main_objdb_reload_notify, main_config); } diff --git a/exec/totemconfig.c b/exec/totemconfig.c index 7bfdc622..be9d7008 100644 --- a/exec/totemconfig.c +++ b/exec/totemconfig.c @@ -1,798 +1,798 @@ /* * Copyright (c) 2002-2005 MontaVista Software, Inc. * Copyright (c) 2006-2009 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "totemconfig.h" #include "tlist.h" /* for HZ */ #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4 #define TOKEN_TIMEOUT 1000 #define TOKEN_RETRANSMIT_TIMEOUT (int)(TOKEN_TIMEOUT / (TOKEN_RETRANSMITS_BEFORE_LOSS_CONST + 0.2)) #define TOKEN_HOLD_TIMEOUT (int)(TOKEN_RETRANSMIT_TIMEOUT * 0.8 - (1000/(int)HZ)) #define JOIN_TIMEOUT 50 #define CONSENSUS_TIMEOUT 800 #define MERGE_TIMEOUT 200 #define DOWNCHECK_TIMEOUT 1000 #define FAIL_TO_RECV_CONST 50 #define SEQNO_UNCHANGED_CONST 30 #define MINIMUM_TIMEOUT (int)(1000/HZ)*3 #define MAX_NETWORK_DELAY 50 #define WINDOW_SIZE 50 #define MAX_MESSAGES 17 #define RRP_PROBLEM_COUNT_TIMEOUT 2000 #define RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT 10 #define RRP_PROBLEM_COUNT_THRESHOLD_MIN 5 static char error_string_response[512]; static struct objdb_iface_ver0 *global_objdb; static void add_totem_config_notification( struct objdb_iface_ver0 *objdb, struct totem_config *totem_config, hdb_handle_t totem_object_handle); /* These just makes the code below a little neater */ static inline int objdb_get_string ( - struct objdb_iface_ver0 *objdb, + const struct objdb_iface_ver0 *objdb, hdb_handle_t object_service_handle, const char *key, const char **value) { int res; *value = NULL; if ( !(res = objdb->object_key_get (object_service_handle, key, strlen (key), (void *)value, NULL))) { if (*value) { return 0; } } return -1; } static inline void objdb_get_int ( - struct objdb_iface_ver0 *objdb, + const struct objdb_iface_ver0 *objdb, hdb_handle_t object_service_handle, const char *key, unsigned int *intvalue) { char *value = NULL; if (!objdb->object_key_get (object_service_handle, key, strlen (key), (void *)&value, NULL)) { if (value) { *intvalue = atoi(value); } } } static unsigned int totem_handle_find ( struct objdb_iface_ver0 *objdb, hdb_handle_t *totem_find_handle) { hdb_handle_t object_find_handle; unsigned int res; /* * Find a network section */ objdb->object_find_create ( OBJECT_PARENT_HANDLE, "network", strlen ("network"), &object_find_handle); res = objdb->object_find_next ( object_find_handle, totem_find_handle); objdb->object_find_destroy (object_find_handle); /* * Network section not found in configuration, checking for totem */ if (res == -1) { objdb->object_find_create ( OBJECT_PARENT_HANDLE, "totem", strlen ("totem"), &object_find_handle); res = objdb->object_find_next ( object_find_handle, totem_find_handle); objdb->object_find_destroy (object_find_handle); } if (res == -1) { return (-1); } return (0); } static void totem_volatile_config_read ( struct objdb_iface_ver0 *objdb, struct totem_config *totem_config, hdb_handle_t object_totem_handle) { objdb_get_int (objdb,object_totem_handle, "token", &totem_config->token_timeout); objdb_get_int (objdb,object_totem_handle, "token_retransmit", &totem_config->token_retransmit_timeout); objdb_get_int (objdb,object_totem_handle, "hold", &totem_config->token_hold_timeout); objdb_get_int (objdb,object_totem_handle, "token_retransmits_before_loss_const", &totem_config->token_retransmits_before_loss_const); objdb_get_int (objdb,object_totem_handle, "join", &totem_config->join_timeout); objdb_get_int (objdb,object_totem_handle, "send_join", &totem_config->send_join_timeout); objdb_get_int (objdb,object_totem_handle, "consensus", &totem_config->consensus_timeout); objdb_get_int (objdb,object_totem_handle, "merge", &totem_config->merge_timeout); objdb_get_int (objdb,object_totem_handle, "downcheck", &totem_config->downcheck_timeout); objdb_get_int (objdb,object_totem_handle, "fail_recv_const", &totem_config->fail_to_recv_const); objdb_get_int (objdb,object_totem_handle, "seqno_unchanged_const", &totem_config->seqno_unchanged_const); objdb_get_int (objdb,object_totem_handle, "rrp_token_expired_timeout", &totem_config->rrp_token_expired_timeout); objdb_get_int (objdb,object_totem_handle, "rrp_problem_count_timeout", &totem_config->rrp_problem_count_timeout); objdb_get_int (objdb,object_totem_handle, "rrp_problem_count_threshold", &totem_config->rrp_problem_count_threshold); objdb_get_int (objdb,object_totem_handle, "heartbeat_failures_allowed", &totem_config->heartbeat_failures_allowed); objdb_get_int (objdb,object_totem_handle, "max_network_delay", &totem_config->max_network_delay); objdb_get_int (objdb,object_totem_handle, "window_size", &totem_config->window_size); objdb_get_string (objdb, object_totem_handle, "vsftype", &totem_config->vsf_type); objdb_get_int (objdb,object_totem_handle, "max_messages", &totem_config->max_messages); } extern int totem_config_read ( struct objdb_iface_ver0 *objdb, struct totem_config *totem_config, const char **error_string) { int res = 0; hdb_handle_t object_totem_handle; hdb_handle_t object_interface_handle; const char *str; unsigned int ringnumber = 0; hdb_handle_t object_find_interface_handle; res = totem_handle_find (objdb, &object_totem_handle); if (res == -1) { printf ("couldn't find totem handle\n"); return (-1); } memset (totem_config, 0, sizeof (struct totem_config)); totem_config->interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX); if (totem_config->interfaces == 0) { *error_string = "Out of memory trying to allocate ethernet interface storage area"; return -1; } memset (totem_config->interfaces, 0, sizeof (struct totem_interface) * INTERFACE_MAX); totem_config->secauth = 1; strcpy (totem_config->rrp_mode, "none"); if (!objdb_get_string (objdb, object_totem_handle, "version", &str)) { if (strcmp (str, "2") == 0) { totem_config->version = 2; } } if (!objdb_get_string (objdb, object_totem_handle, "secauth", &str)) { if (strcmp (str, "on") == 0) { totem_config->secauth = 1; } if (strcmp (str, "off") == 0) { totem_config->secauth = 0; } } if (!objdb_get_string (objdb, object_totem_handle, "rrp_mode", &str)) { strcpy (totem_config->rrp_mode, str); } /* * Get interface node id */ objdb_get_int (objdb, object_totem_handle, "nodeid", &totem_config->node_id); objdb_get_int (objdb,object_totem_handle, "threads", &totem_config->threads); objdb_get_int (objdb,object_totem_handle, "netmtu", &totem_config->net_mtu); /* * Get things that might change in the future */ totem_volatile_config_read (objdb, totem_config, object_totem_handle); objdb->object_find_create ( object_totem_handle, "interface", strlen ("interface"), &object_find_interface_handle); while (objdb->object_find_next ( object_find_interface_handle, &object_interface_handle) == 0) { objdb_get_int (objdb, object_interface_handle, "ringnumber", &ringnumber); /* * Get interface multicast address */ if (!objdb_get_string (objdb, object_interface_handle, "mcastaddr", &str)) { res = totemip_parse (&totem_config->interfaces[ringnumber].mcast_addr, str, 0); } /* * Get mcast port */ if (!objdb_get_string (objdb, object_interface_handle, "mcastport", &str)) { totem_config->interfaces[ringnumber].ip_port = atoi (str); } /* * Get the bind net address */ if (!objdb_get_string (objdb, object_interface_handle, "bindnetaddr", &str)) { res = totemip_parse (&totem_config->interfaces[ringnumber].bindnet, str, totem_config->interfaces[ringnumber].mcast_addr.family); } totem_config->interface_count++; } objdb->object_find_destroy (object_find_interface_handle); add_totem_config_notification(objdb, totem_config, object_totem_handle); return 0; } int totem_config_validate ( struct totem_config *totem_config, const char **error_string) { static char local_error_reason[512]; char parse_error[512]; const char *error_reason = local_error_reason; int i; unsigned int interface_max = INTERFACE_MAX; if (totem_config->interface_count == 0) { error_reason = "No interfaces defined"; goto parse_error; } for (i = 0; i < totem_config->interface_count; i++) { /* * Some error checking of parsed data to make sure its valid */ if ((int *)&totem_config->interfaces[i].mcast_addr.addr == 0) { error_reason = "No multicast address specified"; goto parse_error; } if (totem_config->interfaces[i].ip_port == 0) { error_reason = "No multicast port specified"; goto parse_error; } if (totem_config->interfaces[i].mcast_addr.family == AF_INET6 && totem_config->node_id == 0) { error_reason = "An IPV6 network requires that a node ID be specified."; goto parse_error; } if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) { error_reason = "Multicast address family does not match bind address family"; goto parse_error; } if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) { error_reason = "Not all bind address belong to the same IP family"; goto parse_error; } } if (totem_config->version != 2) { error_reason = "This totem parser can only parse version 2 configurations."; goto parse_error; } if (totem_config->token_retransmits_before_loss_const == 0) { totem_config->token_retransmits_before_loss_const = TOKEN_RETRANSMITS_BEFORE_LOSS_CONST; } /* * Setup timeout values that are not setup by user */ if (totem_config->token_timeout == 0) { totem_config->token_timeout = TOKEN_TIMEOUT; if (totem_config->token_retransmits_before_loss_const == 0) { totem_config->token_retransmits_before_loss_const = TOKEN_RETRANSMITS_BEFORE_LOSS_CONST; } if (totem_config->token_retransmit_timeout == 0) { totem_config->token_retransmit_timeout = (int)(totem_config->token_timeout / (totem_config->token_retransmits_before_loss_const + 0.2)); } if (totem_config->token_hold_timeout == 0) { totem_config->token_hold_timeout = (int)(totem_config->token_retransmit_timeout * 0.8 - (1000/HZ)); } } if (totem_config->max_network_delay == 0) { totem_config->max_network_delay = MAX_NETWORK_DELAY; } if (totem_config->max_network_delay < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The max_network_delay parameter (%d ms) may not be less then (%d ms).", totem_config->max_network_delay, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->window_size == 0) { totem_config->window_size = WINDOW_SIZE; } if (totem_config->max_messages == 0) { totem_config->max_messages = MAX_MESSAGES; } if (totem_config->token_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The token timeout parameter (%d ms) may not be less then (%d ms).", totem_config->token_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->token_retransmit_timeout == 0) { totem_config->token_retransmit_timeout = (int)(totem_config->token_timeout / (totem_config->token_retransmits_before_loss_const + 0.2)); } if (totem_config->token_hold_timeout == 0) { totem_config->token_hold_timeout = (int)(totem_config->token_retransmit_timeout * 0.8 - (1000/HZ)); } if (totem_config->token_retransmit_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The token retransmit timeout parameter (%d ms) may not be less then (%d ms).", totem_config->token_retransmit_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->token_hold_timeout == 0) { totem_config->token_hold_timeout = TOKEN_HOLD_TIMEOUT; } if (totem_config->token_hold_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The token hold timeout parameter (%d ms) may not be less then (%d ms).", totem_config->token_hold_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->join_timeout == 0) { totem_config->join_timeout = JOIN_TIMEOUT; } if (totem_config->join_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The join timeout parameter (%d ms) may not be less then (%d ms).", totem_config->join_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->consensus_timeout == 0) { totem_config->consensus_timeout = CONSENSUS_TIMEOUT; } if (totem_config->consensus_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The consensus timeout parameter (%d ms) may not be less then (%d ms).", totem_config->consensus_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->merge_timeout == 0) { totem_config->merge_timeout = MERGE_TIMEOUT; } if (totem_config->merge_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The merge timeout parameter (%d ms) may not be less then (%d ms).", totem_config->merge_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->downcheck_timeout == 0) { totem_config->downcheck_timeout = DOWNCHECK_TIMEOUT; } if (totem_config->downcheck_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The downcheck timeout parameter (%d ms) may not be less then (%d ms).", totem_config->downcheck_timeout, MINIMUM_TIMEOUT); goto parse_error; } /* * RRP values validation */ if (strcmp (totem_config->rrp_mode, "none") && strcmp (totem_config->rrp_mode, "active") && strcmp (totem_config->rrp_mode, "passive")) { snprintf (local_error_reason, sizeof(local_error_reason), "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config->rrp_mode); goto parse_error; } if (totem_config->rrp_problem_count_timeout == 0) { totem_config->rrp_problem_count_timeout = RRP_PROBLEM_COUNT_TIMEOUT; } if (totem_config->rrp_problem_count_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The RRP problem count timeout parameter (%d ms) may not be less then (%d ms).", totem_config->rrp_problem_count_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (totem_config->rrp_problem_count_threshold == 0) { totem_config->rrp_problem_count_threshold = RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT; } if (totem_config->rrp_problem_count_threshold < RRP_PROBLEM_COUNT_THRESHOLD_MIN) { snprintf (local_error_reason, sizeof(local_error_reason), "The RRP problem count threshold (%d problem count) may not be less then (%d problem count).", totem_config->rrp_problem_count_threshold, RRP_PROBLEM_COUNT_THRESHOLD_MIN); goto parse_error; } if (totem_config->rrp_token_expired_timeout == 0) { totem_config->rrp_token_expired_timeout = totem_config->token_retransmit_timeout; } if (totem_config->rrp_token_expired_timeout < MINIMUM_TIMEOUT) { snprintf (local_error_reason, sizeof(local_error_reason), "The RRP token expired timeout parameter (%d ms) may not be less then (%d ms).", totem_config->rrp_token_expired_timeout, MINIMUM_TIMEOUT); goto parse_error; } if (strcmp (totem_config->rrp_mode, "none") == 0) { interface_max = 1; } if (interface_max < totem_config->interface_count) { snprintf (parse_error, sizeof(parse_error), "%d is too many configured interfaces for the rrp_mode setting %s.", totem_config->interface_count, totem_config->rrp_mode); error_reason = parse_error; goto parse_error; } if (totem_config->fail_to_recv_const == 0) { totem_config->fail_to_recv_const = FAIL_TO_RECV_CONST; } if (totem_config->seqno_unchanged_const == 0) { totem_config->seqno_unchanged_const = SEQNO_UNCHANGED_CONST; } if (totem_config->net_mtu == 0) { totem_config->net_mtu = 1500; } if ((MESSAGE_QUEUE_MAX) < totem_config->max_messages) { snprintf (local_error_reason, sizeof(local_error_reason), "The max_messages parameter (%d messages) may not be greater then (%d messages).", totem_config->max_messages, MESSAGE_QUEUE_MAX); goto parse_error; } if (totem_config->threads > SEND_THREADS_MAX) { totem_config->threads = SEND_THREADS_MAX; } if (totem_config->secauth == 0) { totem_config->threads = 0; } if (totem_config->net_mtu > FRAME_SIZE_MAX) { error_reason = "This net_mtu parameter is greater then the maximum frame size"; goto parse_error; } if (totem_config->vsf_type == NULL) { totem_config->vsf_type = "none"; } return (0); parse_error: snprintf (error_string_response, sizeof(error_string_response), "parse error in config: %s\n", error_reason); *error_string = error_string_response; return (-1); } static int read_keyfile ( const char *key_location, struct totem_config *totem_config, const char **error_string) { int fd; int res; ssize_t expected_key_len = sizeof (totem_config->private_key); int saved_errno; fd = open (key_location, O_RDONLY); if (fd == -1) { snprintf (error_string_response, sizeof(error_string_response), "Could not open %s: %s\n", key_location, strerror (errno)); goto parse_error; } res = read (fd, totem_config->private_key, expected_key_len); saved_errno = errno; close (fd); if (res == -1) { snprintf (error_string_response, sizeof(error_string_response), "Could not read %s: %s\n", key_location, strerror (saved_errno)); goto parse_error; } totem_config->private_key_len = expected_key_len; if (res != expected_key_len) { snprintf (error_string_response, sizeof(error_string_response), "Could only read %d bits of 1024 bits from %s.\n", res * 8, key_location); goto parse_error; } return 0; parse_error: *error_string = error_string_response; return (-1); } int totem_config_keyread ( struct objdb_iface_ver0 *objdb, struct totem_config *totem_config, const char **error_string) { int got_key = 0; const char *key_location = NULL; hdb_handle_t object_totem_handle; int res; memset (totem_config->private_key, 0, 128); totem_config->private_key_len = 128; if (totem_config->secauth == 0) { return (0); } res = totem_handle_find (objdb, &object_totem_handle); if (res == -1) { return (-1); } /* objdb may store the location of the key file */ if (!objdb_get_string (objdb,object_totem_handle, "keyfile", &key_location) && key_location) { res = read_keyfile(key_location, totem_config, error_string); if (res) { goto key_error; } got_key = 1; } else { /* Or the key itself may be in the objdb */ char *key = NULL; - int key_len; + size_t key_len; res = objdb->object_key_get (object_totem_handle, "key", strlen ("key"), (void *)&key, &key_len); if (res == 0 && key) { if (key_len > sizeof (totem_config->private_key)) { goto key_error; } memcpy(totem_config->private_key, key, key_len); totem_config->private_key_len = key_len; got_key = 1; } } /* In desperation we read the default filename */ if (!got_key) { const char *filename = getenv("COROSYNC_TOTEM_AUTHKEY_FILE"); if (!filename) filename = SYSCONFDIR "/ais/authkey"; res = read_keyfile(filename, totem_config, error_string); if (res) goto key_error; } return (0); *error_string = error_string_response; key_error: return (-1); } static void totem_key_change_notify(object_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, - const void *object_name_pt, int object_name_len, - const void *key_name_pt, int key_len, - const void *key_value_pt, int key_value_len, + const void *object_name_pt, size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, void *priv_data_pt) { struct totem_config *totem_config = priv_data_pt; if (memcmp(object_name_pt, "totem", object_name_len) == 0) totem_volatile_config_read(global_objdb, totem_config, object_handle); // CHECK } static void totem_objdb_reload_notify(objdb_reload_notify_type_t type, int flush, void *priv_data_pt) { struct totem_config *totem_config = priv_data_pt; hdb_handle_t totem_object_handle; /* * A new totem {} key might exist, cancel the * existing notification at the start of reload, * and start a new one on the new object when * it's all settled. */ if (type == OBJDB_RELOAD_NOTIFY_START) { global_objdb->object_track_stop( totem_key_change_notify, NULL, NULL, NULL, NULL); } if (type == OBJDB_RELOAD_NOTIFY_END || type == OBJDB_RELOAD_NOTIFY_FAILED) { if (!totem_handle_find(global_objdb, &totem_object_handle)) { add_totem_config_notification(global_objdb, totem_config, totem_object_handle); /* * Reload the configuration */ totem_volatile_config_read(global_objdb, totem_config, totem_object_handle); } else { log_printf(LOG_LEVEL_ERROR, "totem objdb tracking stopped, cannot find totem{} handle on objdb\n"); } } } static void add_totem_config_notification( struct objdb_iface_ver0 *objdb, struct totem_config *totem_config, hdb_handle_t totem_object_handle) { global_objdb = objdb; objdb->object_track_start(totem_object_handle, 1, totem_key_change_notify, NULL, // object_create_notify, NULL, // object_destroy_notify, NULL, // object_reload_notify totem_config); // priv_data /* * Reload notify must be on the parent object */ objdb->object_track_start(OBJECT_PARENT_HANDLE, 1, NULL, // key_change_notify, NULL, // object_create_notify, NULL, // object_destroy_notify, totem_objdb_reload_notify, // object_reload_notify totem_config); // priv_data } diff --git a/include/corosync/confdb.h b/include/corosync/confdb.h index c8563ad8..8693048d 100644 --- a/include/corosync/confdb.h +++ b/include/corosync/confdb.h @@ -1,286 +1,286 @@ /* * Copyright (c) 2008, 2009 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfi@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ #ifndef COROSYNC_CONFDB_H_DEFINED #define COROSYNC_CONFDB_H_DEFINED #include #include /** * @addtogroup confdb_corosync * * @{ */ typedef uint64_t confdb_handle_t; #define OBJECT_PARENT_HANDLE 0xFFFFFFFF00000000ULL typedef enum { CONFDB_TRACK_DEPTH_ONE, CONFDB_TRACK_DEPTH_RECURSIVE } confdb_track_depth_t; typedef enum { OBJECT_KEY_CREATED, OBJECT_KEY_REPLACED, OBJECT_KEY_DELETED } confdb_change_type_t; typedef void (*confdb_key_change_notify_fn_t) ( confdb_handle_t handle, confdb_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const void *object_name, size_t object_name_len, const void *key_name, size_t key_name_len, const void *key_value, size_t key_value_len); typedef void (*confdb_object_create_notify_fn_t) ( confdb_handle_t handle, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const void *name_pt, size_t name_len); typedef void (*confdb_object_delete_notify_fn_t) ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *name_pt, size_t name_len); typedef struct { confdb_object_create_notify_fn_t confdb_object_create_change_notify_fn; confdb_object_delete_notify_fn_t confdb_object_delete_change_notify_fn; confdb_key_change_notify_fn_t confdb_key_change_notify_fn; } confdb_callbacks_t; /** @} */ /* * Create a new confdb connection */ cs_error_t confdb_initialize ( confdb_handle_t *handle, confdb_callbacks_t *callbacks); /* * Close the confdb handle */ cs_error_t confdb_finalize ( confdb_handle_t handle); /* * Write back the configuration */ cs_error_t confdb_write ( confdb_handle_t handle, char *error_text, size_t errbuf_len); /* * Reload the configuration */ cs_error_t confdb_reload ( confdb_handle_t handle, int flush, char *error_text, size_t errbuf_len); /* * Get a file descriptor on which to poll. confdb_handle_t is NOT a * file descriptor and may not be used directly. */ cs_error_t confdb_fd_get ( confdb_handle_t handle, int *fd); /* * Dispatch configuration changes */ cs_error_t confdb_dispatch ( confdb_handle_t handle, cs_dispatch_flags_t dispatch_types); /* * Change notification */ cs_error_t confdb_track_changes ( confdb_handle_t handle, hdb_handle_t object_handle, unsigned int flags); cs_error_t confdb_stop_track_changes ( confdb_handle_t handle); /* * Manipulate objects */ cs_error_t confdb_object_create ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_handle); cs_error_t confdb_object_destroy ( confdb_handle_t handle, hdb_handle_t object_handle); cs_error_t confdb_object_parent_get ( confdb_handle_t handle, hdb_handle_t object_handle, hdb_handle_t *parent_object_handle); /* * Manipulate keys */ cs_error_t confdb_key_create ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *value, - int value_len); + size_t value_len); cs_error_t confdb_key_delete ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *value, - int value_len); + size_t value_len); /* * Key queries */ cs_error_t confdb_key_get ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, void *value, - int *value_len); + size_t *value_len); cs_error_t confdb_key_replace ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *old_value, - int old_value_len, + size_t old_value_len, const void *new_value, - int new_value_len); + size_t new_value_len); cs_error_t confdb_key_increment ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, unsigned int *value); cs_error_t confdb_key_decrement ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, unsigned int *value); /* * Object queries * "find" loops through all objects of a given name and is also * a quick way of finding a specific object, * "iter" returns each object in sequence. */ cs_error_t confdb_object_find_start ( confdb_handle_t handle, hdb_handle_t parent_object_handle); cs_error_t confdb_object_find ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_handle); cs_error_t confdb_object_find_destroy( confdb_handle_t handle, hdb_handle_t parent_object_handle); cs_error_t confdb_object_iter_start ( confdb_handle_t handle, hdb_handle_t parent_object_handle); cs_error_t confdb_object_iter ( confdb_handle_t handle, hdb_handle_t parent_object_handle, hdb_handle_t *object_handle, void *object_name, - int *object_name_len); + size_t *object_name_len); cs_error_t confdb_object_iter_destroy( confdb_handle_t handle, hdb_handle_t parent_object_handle); /* * Key iterator */ cs_error_t confdb_key_iter_start ( confdb_handle_t handle, hdb_handle_t object_handle); cs_error_t confdb_key_iter ( confdb_handle_t handle, hdb_handle_t parent_object_handle, void *key_name, - int *key_name_len, + size_t *key_name_len, void *value, - int *value_len); + size_t *value_len); /* * Get/set context variable */ cs_error_t confdb_context_get ( confdb_handle_t handle, const void **context); cs_error_t confdb_context_set ( confdb_handle_t handle, const void *context); #endif /* COROSYNC_CONFDB_H_DEFINED */ diff --git a/include/corosync/engine/coroapi.h b/include/corosync/engine/coroapi.h index f08e84b2..55470b57 100644 --- a/include/corosync/engine/coroapi.h +++ b/include/corosync/engine/coroapi.h @@ -1,602 +1,603 @@ /* * Copyright (c) 2008, 2009 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ #ifndef COROAPI_H_DEFINED #define COROAPI_H_DEFINED #include #ifdef COROSYNC_BSD #include #endif #include typedef void * corosync_timer_handle_t; struct corosync_tpg_group { const void *group; - int group_len; + size_t group_len; }; #define TOTEMIP_ADDRLEN (sizeof(struct in6_addr)) #define PROCESSOR_COUNT_MAX 384 #define INTERFACE_MAX 2 #ifndef MESSAGE_SIZE_MAX #define MESSAGE_SIZE_MAX 1024*1024 /* (1MB) */ #endif /* MESSAGE_SIZE_MAX */ #ifndef MESSAGE_QUEUE_MAX #define MESSAGE_QUEUE_MAX MESSAGE_SIZE_MAX / totem_config->net_mtu #endif /* MESSAGE_QUEUE_MAX */ #define TOTEM_AGREED 0 #define TOTEM_SAFE 1 #define MILLI_2_NANO_SECONDS 1000000ULL #if !defined(TOTEM_IP_ADDRESS) struct totem_ip_address { unsigned int nodeid; unsigned short family; unsigned char addr[TOTEMIP_ADDRLEN]; } __attribute__((packed)); #endif #if !defined(MEMB_RING_ID) struct memb_ring_id { struct totem_ip_address rep; unsigned long long seq; } __attribute__((packed)); #endif #if !defined(TOTEM_CONFIGURATION_TYPE) enum totem_configuration_type { TOTEM_CONFIGURATION_REGULAR, TOTEM_CONFIGURATION_TRANSITIONAL }; #endif #if !defined(TOTEM_CALLBACK_TOKEN_TYPE) enum totem_callback_token_type { TOTEM_CALLBACK_TOKEN_RECEIVED = 1, TOTEM_CALLBACK_TOKEN_SENT = 2 }; #endif enum cs_lib_flow_control { CS_LIB_FLOW_CONTROL_REQUIRED = 1, CS_LIB_FLOW_CONTROL_NOT_REQUIRED = 2 }; #define corosync_lib_flow_control cs_lib_flow_control #define COROSYNC_LIB_FLOW_CONTROL_REQUIRED CS_LIB_FLOW_CONTROL_REQUIRED #define COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED CS_LIB_FLOW_CONTROL_NOT_REQUIRED enum cs_lib_allow_inquorate { CS_LIB_DISALLOW_INQUORATE = 0, /* default */ CS_LIB_ALLOW_INQUORATE = 1 }; #if !defined (COROSYNC_FLOW_CONTROL_STATE) enum cs_flow_control_state { CS_FLOW_CONTROL_STATE_DISABLED, CS_FLOW_CONTROL_STATE_ENABLED }; #define corosync_flow_control_state cs_flow_control_state #define CS_FLOW_CONTROL_STATE_DISABLED CS_FLOW_CONTROL_STATE_DISABLED #define CS_FLOW_CONTROL_STATE_ENABLED CS_FLOW_CONTROL_STATE_ENABLED #endif /* COROSYNC_FLOW_CONTROL_STATE */ typedef enum { COROSYNC_FATAL_ERROR_EXIT = -1, COROSYNC_LIBAIS_SOCKET = -6, COROSYNC_LIBAIS_BIND = -7, COROSYNC_READKEY = -8, COROSYNC_INVALID_CONFIG = -9, COROSYNC_DYNAMICLOAD = -12, COROSYNC_OUT_OF_MEMORY = -15, COROSYNC_FATAL_ERR = -16 } cs_fatal_error_t; #define corosync_fatal_error_t cs_fatal_error_t; #ifndef OBJECT_PARENT_HANDLE #define OBJECT_PARENT_HANDLE 0xffffffff00000000ULL struct object_valid { char *object_name; - int object_len; + size_t object_len; }; struct object_key_valid { char *key_name; - int key_len; - int (*validate_callback) (const void *key, int key_len, - const void *value, int value_len); + size_t key_len; + int (*validate_callback) (const void *key, size_t key_len, + const void *value, size_t value_len); }; /* deprecated */ typedef enum { OBJECT_TRACK_DEPTH_ONE, OBJECT_TRACK_DEPTH_RECURSIVE } object_track_depth_t; typedef enum { OBJECT_KEY_CREATED, OBJECT_KEY_REPLACED, OBJECT_KEY_DELETED } object_change_type_t; typedef enum { OBJDB_RELOAD_NOTIFY_START, OBJDB_RELOAD_NOTIFY_END, OBJDB_RELOAD_NOTIFY_FAILED } objdb_reload_notify_type_t; typedef void (*object_key_change_notify_fn_t)( object_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, - const void *object_name_pt, int object_name_len, - const void *key_name_pt, int key_len, - const void *key_value_pt, int key_value_len, - void *priv_data_pt); + const void *object_name_pt, size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, + const void *priv_data_pt); typedef void (*object_create_notify_fn_t) ( hdb_handle_t parent_object_handle, hdb_handle_t object_handle, - const uint8_t *name_pt, int name_len, - void *priv_data_pt); + const uint8_t *name_pt, size_t name_len, + const void *priv_data_pt); typedef void (*object_destroy_notify_fn_t) ( hdb_handle_t parent_object_handle, - const uint8_t *name_pt, int name_len, - void *priv_data_pt); + const uint8_t *name_pt, size_t name_len, + const void *priv_data_pt); typedef void (*object_notify_callback_fn_t)( hdb_handle_t object_handle, - const void *key_name, int key_len, - const void *value, int value_len, + const void *key_name, size_t key_len, + const void *value, size_t value_len, object_change_type_t type, - void * priv_data_pt); + const void * priv_data_pt); typedef void (*object_reload_notify_fn_t) ( objdb_reload_notify_type_t, int flush, - void *priv_data_pt); + const void *priv_data_pt); #endif /* OBJECT_PARENT_HANDLE_DEFINED */ #ifndef QUORUM_H_DEFINED typedef void (*quorum_callback_fn_t) (int quorate, void *context); struct quorum_callin_functions { int (*quorate) (void); int (*register_callback) (quorum_callback_fn_t callback_fn, void *context); int (*unregister_callback) (quorum_callback_fn_t callback_fn, void *context); }; typedef void (*sync_callback_fn_t) ( const unsigned int *view_list, size_t view_list_entries, int primary_designated, struct memb_ring_id *ring_id); #endif /* QUORUM_H_DEFINED */ struct corosync_api_v1 { /* * Object and configuration APIs */ int (*object_create) ( hdb_handle_t parent_object_handle, hdb_handle_t *object_handle, - const void *object_name, unsigned int object_name_len); + const void *object_name, + size_t object_name_len); int (*object_priv_set) ( hdb_handle_t object_handle, void *priv); int (*object_key_create) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, const void *value, - int value_len); + size_t value_len); int (*object_destroy) ( hdb_handle_t object_handle); int (*object_valid_set) ( hdb_handle_t object_handle, struct object_valid *object_valid_list, unsigned int object_valid_list_entries); int (*object_key_valid_set) ( hdb_handle_t object_handle, struct object_key_valid *object_key_valid_list, unsigned int object_key_valid_list_entries); int (*object_find_create) ( hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_find_handle); int (*object_find_next) ( hdb_handle_t object_find_handle, hdb_handle_t *object_handle); int (*object_find_destroy) ( hdb_handle_t object_find_handle); int (*object_key_get) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, void **value, - int *value_len); + size_t *value_len); int (*object_priv_get) ( hdb_handle_t jobject_handle, void **priv); int (*object_key_replace) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, const void *new_value, - int new_value_len); + size_t new_value_len); int (*object_key_delete) ( hdb_handle_t object_handle, const void *key_name, - int key_len); + size_t key_len); int (*object_iter_reset) ( hdb_handle_t parent_object_handle); int (*object_iter) ( hdb_handle_t parent_object_handle, void **object_name, - int *name_len, + size_t *name_len, hdb_handle_t *object_handle); int (*object_key_iter_reset) ( hdb_handle_t object_handle); int (*object_key_iter) ( hdb_handle_t parent_object_handle, void **key_name, - int *key_len, + size_t *key_len, void **value, - int *value_len); + size_t *value_len); int (*object_parent_get) ( hdb_handle_t object_handle, hdb_handle_t *parent_handle); int (*object_name_get) ( hdb_handle_t object_handle, char *object_name, - int *object_name_len); + size_t *object_name_len); int (*object_dump) ( hdb_handle_t object_handle, FILE *file); int (*object_key_iter_from) ( hdb_handle_t parent_object_handle, hdb_handle_t start_pos, void **key_name, - int *key_len, + size_t *key_len, void **value, - int *value_len); + size_t *value_len); int (*object_track_start) ( hdb_handle_t object_handle, object_track_depth_t depth, object_key_change_notify_fn_t key_change_notify_fn, object_create_notify_fn_t object_create_notify_fn, object_destroy_notify_fn_t object_destroy_notify_fn, object_reload_notify_fn_t object_reload_notify_fn, void * priv_data_pt); void (*object_track_stop) ( object_key_change_notify_fn_t key_change_notify_fn, object_create_notify_fn_t object_create_notify_fn, object_destroy_notify_fn_t object_destroy_notify_fn, object_reload_notify_fn_t object_reload_notify_fn, void * priv_data_pt); int (*object_write_config) (const char **error_string); int (*object_reload_config) (int flush, const char **error_string); int (*object_key_increment) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, unsigned int *value); int (*object_key_decrement) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, unsigned int *value); /* * Time and timer APIs */ int (*timer_add_duration) ( unsigned long long nanoseconds_in_future, void *data, void (*timer_nf) (void *data), corosync_timer_handle_t *handle); int (*timer_add_absolute) ( unsigned long long nanoseconds_from_epoch, void *data, void (*timer_fn) (void *data), corosync_timer_handle_t *handle); void (*timer_delete) ( corosync_timer_handle_t timer_handle); unsigned long long (*timer_time_get) (void); unsigned long long (*timer_expire_time_get) ( corosync_timer_handle_t timer_handle); /* * IPC APIs */ void (*ipc_source_set) (mar_message_source_t *source, void *conn); int (*ipc_source_is_local) (const mar_message_source_t *source); void *(*ipc_private_data_get) (void *conn); int (*ipc_response_send) (void *conn, const void *msg, int mlen); int (*ipc_response_iov_send) (void *conn, const struct iovec *iov, unsigned int iov_len); int (*ipc_dispatch_send) (void *conn, const void *msg, int mlen); int (*ipc_dispatch_iov_send) (void *conn, const struct iovec *iov, unsigned int iov_len); void (*ipc_refcnt_inc) (void *conn); void (*ipc_refcnt_dec) (void *conn); /* * Totem APIs */ unsigned int (*totem_nodeid_get) (void); int (*totem_family_get) (void); int (*totem_ring_reenable) (void); int (*totem_mcast) (struct iovec *iovec, unsigned int iov_len, unsigned int guarantee); int (*totem_ifaces_get) ( unsigned int nodeid, struct totem_ip_address *interfaces, char ***status, unsigned int *iface_count); const char *(*totem_ifaces_print) (unsigned int nodeid); const char *(*totem_ip_print) (const struct totem_ip_address *addr); int (*totem_callback_token_create) ( void **handle_out, enum totem_callback_token_type type, int delete, int (*callback_fn) (enum totem_callback_token_type type, const void *), const void *data); /* * Totem open process groups API for those service engines * wanting their own groups */ int (*tpg_init) ( hdb_handle_t *handle, void (*deliver_fn) ( unsigned int nodeid, struct iovec *iovec, unsigned int iov_len, int endian_conversion_required), void (*confchg_fn) ( enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id)); int (*tpg_exit) ( hdb_handle_t handle); int (*tpg_join) ( hdb_handle_t handle, struct corosync_tpg_group *groups, int group_cnt); int (*tpg_leave) ( hdb_handle_t handle, struct corosync_tpg_group *groups, int group_cnt); int (*tpg_joined_mcast) ( hdb_handle_t handle, const struct iovec *iovec, unsigned int iov_len, int guarantee); int (*tpg_joined_reserve) ( hdb_handle_t handle, const struct iovec *iovec, unsigned int iov_len); int (*tpg_joined_release) ( int reserved_msgs); int (*tpg_groups_mcast) ( hdb_handle_t handle, int guarantee, const struct corosync_tpg_group *groups, int groups_cnt, const struct iovec *iovec, unsigned int iov_len); int (*tpg_groups_reserve) ( hdb_handle_t handle, const struct corosync_tpg_group *groups, int groups_cnt, const struct iovec *iovec, unsigned int iov_len); int (*tpg_groups_release) ( int reserved_msgs); int (*sync_request) ( const char *service_name); /* * User plugin-callable functions for quorum */ int (*quorum_is_quorate) (void); int (*quorum_register_callback) (quorum_callback_fn_t callback_fn, void *context); int (*quorum_unregister_callback) (quorum_callback_fn_t callback_fn, void *context); /* * This one is for the quorum management plugin's use */ int (*quorum_initialize)(struct quorum_callin_functions *fns); /* * Plugin loading and unloading */ int (*plugin_interface_reference) ( hdb_handle_t *handle, const char *iface_name, int version, void **interface, void *context); int (*plugin_interface_release) (hdb_handle_t handle); /* * Service loading and unloading APIs */ unsigned int (*service_link_and_init) ( struct corosync_api_v1 *corosync_api_v1, const char *service_name, unsigned int service_ver); unsigned int (*service_unlink_and_exit) ( struct corosync_api_v1 *corosync_api_v1, const char *service_name, unsigned int service_ver); /* * Error handling APIs */ void (*error_memory_failure) (void); #define corosync_fatal_error(err) api->fatal_error ((err), __FILE__, __LINE__) void (*fatal_error) (cs_fatal_error_t err, const char *file, unsigned int line); }; #define SERVICE_ID_MAKE(a,b) ( ((a)<<16) | (b) ) #define SERVICE_HANDLER_MAXIMUM_COUNT 64 struct corosync_lib_handler { void (*lib_handler_fn) (void *conn, void *msg); int response_size; int response_id; enum cs_lib_flow_control flow_control; }; struct corosync_exec_handler { void (*exec_handler_fn) (const void *msg, unsigned int nodeid); void (*exec_endian_convert_fn) (void *msg); }; struct corosync_service_engine_iface_ver0 { struct corosync_service_engine *(*corosync_get_service_engine_ver0) (void); }; struct corosync_service_engine { const char *name; unsigned short id; unsigned int private_data_size; enum cs_lib_flow_control flow_control; enum cs_lib_allow_inquorate allow_inquorate; int (*exec_init_fn) (struct corosync_api_v1 *); int (*exec_exit_fn) (void); void (*exec_dump_fn) (void); int (*lib_init_fn) (void *conn); int (*lib_exit_fn) (void *conn); struct corosync_lib_handler *lib_engine; int lib_engine_count; struct corosync_exec_handler *exec_engine; int exec_engine_count; int (*config_init_fn) (struct corosync_api_v1 *); void (*confchg_fn) ( enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id); void (*sync_init) (void); int (*sync_process) (void); void (*sync_activate) (void); void (*sync_abort) (void); }; #endif /* COROAPI_H_DEFINED */ diff --git a/include/corosync/engine/objdb.h b/include/corosync/engine/objdb.h index f5e36d90..2eac2fe9 100644 --- a/include/corosync/engine/objdb.h +++ b/include/corosync/engine/objdb.h @@ -1,239 +1,239 @@ /* * Copyright (c) 2006 MontaVista Software, Inc. * Copyright (c) 2007-2009 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ #ifndef OBJDB_H_DEFINED #define OBJDB_H_DEFINED #define OBJECT_PARENT_HANDLE 0xFFFFFFFF00000000ULL #include #include typedef enum { OBJECT_TRACK_DEPTH_ONE, OBJECT_TRACK_DEPTH_RECURSIVE } object_track_depth_t; typedef enum { OBJECT_KEY_CREATED, OBJECT_KEY_REPLACED, OBJECT_KEY_DELETED } object_change_type_t; typedef enum { OBJDB_RELOAD_NOTIFY_START, OBJDB_RELOAD_NOTIFY_END, OBJDB_RELOAD_NOTIFY_FAILED } objdb_reload_notify_type_t; typedef void (*object_key_change_notify_fn_t)( object_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, - const void *object_name_pt, int object_name_len, - const void *key_name_pt, int key_len, - const void *key_value_pt, int key_value_len, -void *priv_data_pt); + const void *object_name_pt, size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, + const void *priv_data_pt); typedef void (*object_create_notify_fn_t) (unsigned int parent_object_handle, hdb_handle_t object_handle, -const void *name_pt, int name_len, +const void *name_pt, size_t name_len, void *priv_data_pt); typedef void (*object_destroy_notify_fn_t) (unsigned int parent_object_handle, - void *name_pt, int name_len, + void *name_pt, size_t name_len, void *priv_data_pt); typedef void (*object_reload_notify_fn_t) (objdb_reload_notify_type_t, int flush, void *priv_data_pt); struct object_valid { char *object_name; - int object_len; + size_t object_len; }; struct object_key_valid { char *key_name; - int key_len; - int (*validate_callback) (const void *key, int key_len, - const void *value, int value_len); + size_t key_len; + int (*validate_callback) (const void *key, size_t key_len, + const void *value, size_t value_len); }; struct objdb_iface_ver0 { int (*objdb_init) (void); int (*object_create) ( hdb_handle_t parent_object_handle, hdb_handle_t *object_handle, const void *object_name, - unsigned int object_name_len); + size_t object_name_len); int (*object_priv_set) ( hdb_handle_t object_handle, void *priv); int (*object_key_create) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, const void *value, - int value_len); + size_t value_len); int (*object_destroy) ( hdb_handle_t object_handle); int (*object_valid_set) ( hdb_handle_t object_handle, struct object_valid *object_valid_list, unsigned int object_valid_list_entries); int (*object_key_valid_set) ( hdb_handle_t object_handle, struct object_key_valid *object_key_valid_list, unsigned int object_key_valid_list_entries); int (*object_find_create) ( hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_find_handle); int (*object_find_next) ( hdb_handle_t object_find_handle, hdb_handle_t *object_handle); int (*object_find_destroy) ( hdb_handle_t object_find_handle); int (*object_key_get) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, void **value, - int *value_len); + size_t *value_len); int (*object_priv_get) ( hdb_handle_t jobject_handle, void **priv); int (*object_key_replace) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, const void *new_value, - int new_value_len); + size_t new_value_len); int (*object_key_delete) ( hdb_handle_t object_handle, const void *key_name, - int key_len); + size_t key_len); int (*object_iter_reset) ( hdb_handle_t parent_object_handle); int (*object_iter) ( hdb_handle_t parent_object_handle, void **object_name, - int *name_len, + size_t *name_len, hdb_handle_t *object_handle); int (*object_key_iter_reset) ( hdb_handle_t object_handle); int (*object_key_iter) ( hdb_handle_t parent_object_handle, void **key_name, - int *key_len, + size_t *key_len, void **value, - int *value_len); + size_t *value_len); int (*object_parent_get) ( hdb_handle_t object_handle, hdb_handle_t *parent_handle); int (*object_name_get) ( hdb_handle_t object_handle, char *object_name, - int *object_name_len); + size_t *object_name_len); int (*object_dump) ( hdb_handle_t object_handle, FILE *file); int (*object_key_iter_from) ( hdb_handle_t parent_object_handle, hdb_handle_t start_pos, void **key_name, - int *key_len, + size_t *key_len, void **value, - int *value_len); + size_t *value_len); int (*object_track_start) ( hdb_handle_t object_handle, object_track_depth_t depth, object_key_change_notify_fn_t key_change_notify_fn, object_create_notify_fn_t object_create_notify_fn, object_destroy_notify_fn_t object_destroy_notify_fn, object_reload_notify_fn_t object_reload_notify_fn, void * priv_data_pt); void (*object_track_stop) ( object_key_change_notify_fn_t key_change_notify_fn, object_create_notify_fn_t object_create_notify_fn, object_destroy_notify_fn_t object_destroy_notify_fn, object_reload_notify_fn_t object_reload_notify_fn, void * priv_data_pt); int (*object_write_config) (const char **error_string); int (*object_reload_config) ( int flush, const char **error_string); int (*object_key_increment) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, unsigned int *value); int (*object_key_decrement) ( hdb_handle_t object_handle, const void *key_name, - int key_len, + size_t key_len, unsigned int *value); }; #endif /* OBJDB_H_DEFINED */ diff --git a/lib/confdb.c b/lib/confdb.c index 21842805..af91d0d6 100644 --- a/lib/confdb.c +++ b/lib/confdb.c @@ -1,1617 +1,1617 @@ /* * Copyright (c) 2008-2009 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ /* * Provides access to data in the corosync object database */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sa-confdb.h" #undef MIN #define MIN(x,y) ((x) < (y) ? (x) : (y)) /* Hold the information for iterators so that callers can do recursive tree traversals. each object_handle can have its own iterator */ struct iter_context { struct list_head list; hdb_handle_t parent_object_handle; hdb_handle_t find_handle; hdb_handle_t next_entry; }; struct confdb_inst { void *ipc_ctx; int finalize; int standalone; confdb_callbacks_t callbacks; const void *context; pthread_mutex_t response_mutex; pthread_mutex_t dispatch_mutex; struct list_head object_find_head; struct list_head object_iter_head; struct list_head key_iter_head; }; static void confdb_instance_destructor (void *instance); static struct saHandleDatabase confdb_handle_t_db = { .handleCount = 0, .handles = 0, .mutex = PTHREAD_MUTEX_INITIALIZER, .handleInstanceDestructor = confdb_instance_destructor }; static cs_error_t do_find_destroy(struct confdb_inst *confdb_inst, hdb_handle_t find_handle); /* Safely tidy one iterator context list */ static void free_context_list(struct confdb_inst *confdb_inst, struct list_head *list) { struct iter_context *context; struct list_head *iter, *tmp; for (iter = list->next, tmp = iter->next; iter != list; iter = tmp, tmp = iter->next) { context = list_entry (iter, struct iter_context, list); (void)do_find_destroy(confdb_inst, context->find_handle); free(context); } } /* * Clean up function for a confdb instance (confdb_initialize) handle */ static void confdb_instance_destructor (void *instance) { struct confdb_inst *confdb_inst = instance; pthread_mutex_destroy (&confdb_inst->response_mutex); pthread_mutex_destroy (&confdb_inst->dispatch_mutex); } static struct iter_context *find_iter_context(struct list_head *list, hdb_handle_t object_handle) { struct iter_context *context; struct list_head *iter; for (iter = list->next; iter != list; iter = iter->next) { context = list_entry (iter, struct iter_context, list); if (context->parent_object_handle == object_handle) return context; } return NULL; } /** * @defgroup confdb_corosync * @ingroup corosync * * @{ */ cs_error_t confdb_initialize ( confdb_handle_t *handle, confdb_callbacks_t *callbacks) { cs_error_t error; struct confdb_inst *confdb_inst; error = saHandleCreate (&confdb_handle_t_db, sizeof (struct confdb_inst), handle); if (error != CS_OK) { goto error_no_destroy; } error = saHandleInstanceGet (&confdb_handle_t_db, *handle, (void *)&confdb_inst); if (error != CS_OK) { goto error_destroy; } if (getenv("COROSYNC_DEFAULT_CONFIG_IFACE")) { error = confdb_sa_init(); confdb_inst->standalone = 1; } else { error = coroipcc_service_connect (IPC_SOCKET_NAME, CONFDB_SERVICE, &confdb_inst->ipc_ctx); } if (error != CS_OK) goto error_put_destroy; memcpy (&confdb_inst->callbacks, callbacks, sizeof (confdb_callbacks_t)); pthread_mutex_init (&confdb_inst->response_mutex, NULL); pthread_mutex_init (&confdb_inst->dispatch_mutex, NULL); list_init (&confdb_inst->object_find_head); list_init (&confdb_inst->object_iter_head); list_init (&confdb_inst->key_iter_head); (void)saHandleInstancePut (&confdb_handle_t_db, *handle); return (CS_OK); error_put_destroy: (void)saHandleInstancePut (&confdb_handle_t_db, *handle); error_destroy: (void)saHandleDestroy (&confdb_handle_t_db, *handle); error_no_destroy: return (error); } cs_error_t confdb_finalize ( confdb_handle_t handle) { struct confdb_inst *confdb_inst; cs_error_t error; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } pthread_mutex_lock (&confdb_inst->response_mutex); /* * Another thread has already started finalizing */ if (confdb_inst->finalize) { pthread_mutex_unlock (&confdb_inst->response_mutex); (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (CS_ERR_BAD_HANDLE); } confdb_inst->finalize = 1; pthread_mutex_unlock (&confdb_inst->response_mutex); /* Free saved context handles */ free_context_list(confdb_inst, &confdb_inst->object_find_head); free_context_list(confdb_inst, &confdb_inst->object_iter_head); free_context_list(confdb_inst, &confdb_inst->key_iter_head); if (!confdb_inst->standalone) { coroipcc_service_disconnect (confdb_inst->ipc_ctx); } (void)saHandleDestroy (&confdb_handle_t_db, handle); (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (CS_OK); } cs_error_t confdb_fd_get ( confdb_handle_t handle, int *fd) { cs_error_t error; struct confdb_inst *confdb_inst; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } *fd = coroipcc_fd_get (confdb_inst->ipc_ctx); (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (CS_OK); } cs_error_t confdb_context_get ( confdb_handle_t handle, const void **context) { cs_error_t error; struct confdb_inst *confdb_inst; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } *context = confdb_inst->context; (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (CS_OK); } cs_error_t confdb_context_set ( confdb_handle_t handle, const void *context) { cs_error_t error; struct confdb_inst *confdb_inst; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } confdb_inst->context = context; (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (CS_OK); } struct confdb_res_overlay { mar_res_header_t header __attribute__((aligned(8))); char data[512000]; }; cs_error_t confdb_dispatch ( confdb_handle_t handle, cs_dispatch_flags_t dispatch_types) { int timeout = -1; cs_error_t error; int cont = 1; /* always continue do loop except when set to 0 */ int dispatch_avail; struct confdb_inst *confdb_inst; confdb_callbacks_t callbacks; struct res_lib_confdb_key_change_callback *res_key_changed_pt; struct res_lib_confdb_object_create_callback *res_object_created_pt; struct res_lib_confdb_object_destroy_callback *res_object_destroyed_pt; struct confdb_res_overlay dispatch_data; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_ERR_NOT_SUPPORTED; goto error_put; } /* * Timeout instantly for SA_DISPATCH_ONE or SA_DISPATCH_ALL and * wait indefinately for SA_DISPATCH_BLOCKING */ if (dispatch_types == CONFDB_DISPATCH_ALL) { timeout = 0; } do { pthread_mutex_lock (&confdb_inst->dispatch_mutex); dispatch_avail = coroipcc_dispatch_recv (confdb_inst->ipc_ctx, (void *)&dispatch_data, sizeof (dispatch_data), timeout); /* * Handle has been finalized in another thread */ if (confdb_inst->finalize == 1) { error = CS_OK; pthread_mutex_unlock (&confdb_inst->dispatch_mutex); goto error_put; } if (dispatch_avail == 0 && dispatch_types == CONFDB_DISPATCH_ALL) { pthread_mutex_unlock (&confdb_inst->dispatch_mutex); break; /* exit do while cont is 1 loop */ } else if (dispatch_avail == 0) { pthread_mutex_unlock (&confdb_inst->dispatch_mutex); continue; /* next poll */ } /* * Make copy of callbacks, message data, unlock instance, and call callback * A risk of this dispatch method is that the callback routines may * operate at the same time that confdbFinalize has been called. */ memcpy (&callbacks, &confdb_inst->callbacks, sizeof (confdb_callbacks_t)); pthread_mutex_unlock (&confdb_inst->dispatch_mutex); /* * Dispatch incoming message */ switch (dispatch_data.header.id) { case MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK: res_key_changed_pt = (struct res_lib_confdb_key_change_callback *)&dispatch_data; callbacks.confdb_key_change_notify_fn(handle, res_key_changed_pt->change_type, res_key_changed_pt->object_handle, res_key_changed_pt->parent_object_handle, res_key_changed_pt->object_name.value, res_key_changed_pt->object_name.length, res_key_changed_pt->key_name.value, res_key_changed_pt->key_name.length, res_key_changed_pt->key_value.value, res_key_changed_pt->key_value.length); break; case MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK: res_object_created_pt = (struct res_lib_confdb_object_create_callback *)&dispatch_data; callbacks.confdb_object_create_change_notify_fn(handle, res_object_created_pt->object_handle, res_object_created_pt->parent_object_handle, res_object_created_pt->name.value, res_object_created_pt->name.length); break; case MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK: res_object_destroyed_pt = (struct res_lib_confdb_object_destroy_callback *)&dispatch_data; callbacks.confdb_object_delete_change_notify_fn(handle, res_object_destroyed_pt->parent_object_handle, res_object_destroyed_pt->name.value, res_object_destroyed_pt->name.length); break; default: error = CS_ERR_LIBRARY; goto error_noput; break; } /* * Determine if more messages should be processed * */ switch (dispatch_types) { case CONFDB_DISPATCH_ONE: cont = 0; break; case CONFDB_DISPATCH_ALL: break; case CONFDB_DISPATCH_BLOCKING: break; } } while (cont); error_put: (void)saHandleInstancePut (&confdb_handle_t_db, handle); error_noput: return (error); } cs_error_t confdb_object_create ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_handle) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_object_create req_lib_confdb_object_create; struct res_lib_confdb_object_create res_lib_confdb_object_create; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_object_create(parent_object_handle, object_name, object_name_len, object_handle)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_object_create.header.size = sizeof (struct req_lib_confdb_object_create); req_lib_confdb_object_create.header.id = MESSAGE_REQ_CONFDB_OBJECT_CREATE; req_lib_confdb_object_create.parent_object_handle = parent_object_handle; memcpy(req_lib_confdb_object_create.object_name.value, object_name, object_name_len); req_lib_confdb_object_create.object_name.length = object_name_len; iov.iov_base = (char *)&req_lib_confdb_object_create; iov.iov_len = sizeof (struct req_lib_confdb_object_create); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_object_create, sizeof (struct res_lib_confdb_object_create)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_object_create.header.error; *object_handle = res_lib_confdb_object_create.object_handle; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_object_destroy ( confdb_handle_t handle, hdb_handle_t object_handle) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_object_destroy req_lib_confdb_object_destroy; mar_res_header_t res; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_object_destroy(object_handle)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_object_destroy.header.size = sizeof (struct req_lib_confdb_object_destroy); req_lib_confdb_object_destroy.header.id = MESSAGE_REQ_CONFDB_OBJECT_DESTROY; req_lib_confdb_object_destroy.object_handle = object_handle; iov.iov_base = (char *)&req_lib_confdb_object_destroy; iov.iov_len = sizeof (struct req_lib_confdb_object_destroy); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (mar_res_header_t)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_object_parent_get ( confdb_handle_t handle, hdb_handle_t object_handle, hdb_handle_t *parent_object_handle) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_object_parent_get req_lib_confdb_object_parent_get; struct res_lib_confdb_object_parent_get res_lib_confdb_object_parent_get; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_object_parent_get(object_handle, parent_object_handle)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_object_parent_get.header.size = sizeof (struct req_lib_confdb_object_parent_get); req_lib_confdb_object_parent_get.header.id = MESSAGE_REQ_CONFDB_OBJECT_PARENT_GET; req_lib_confdb_object_parent_get.object_handle = object_handle; iov.iov_base = (char *)&req_lib_confdb_object_parent_get; iov.iov_len = sizeof (struct req_lib_confdb_object_parent_get); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_object_parent_get, sizeof (struct res_lib_confdb_object_parent_get)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_object_parent_get.header.error; *parent_object_handle = res_lib_confdb_object_parent_get.parent_object_handle; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } static cs_error_t do_find_destroy( struct confdb_inst *confdb_inst, hdb_handle_t find_handle) { cs_error_t error; struct iovec iov; struct req_lib_confdb_object_find_destroy req_lib_confdb_object_find_destroy; mar_res_header_t res; if (!find_handle) return CS_OK; if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_find_destroy(find_handle)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_object_find_destroy.header.size = sizeof (struct req_lib_confdb_object_find_destroy); req_lib_confdb_object_find_destroy.header.id = MESSAGE_REQ_CONFDB_OBJECT_FIND_DESTROY; req_lib_confdb_object_find_destroy.find_handle = find_handle; iov.iov_base = (char *)&req_lib_confdb_object_find_destroy; iov.iov_len = sizeof (struct req_lib_confdb_object_find_destroy); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (mar_res_header_t)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: return (error); } cs_error_t confdb_object_find_destroy( confdb_handle_t handle, hdb_handle_t parent_object_handle) { struct iter_context *context; cs_error_t error; struct confdb_inst *confdb_inst; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } context = find_iter_context(&confdb_inst->object_find_head, parent_object_handle); error = do_find_destroy(confdb_inst, context->find_handle); if (error == CS_OK) { list_del(&context->list); free(context); } (void)saHandleInstancePut (&confdb_handle_t_db, handle); return error; } cs_error_t confdb_object_iter_destroy( confdb_handle_t handle, hdb_handle_t parent_object_handle) { struct iter_context *context; cs_error_t error; struct confdb_inst *confdb_inst; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } context = find_iter_context(&confdb_inst->object_iter_head, parent_object_handle); error = do_find_destroy(confdb_inst, context->find_handle); if (error == CS_OK) { list_del(&context->list); free(context); } (void)saHandleInstancePut (&confdb_handle_t_db, handle); return error; } cs_error_t confdb_key_create ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *value, - int value_len) + size_t value_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_key_create req_lib_confdb_key_create; mar_res_header_t res; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_create(parent_object_handle, key_name, key_name_len, value, value_len)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_key_create.header.size = sizeof (struct req_lib_confdb_key_create); req_lib_confdb_key_create.header.id = MESSAGE_REQ_CONFDB_KEY_CREATE; req_lib_confdb_key_create.object_handle = parent_object_handle; memcpy(req_lib_confdb_key_create.key_name.value, key_name, key_name_len); req_lib_confdb_key_create.key_name.length = key_name_len; memcpy(req_lib_confdb_key_create.value.value, value, value_len); req_lib_confdb_key_create.value.length = value_len; iov.iov_base = (char *)&req_lib_confdb_key_create; iov.iov_len = sizeof (struct req_lib_confdb_key_create); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (res)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_key_delete ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *value, - int value_len) + size_t value_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_key_delete req_lib_confdb_key_delete; mar_res_header_t res; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_delete(parent_object_handle, key_name, key_name_len, value, value_len)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_key_delete.header.size = sizeof (struct req_lib_confdb_key_delete); req_lib_confdb_key_delete.header.id = MESSAGE_REQ_CONFDB_KEY_DELETE; req_lib_confdb_key_delete.object_handle = parent_object_handle; memcpy(req_lib_confdb_key_delete.key_name.value, key_name, key_name_len); req_lib_confdb_key_delete.key_name.length = key_name_len; memcpy(req_lib_confdb_key_delete.value.value, value, value_len); req_lib_confdb_key_delete.value.length = value_len; iov.iov_base = (char *)&req_lib_confdb_key_delete; iov.iov_len = sizeof (struct req_lib_confdb_key_delete); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (res)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_key_get ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, void *value, - int *value_len) + size_t *value_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_key_get req_lib_confdb_key_get; struct res_lib_confdb_key_get res_lib_confdb_key_get; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_get(parent_object_handle, key_name, key_name_len, value, value_len)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_key_get.header.size = sizeof (struct req_lib_confdb_key_get); req_lib_confdb_key_get.header.id = MESSAGE_REQ_CONFDB_KEY_GET; req_lib_confdb_key_get.parent_object_handle = parent_object_handle; memcpy(req_lib_confdb_key_get.key_name.value, key_name, key_name_len); req_lib_confdb_key_get.key_name.length = key_name_len; iov.iov_base = (char *)&req_lib_confdb_key_get; iov.iov_len = sizeof (struct req_lib_confdb_key_get); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_key_get, sizeof (struct res_lib_confdb_key_get)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_key_get.header.error; if (error == CS_OK) { *value_len = res_lib_confdb_key_get.value.length; memcpy(value, res_lib_confdb_key_get.value.value, *value_len); } error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_key_increment ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, unsigned int *value) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_key_get req_lib_confdb_key_get; struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_increment(parent_object_handle, key_name, key_name_len, value)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_key_get.header.size = sizeof (struct req_lib_confdb_key_get); req_lib_confdb_key_get.header.id = MESSAGE_REQ_CONFDB_KEY_INCREMENT; req_lib_confdb_key_get.parent_object_handle = parent_object_handle; memcpy(req_lib_confdb_key_get.key_name.value, key_name, key_name_len); req_lib_confdb_key_get.key_name.length = key_name_len; iov.iov_base = (char *)&req_lib_confdb_key_get; iov.iov_len = sizeof (struct req_lib_confdb_key_get); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_key_incdec, sizeof (struct res_lib_confdb_key_incdec)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_key_incdec.header.error; if (error == CS_OK) { *value = res_lib_confdb_key_incdec.value; } error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_key_decrement ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, unsigned int *value) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_key_get req_lib_confdb_key_get; struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_decrement(parent_object_handle, key_name, key_name_len, value)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_key_get.header.size = sizeof (struct req_lib_confdb_key_get); req_lib_confdb_key_get.header.id = MESSAGE_REQ_CONFDB_KEY_DECREMENT; req_lib_confdb_key_get.parent_object_handle = parent_object_handle; memcpy(req_lib_confdb_key_get.key_name.value, key_name, key_name_len); req_lib_confdb_key_get.key_name.length = key_name_len; iov.iov_base = (char *)&req_lib_confdb_key_get; iov.iov_len = sizeof (struct req_lib_confdb_key_get); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_key_incdec, sizeof (struct res_lib_confdb_key_incdec)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_key_incdec.header.error; if (error == CS_OK) { *value = res_lib_confdb_key_incdec.value; } error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_key_replace ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *old_value, - int old_value_len, + size_t old_value_len, const void *new_value, - int new_value_len) + size_t new_value_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_key_replace req_lib_confdb_key_replace; mar_res_header_t res; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_replace(parent_object_handle, key_name, key_name_len, old_value, old_value_len, new_value, new_value_len)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_key_replace.header.size = sizeof (struct req_lib_confdb_key_replace); req_lib_confdb_key_replace.header.id = MESSAGE_REQ_CONFDB_KEY_REPLACE; req_lib_confdb_key_replace.object_handle = parent_object_handle; memcpy(req_lib_confdb_key_replace.key_name.value, key_name, key_name_len); req_lib_confdb_key_replace.key_name.length = key_name_len; memcpy(req_lib_confdb_key_replace.old_value.value, old_value, old_value_len); req_lib_confdb_key_replace.old_value.length = old_value_len; memcpy(req_lib_confdb_key_replace.new_value.value, new_value, new_value_len); req_lib_confdb_key_replace.new_value.length = new_value_len; iov.iov_base = (char *)&req_lib_confdb_key_replace; iov.iov_len = sizeof (struct req_lib_confdb_key_replace); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (res)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_object_iter_start ( confdb_handle_t handle, hdb_handle_t object_handle) { struct confdb_inst *confdb_inst; cs_error_t error = CS_OK; struct iter_context *context; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } context = find_iter_context(&confdb_inst->object_iter_head, object_handle); if (!context) { context = malloc(sizeof(struct iter_context)); if (!context) { error = CS_ERR_NO_MEMORY; goto ret; } context->parent_object_handle = object_handle; context->find_handle = 0; list_add(&context->list, &confdb_inst->object_iter_head); } /* Start a new find context */ if (context->find_handle) { (void)do_find_destroy(confdb_inst, context->find_handle); context->find_handle = 0; } (void)saHandleInstancePut (&confdb_handle_t_db, handle); ret: return error; } cs_error_t confdb_key_iter_start ( confdb_handle_t handle, hdb_handle_t object_handle) { struct confdb_inst *confdb_inst; cs_error_t error = CS_OK; struct iter_context *context; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } context = find_iter_context(&confdb_inst->key_iter_head, object_handle); if (!context) { context = malloc(sizeof(struct iter_context)); if (!context) { error = CS_ERR_NO_MEMORY; goto ret; } context->parent_object_handle = object_handle; list_add(&context->list, &confdb_inst->key_iter_head); } context->find_handle = 0; context->next_entry = 0; (void)saHandleInstancePut (&confdb_handle_t_db, handle); ret: return error; } cs_error_t confdb_object_find_start ( confdb_handle_t handle, hdb_handle_t parent_object_handle) { struct confdb_inst *confdb_inst; cs_error_t error = CS_OK; struct iter_context *context; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } context = find_iter_context(&confdb_inst->object_find_head, parent_object_handle); if (!context) { context = malloc(sizeof(struct iter_context)); if (!context) { error = CS_ERR_NO_MEMORY; goto ret; } context->find_handle = 0; context->parent_object_handle = parent_object_handle; list_add(&context->list, &confdb_inst->object_find_head); } /* Start a new find context */ if (context->find_handle) { (void)do_find_destroy(confdb_inst, context->find_handle); context->find_handle = 0; } (void)saHandleInstancePut (&confdb_handle_t_db, handle); ret: return error; } cs_error_t confdb_object_find ( confdb_handle_t handle, hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_handle) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct iter_context *context; struct req_lib_confdb_object_find req_lib_confdb_object_find; struct res_lib_confdb_object_find res_lib_confdb_object_find; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } /* You MUST call confdb_object_find_start first */ context = find_iter_context(&confdb_inst->object_find_head, parent_object_handle); if (!context) { error = CS_ERR_CONTEXT_NOT_FOUND; goto error_exit; } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_object_find(parent_object_handle, &context->find_handle, object_handle, object_name, object_name_len)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_object_find.header.size = sizeof (struct req_lib_confdb_object_find); req_lib_confdb_object_find.header.id = MESSAGE_REQ_CONFDB_OBJECT_FIND; req_lib_confdb_object_find.parent_object_handle = parent_object_handle; req_lib_confdb_object_find.find_handle = context->find_handle; memcpy(req_lib_confdb_object_find.object_name.value, object_name, object_name_len); req_lib_confdb_object_find.object_name.length = object_name_len; iov.iov_base = (char *)&req_lib_confdb_object_find; iov.iov_len = sizeof (struct req_lib_confdb_object_find); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_object_find, sizeof (struct res_lib_confdb_object_find)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_object_find.header.error; *object_handle = res_lib_confdb_object_find.object_handle; context->find_handle = res_lib_confdb_object_find.find_handle; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_object_iter ( confdb_handle_t handle, hdb_handle_t parent_object_handle, hdb_handle_t *object_handle, void *object_name, - int *object_name_len) + size_t *object_name_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct iter_context *context; struct req_lib_confdb_object_iter req_lib_confdb_object_iter; struct res_lib_confdb_object_iter res_lib_confdb_object_iter; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } /* You MUST call confdb_object_iter_start first */ context = find_iter_context(&confdb_inst->object_iter_head, parent_object_handle); if (!context) { error = CS_ERR_CONTEXT_NOT_FOUND; goto error_exit; } if (confdb_inst->standalone) { error = CS_OK; *object_name_len = 0; if (confdb_sa_object_iter(parent_object_handle, &context->find_handle, object_handle, NULL, 0, object_name, object_name_len)) error = CS_ERR_ACCESS; goto sa_exit; } req_lib_confdb_object_iter.header.size = sizeof (struct req_lib_confdb_object_iter); req_lib_confdb_object_iter.header.id = MESSAGE_REQ_CONFDB_OBJECT_ITER; req_lib_confdb_object_iter.parent_object_handle = parent_object_handle; req_lib_confdb_object_iter.find_handle = context->find_handle; iov.iov_base = (char *)&req_lib_confdb_object_iter; iov.iov_len = sizeof (struct req_lib_confdb_object_iter); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_object_iter, sizeof (struct res_lib_confdb_object_iter)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_object_iter.header.error; if (error == CS_OK) { *object_name_len = res_lib_confdb_object_iter.object_name.length; memcpy(object_name, res_lib_confdb_object_iter.object_name.value, *object_name_len); *object_handle = res_lib_confdb_object_iter.object_handle; context->find_handle = res_lib_confdb_object_iter.find_handle; } sa_exit: error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_key_iter ( confdb_handle_t handle, hdb_handle_t parent_object_handle, void *key_name, - int *key_name_len, + size_t *key_name_len, void *value, - int *value_len) + size_t *value_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct iter_context *context; struct req_lib_confdb_key_iter req_lib_confdb_key_iter; struct res_lib_confdb_key_iter res_lib_confdb_key_iter; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } /* You MUST call confdb_key_iter_start first */ context = find_iter_context(&confdb_inst->key_iter_head, parent_object_handle); if (!context) { error = CS_ERR_CONTEXT_NOT_FOUND; goto error_exit; } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_key_iter(parent_object_handle, context->next_entry, key_name, key_name_len, value, value_len)) error = CS_ERR_ACCESS; goto sa_exit; } req_lib_confdb_key_iter.header.size = sizeof (struct req_lib_confdb_key_iter); req_lib_confdb_key_iter.header.id = MESSAGE_REQ_CONFDB_KEY_ITER; req_lib_confdb_key_iter.parent_object_handle = parent_object_handle; req_lib_confdb_key_iter.next_entry= context->next_entry; iov.iov_base = (char *)&req_lib_confdb_key_iter; iov.iov_len = sizeof (struct req_lib_confdb_key_iter); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_key_iter, sizeof (struct res_lib_confdb_key_iter)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res_lib_confdb_key_iter.header.error; if (error == CS_OK) { *key_name_len = res_lib_confdb_key_iter.key_name.length; memcpy(key_name, res_lib_confdb_key_iter.key_name.value, *key_name_len); *value_len = res_lib_confdb_key_iter.value.length; memcpy(value, res_lib_confdb_key_iter.value.value, *value_len); } sa_exit: context->next_entry++; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_write ( confdb_handle_t handle, char *error_text, size_t errbuf_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; mar_req_header_t req; struct res_lib_confdb_write res_lib_confdb_write; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { /* FIXME: set error_text */ return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_write(error_text, errbuf_len)) error = CS_ERR_ACCESS; goto error_exit; } req.size = sizeof (mar_req_header_t); req.id = MESSAGE_REQ_CONFDB_WRITE; iov.iov_base = (char *)&req; iov.iov_len = sizeof (mar_req_header_t); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_write, sizeof (struct res_lib_confdb_write)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { /* FIXME: set error_text */ goto error_exit; } error = res_lib_confdb_write.header.error; if (res_lib_confdb_write.error.length) { memcpy(error_text, res_lib_confdb_write.error.value, MIN(res_lib_confdb_write.error.length,errbuf_len)); error_text[errbuf_len-1] = '\0'; } error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_reload ( confdb_handle_t handle, int flush, char *error_text, size_t errbuf_len) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct res_lib_confdb_reload res_lib_confdb_reload; struct req_lib_confdb_reload req_lib_confdb_reload; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { /* FIXME: set error_text */ return (error); } if (confdb_inst->standalone) { error = CS_OK; if (confdb_sa_reload(flush, error_text, errbuf_len)) error = CS_ERR_ACCESS; goto error_exit; } req_lib_confdb_reload.header.size = sizeof (req_lib_confdb_reload); req_lib_confdb_reload.header.id = MESSAGE_REQ_CONFDB_RELOAD; req_lib_confdb_reload.flush = flush; iov.iov_base = (char *)&req_lib_confdb_reload; iov.iov_len = sizeof (req_lib_confdb_reload); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res_lib_confdb_reload, sizeof (struct res_lib_confdb_reload)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { /* FIXME: set error_text */ goto error_exit; } error = res_lib_confdb_reload.header.error; if(res_lib_confdb_reload.error.length) { memcpy(error_text, res_lib_confdb_reload.error.value, MIN(res_lib_confdb_reload.error.length,errbuf_len)); error_text[errbuf_len-1] = '\0'; } error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_track_changes ( confdb_handle_t handle, hdb_handle_t object_handle, unsigned int flags) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; struct req_lib_confdb_object_track_start req; mar_res_header_t res; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_ERR_NOT_SUPPORTED; goto error_exit; } req.header.size = sizeof (struct req_lib_confdb_object_track_start); req.header.id = MESSAGE_REQ_CONFDB_TRACK_START; req.object_handle = object_handle; req.flags = flags; iov.iov_base = (char *)&req; iov.iov_len = sizeof (struct req_lib_confdb_object_track_start); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (mar_res_header_t)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } cs_error_t confdb_stop_track_changes (confdb_handle_t handle) { cs_error_t error; struct confdb_inst *confdb_inst; struct iovec iov; mar_req_header_t req; mar_res_header_t res; error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void *)&confdb_inst); if (error != CS_OK) { return (error); } if (confdb_inst->standalone) { error = CS_ERR_NOT_SUPPORTED; goto error_exit; } req.size = sizeof (mar_req_header_t); req.id = MESSAGE_REQ_CONFDB_TRACK_STOP; iov.iov_base = (char *)&req; iov.iov_len = sizeof (mar_req_header_t); pthread_mutex_lock (&confdb_inst->response_mutex); error = coroipcc_msg_send_reply_receive ( confdb_inst->ipc_ctx, &iov, 1, &res, sizeof (mar_res_header_t)); pthread_mutex_unlock (&confdb_inst->response_mutex); if (error != CS_OK) { goto error_exit; } error = res.error; error_exit: (void)saHandleInstancePut (&confdb_handle_t_db, handle); return (error); } diff --git a/lib/sa-confdb.c b/lib/sa-confdb.c index 8ace1044..3b7828b7 100644 --- a/lib/sa-confdb.c +++ b/lib/sa-confdb.c @@ -1,411 +1,411 @@ /* * Copyright (c) 2008, 2009 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ /* * Provides stand-alone access to data in the corosync object database * when aisexec is not running. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sa-confdb.h" static struct objdb_iface_ver0 *objdb; static int num_config_modules; static struct config_iface_ver0 *config_modules[128]; void main_get_config_modules(struct config_iface_ver0 ***modules, int *num); char *strstr_rs (const char *haystack, const char *needle); static int load_objdb(void) { hdb_handle_t objdb_handle; void *objdb_p; int res; /* * Load the object database interface */ res = lcr_ifact_reference ( &objdb_handle, "objdb", 0, &objdb_p, (void *)0); if (res == -1) { return -1; } objdb = (struct objdb_iface_ver0 *)objdb_p; objdb->objdb_init (); return CS_OK; } static int load_config(void) { char *config_iface; char *iface; int res; hdb_handle_t config_handle; hdb_handle_t config_version = 0; void *config_p; struct config_iface_ver0 *config; char *error_string; /* User's bootstrap config service */ config_iface = getenv("COROSYNC_DEFAULT_CONFIG_IFACE"); if (!config_iface) { if ((config_iface = strdup("corosync_parser")) == NULL) { return -1; } } /* Make a copy so we can deface it with strtok */ if ((config_iface = strdup(config_iface)) == NULL) { return -1; } iface = strtok(config_iface, ":"); while (iface) { res = lcr_ifact_reference ( &config_handle, iface, config_version, &config_p, 0); config = (struct config_iface_ver0 *)config_p; if (res == -1) { return -1; } res = config->config_readconfig(objdb, &error_string); if (res == -1) { return -1; } config_modules[num_config_modules++] = config; iface = strtok(NULL, ":"); } if (config_iface) free(config_iface); return CS_OK; } /* Needed by objdb when it writes back the configuration */ void main_get_config_modules(struct config_iface_ver0 ***modules, int *num) { *modules = config_modules; *num = num_config_modules; } /* Needed by some modules ... */ char *strstr_rs (const char *haystack, const char *needle) { char *end_address; char *new_needle; new_needle = (char *)strdup (needle); new_needle[strlen (new_needle) - 1] = '\0'; end_address = strstr (haystack, new_needle); if (end_address) { end_address += strlen (new_needle); end_address = strstr (end_address, needle + strlen (new_needle)); } if (end_address) { end_address += 1; /* skip past { or = */ do { if (*end_address == '\t' || *end_address == ' ') { end_address++; } else { break; } } while (*end_address != '\0'); } free (new_needle); return (end_address); } int confdb_sa_init (void) { int res; res = load_objdb(); if (res != CS_OK) return res; res = load_config(); return res; } int confdb_sa_object_create ( hdb_handle_t parent_object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, hdb_handle_t *object_handle) { return objdb->object_create(parent_object_handle, object_handle, object_name, object_name_len); } int confdb_sa_object_destroy ( hdb_handle_t object_handle) { return objdb->object_destroy(object_handle); } int confdb_sa_object_parent_get ( hdb_handle_t object_handle, hdb_handle_t *parent_object_handle) { return objdb->object_parent_get(object_handle, parent_object_handle); } int confdb_sa_key_create ( hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *value, - int value_len) + size_t value_len) { return objdb->object_key_create(parent_object_handle, key_name, key_name_len, value, value_len); } int confdb_sa_key_delete ( hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *value, - int value_len) + size_t value_len) { return objdb->object_key_delete(parent_object_handle, key_name, key_name_len); } int confdb_sa_key_get ( hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, void *value, - int *value_len) + size_t *value_len) { int res; void *kvalue; res = objdb->object_key_get(parent_object_handle, key_name, key_name_len, &kvalue, value_len); if (!res) { memcpy(value, kvalue, *value_len); } return res; } int confdb_sa_key_increment ( hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, unsigned int *value) { int res; res = objdb->object_key_increment(parent_object_handle, key_name, key_name_len, value); return res; } int confdb_sa_key_decrement ( hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, unsigned int *value) { int res; res = objdb->object_key_decrement(parent_object_handle, key_name, key_name_len, value); return res; } int confdb_sa_key_replace ( hdb_handle_t parent_object_handle, const void *key_name, - int key_name_len, + size_t key_name_len, const void *old_value, - int old_value_len, + size_t old_value_len, const void *new_value, - int new_value_len) + size_t new_value_len) { return objdb->object_key_replace(parent_object_handle, key_name, key_name_len, new_value, new_value_len); } int confdb_sa_write (char *error_text, size_t errbuf_len) { const char *errtext; int ret; ret = objdb->object_write_config(&errtext); if (!ret) { strncpy(error_text, errtext, errbuf_len); if (errbuf_len > 0) error_text[errbuf_len-1] = '\0'; } return ret; } int confdb_sa_reload ( int flush, char *error_text, size_t errbuf_len) { char *errtext; int ret; ret = objdb->object_reload_config(flush, (const char **) &errtext); if (!ret) { strncpy(error_text, errtext, errbuf_len); if (errbuf_len > 0) error_text[errbuf_len-1] = '\0'; } return ret; } int confdb_sa_object_find ( hdb_handle_t parent_object_handle, hdb_handle_t *find_handle, hdb_handle_t *object_handle, const void *object_name, - int object_name_len) + size_t object_name_len) { int res; if (!*find_handle) { objdb->object_find_create(parent_object_handle, object_name, object_name_len, find_handle); } res = objdb->object_find_next(*find_handle, object_handle); return res; } int confdb_sa_object_iter ( hdb_handle_t parent_object_handle, hdb_handle_t *find_handle, hdb_handle_t *object_handle, const void *object_name, - int object_name_len, + size_t object_name_len, void *found_object_name, - int *found_object_name_len) + size_t *found_object_name_len) { int res; if (!*find_handle) { objdb->object_find_create(parent_object_handle, object_name, object_name_len, find_handle); } res = objdb->object_find_next(*find_handle, object_handle); /* Return object name if we were called as _iter */ if (!res) { objdb->object_name_get(*object_handle, found_object_name, found_object_name_len); } return res; } int confdb_sa_key_iter ( hdb_handle_t parent_object_handle, hdb_handle_t start_pos, void *key_name, - int *key_name_len, + size_t *key_name_len, void *value, - int *value_len) + size_t *value_len) { int res; void *kname, *kvalue; res = objdb->object_key_iter_from(parent_object_handle, start_pos, &kname, key_name_len, &kvalue, value_len); if (!res) { memcpy(key_name, kname, *key_name_len); memcpy(value, kvalue, *value_len); } return res; } int confdb_sa_find_destroy(hdb_handle_t find_handle) { return objdb->object_find_destroy(find_handle); } diff --git a/lib/sa-confdb.h b/lib/sa-confdb.h index 402740a4..102eaf5f 100644 --- a/lib/sa-confdb.h +++ b/lib/sa-confdb.h @@ -1,50 +1,93 @@ /* * Copyright (c) 2008, 2009 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ extern int confdb_sa_init(void); -extern int confdb_sa_object_create(hdb_handle_t parent_object_handle, const void *object_name, int object_name_len, hdb_handle_t *object_handle); +extern int confdb_sa_object_create(hdb_handle_t parent_object_handle, + const void *object_name, + size_t object_name_len, + hdb_handle_t *object_handle); extern int confdb_sa_object_destroy(hdb_handle_t object_handle); -extern int confdb_sa_object_parent_get(hdb_handle_t object_handle, hdb_handle_t *parent_object_handle); -extern int confdb_sa_key_create(hdb_handle_t parent_object_handle, const void *key_name, int key_name_len, const void *value, int value_len); -extern int confdb_sa_key_delete(hdb_handle_t parent_object_handle, const void *key_name, int key_name_len, const void *value, int value_len); -extern int confdb_sa_key_get(hdb_handle_t parent_object_handle, const void *key_name, int key_name_len, void *value, int *value_len); -extern int confdb_sa_key_replace(hdb_handle_t parent_object_handle, const void *key_name, int key_name_len, const void *old_value, int old_value_len, const void *new_value, int new_value_len); -extern int confdb_sa_object_find(hdb_handle_t parent_object_handle, hdb_handle_t *find_handle, hdb_handle_t *object_handle, const void *object_name, int object_name_len); -extern int confdb_sa_object_iter(hdb_handle_t parent_object_handle, hdb_handle_t *find_handle, hdb_handle_t *object_handle, const void *object_name, int object_name_len, void *found_object_name, int *found_object_name_len); -extern int confdb_sa_key_iter(hdb_handle_t parent_object_handle, hdb_handle_t start_pos, void *key_name, int *key_name_len, void *value, int *value_len); -extern int confdb_sa_key_increment(hdb_handle_t parent_object_handle, const void *key_name, int key_name_len, unsigned int *value); -extern int confdb_sa_key_decrement(hdb_handle_t parent_object_handle, const void *key_name, int key_name_len, unsigned int *value); +extern int confdb_sa_object_parent_get(hdb_handle_t object_handle, + hdb_handle_t *parent_object_handle); +extern int confdb_sa_key_create(hdb_handle_t parent_object_handle, + const void *key_name, + size_t key_name_len, + const void *value, + size_t value_len); +extern int confdb_sa_key_delete(hdb_handle_t parent_object_handle, + const void *key_name, + size_t key_name_len, + const void *value, + size_t value_len); +extern int confdb_sa_key_get(hdb_handle_t parent_object_handle, + const void *key_name, + size_t key_name_len, + void *value, + size_t *value_len); +extern int confdb_sa_key_replace(hdb_handle_t parent_object_handle, + const void *key_name, + size_t key_name_len, + const void *old_value, + size_t old_value_len, + const void *new_value, + size_t new_value_len); +extern int confdb_sa_object_find(hdb_handle_t parent_object_handle, + hdb_handle_t *find_handle, + hdb_handle_t *object_handle, + const void *object_name, + size_t object_name_len); +extern int confdb_sa_object_iter(hdb_handle_t parent_object_handle, + hdb_handle_t *find_handle, + hdb_handle_t *object_handle, + const void *object_name, + size_t object_name_len, + void *found_object_name, + size_t *found_object_name_len); +extern int confdb_sa_key_iter(hdb_handle_t parent_object_handle, + hdb_handle_t start_pos, + void *key_name, + size_t *key_name_len, + void *value, + size_t *value_len); +extern int confdb_sa_key_increment(hdb_handle_t parent_object_handle, + const void *key_name, + size_t key_name_len, + unsigned int *value); +extern int confdb_sa_key_decrement(hdb_handle_t parent_object_handle, + const void *key_name, + size_t key_name_len, + unsigned int *value); extern int confdb_sa_find_destroy(hdb_handle_t find_handle); extern int confdb_sa_write(char *error_text, size_t errbuf_len); extern int confdb_sa_reload(int flush, char *error_text, size_t errbuf_len); diff --git a/services/confdb.c b/services/confdb.c index 45086bfc..0a9b723b 100644 --- a/services/confdb.c +++ b/services/confdb.c @@ -1,717 +1,718 @@ /* * Copyright (c) 2008-2009 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS AND CONTIBUTORS "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 COPYRIGHT OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include LOGSYS_DECLARE_SUBSYS ("CONFDB", LOG_INFO); static struct corosync_api_v1 *api; static int confdb_exec_init_fn ( struct corosync_api_v1 *corosync_api); static int confdb_lib_init_fn (void *conn); static int confdb_lib_exit_fn (void *conn); static void message_handler_req_lib_confdb_object_create (void *conn, void *message); static void message_handler_req_lib_confdb_object_destroy (void *conn, void *message); static void message_handler_req_lib_confdb_object_find_destroy (void *conn, void *message); static void message_handler_req_lib_confdb_key_create (void *conn, void *message); static void message_handler_req_lib_confdb_key_get (void *conn, void *message); static void message_handler_req_lib_confdb_key_replace (void *conn, void *message); static void message_handler_req_lib_confdb_key_delete (void *conn, void *message); static void message_handler_req_lib_confdb_key_iter (void *conn, void *message); static void message_handler_req_lib_confdb_key_increment (void *conn, void *message); static void message_handler_req_lib_confdb_key_decrement (void *conn, void *message); static void message_handler_req_lib_confdb_object_iter (void *conn, void *message); static void message_handler_req_lib_confdb_object_find (void *conn, void *message); static void message_handler_req_lib_confdb_object_parent_get (void *conn, void *message); static void message_handler_req_lib_confdb_write (void *conn, void *message); static void message_handler_req_lib_confdb_reload (void *conn, void *message); static void message_handler_req_lib_confdb_track_start (void *conn, void *message); static void message_handler_req_lib_confdb_track_stop (void *conn, void *message); static void confdb_notify_lib_of_key_change( object_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const void *object_name_pt, int object_name_len, const void *key_name_pt, int key_name_len, const void *key_value_pt, int key_value_len, void *priv_data_pt); static void confdb_notify_lib_of_new_object( hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const uint8_t *name_pt, int name_len, void *priv_data_pt); static void confdb_notify_lib_of_destroyed_object( hdb_handle_t parent_object_handle, const uint8_t *name_pt, int name_len, void *priv_data_pt); /* * Library Handler Definition */ static struct corosync_lib_handler confdb_lib_engine[] = { { /* 0 */ .lib_handler_fn = message_handler_req_lib_confdb_object_create, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_OBJECT_CREATE, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 1 */ .lib_handler_fn = message_handler_req_lib_confdb_object_destroy, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_OBJECT_DESTROY, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 2 */ .lib_handler_fn = message_handler_req_lib_confdb_object_find, .response_size = sizeof (struct res_lib_confdb_object_find), .response_id = MESSAGE_RES_CONFDB_OBJECT_FIND, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 3 */ .lib_handler_fn = message_handler_req_lib_confdb_key_create, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_KEY_CREATE, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 4 */ .lib_handler_fn = message_handler_req_lib_confdb_key_get, .response_size = sizeof (struct res_lib_confdb_key_get), .response_id = MESSAGE_RES_CONFDB_KEY_GET, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 5 */ .lib_handler_fn = message_handler_req_lib_confdb_key_replace, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_KEY_REPLACE, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 6 */ .lib_handler_fn = message_handler_req_lib_confdb_key_delete, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_KEY_DELETE, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 7 */ .lib_handler_fn = message_handler_req_lib_confdb_object_iter, .response_size = sizeof (struct res_lib_confdb_object_iter), .response_id = MESSAGE_RES_CONFDB_OBJECT_ITER, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 8 */ .lib_handler_fn = message_handler_req_lib_confdb_object_parent_get, .response_size = sizeof (struct res_lib_confdb_object_parent_get), .response_id = MESSAGE_RES_CONFDB_OBJECT_PARENT_GET, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 9 */ .lib_handler_fn = message_handler_req_lib_confdb_key_iter, .response_size = sizeof (struct res_lib_confdb_key_iter), .response_id = MESSAGE_RES_CONFDB_KEY_ITER, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 10 */ .lib_handler_fn = message_handler_req_lib_confdb_track_start, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_TRACK_START, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 11 */ .lib_handler_fn = message_handler_req_lib_confdb_track_stop, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_TRACK_STOP, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 12 */ .lib_handler_fn = message_handler_req_lib_confdb_write, .response_size = sizeof (struct res_lib_confdb_write), .response_id = MESSAGE_RES_CONFDB_WRITE, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 13 */ .lib_handler_fn = message_handler_req_lib_confdb_reload, .response_size = sizeof (struct res_lib_confdb_reload), .response_id = MESSAGE_RES_CONFDB_RELOAD, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 14 */ .lib_handler_fn = message_handler_req_lib_confdb_object_find_destroy, .response_size = sizeof (mar_res_header_t), .response_id = MESSAGE_RES_CONFDB_OBJECT_FIND_DESTROY, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 15 */ .lib_handler_fn = message_handler_req_lib_confdb_key_increment, .response_size = sizeof (struct res_lib_confdb_key_incdec), .response_id = MESSAGE_RES_CONFDB_KEY_INCREMENT, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 16 */ .lib_handler_fn = message_handler_req_lib_confdb_key_decrement, .response_size = sizeof (struct res_lib_confdb_key_incdec), .response_id = MESSAGE_RES_CONFDB_KEY_DECREMENT, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED }, }; struct corosync_service_engine confdb_service_engine = { .name = "corosync cluster config database access v1.01", .id = CONFDB_SERVICE, .private_data_size = 0, .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED, .allow_inquorate = CS_LIB_ALLOW_INQUORATE, .lib_init_fn = confdb_lib_init_fn, .lib_exit_fn = confdb_lib_exit_fn, .lib_engine = confdb_lib_engine, .lib_engine_count = sizeof (confdb_lib_engine) / sizeof (struct corosync_lib_handler), .exec_init_fn = confdb_exec_init_fn, }; /* * Dynamic loader definition */ static struct corosync_service_engine *confdb_get_service_engine_ver0 (void); static struct corosync_service_engine_iface_ver0 confdb_service_engine_iface = { .corosync_get_service_engine_ver0 = confdb_get_service_engine_ver0 }; static struct lcr_iface corosync_confdb_ver0[1] = { { .name = "corosync_confdb", .version = 0, .versions_replace = 0, .versions_replace_count = 0, .dependencies = 0, .dependency_count = 0, .constructor = NULL, .destructor = NULL, .interfaces = NULL } }; static struct lcr_comp confdb_comp_ver0 = { .iface_count = 1, .ifaces = corosync_confdb_ver0 }; static struct corosync_service_engine *confdb_get_service_engine_ver0 (void) { return (&confdb_service_engine); } __attribute__ ((constructor)) static void confdb_comp_register (void) { lcr_interfaces_set (&corosync_confdb_ver0[0], &confdb_service_engine_iface); lcr_component_register (&confdb_comp_ver0); } static int confdb_exec_init_fn ( struct corosync_api_v1 *corosync_api) { api = corosync_api; return 0; } static int confdb_lib_init_fn (void *conn) { log_printf(LOG_LEVEL_DEBUG, "lib_init_fn: conn=%p\n", conn); return (0); } static int confdb_lib_exit_fn (void *conn) { log_printf(LOG_LEVEL_DEBUG, "exit_fn for conn=%p\n", conn); /* cleanup the object trackers for this client. */ api->object_track_stop(confdb_notify_lib_of_key_change, confdb_notify_lib_of_new_object, confdb_notify_lib_of_destroyed_object, NULL, conn); return (0); } static void message_handler_req_lib_confdb_object_create (void *conn, void *message) { struct req_lib_confdb_object_create *req_lib_confdb_object_create = (struct req_lib_confdb_object_create *)message; struct res_lib_confdb_object_create res_lib_confdb_object_create; hdb_handle_t object_handle; int ret = CS_OK; if (api->object_create(req_lib_confdb_object_create->parent_object_handle, &object_handle, req_lib_confdb_object_create->object_name.value, req_lib_confdb_object_create->object_name.length)) ret = CS_ERR_ACCESS; res_lib_confdb_object_create.object_handle = object_handle; res_lib_confdb_object_create.header.size = sizeof(res_lib_confdb_object_create); res_lib_confdb_object_create.header.id = MESSAGE_RES_CONFDB_OBJECT_CREATE; res_lib_confdb_object_create.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_object_create, sizeof(res_lib_confdb_object_create)); } static void message_handler_req_lib_confdb_object_destroy (void *conn, void *message) { struct req_lib_confdb_object_destroy *req_lib_confdb_object_destroy = (struct req_lib_confdb_object_destroy *)message; mar_res_header_t res; int ret = CS_OK; if (api->object_destroy(req_lib_confdb_object_destroy->object_handle)) ret = CS_ERR_ACCESS; res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_OBJECT_DESTROY; res.error = ret; api->ipc_response_send(conn, &res, sizeof(res)); } static void message_handler_req_lib_confdb_object_find_destroy (void *conn, void *message) { struct req_lib_confdb_object_find_destroy *req_lib_confdb_object_find_destroy = (struct req_lib_confdb_object_find_destroy *)message; mar_res_header_t res; int ret = CS_OK; if (api->object_find_destroy(req_lib_confdb_object_find_destroy->find_handle)) ret = CS_ERR_ACCESS; res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_OBJECT_FIND_DESTROY; res.error = ret; api->ipc_response_send(conn, &res, sizeof(res)); } static void message_handler_req_lib_confdb_key_create (void *conn, void *message) { struct req_lib_confdb_key_create *req_lib_confdb_key_create = (struct req_lib_confdb_key_create *)message; mar_res_header_t res; int ret = CS_OK; if (api->object_key_create(req_lib_confdb_key_create->object_handle, req_lib_confdb_key_create->key_name.value, req_lib_confdb_key_create->key_name.length, req_lib_confdb_key_create->value.value, req_lib_confdb_key_create->value.length)) ret = CS_ERR_ACCESS; res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_KEY_CREATE; res.error = ret; api->ipc_response_send(conn, &res, sizeof(res)); } static void message_handler_req_lib_confdb_key_get (void *conn, void *message) { struct req_lib_confdb_key_get *req_lib_confdb_key_get = (struct req_lib_confdb_key_get *)message; struct res_lib_confdb_key_get res_lib_confdb_key_get; int value_len; void *value; int ret = CS_OK; if (api->object_key_get(req_lib_confdb_key_get->parent_object_handle, req_lib_confdb_key_get->key_name.value, req_lib_confdb_key_get->key_name.length, &value, &value_len)) ret = CS_ERR_ACCESS; else { memcpy(res_lib_confdb_key_get.value.value, value, value_len); res_lib_confdb_key_get.value.length = value_len; } res_lib_confdb_key_get.header.size = sizeof(res_lib_confdb_key_get); res_lib_confdb_key_get.header.id = MESSAGE_RES_CONFDB_KEY_GET; res_lib_confdb_key_get.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_key_get, sizeof(res_lib_confdb_key_get)); } static void message_handler_req_lib_confdb_key_increment (void *conn, void *message) { struct req_lib_confdb_key_get *req_lib_confdb_key_get = (struct req_lib_confdb_key_get *)message; struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; int ret = CS_OK; if (api->object_key_increment(req_lib_confdb_key_get->parent_object_handle, req_lib_confdb_key_get->key_name.value, req_lib_confdb_key_get->key_name.length, &res_lib_confdb_key_incdec.value)) ret = CS_ERR_ACCESS; res_lib_confdb_key_incdec.header.size = sizeof(res_lib_confdb_key_incdec); res_lib_confdb_key_incdec.header.id = MESSAGE_RES_CONFDB_KEY_INCREMENT; res_lib_confdb_key_incdec.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_key_incdec, sizeof(res_lib_confdb_key_incdec)); } static void message_handler_req_lib_confdb_key_decrement (void *conn, void *message) { struct req_lib_confdb_key_get *req_lib_confdb_key_get = (struct req_lib_confdb_key_get *)message; struct res_lib_confdb_key_incdec res_lib_confdb_key_incdec; int ret = CS_OK; if (api->object_key_decrement(req_lib_confdb_key_get->parent_object_handle, req_lib_confdb_key_get->key_name.value, req_lib_confdb_key_get->key_name.length, &res_lib_confdb_key_incdec.value)) ret = CS_ERR_ACCESS; res_lib_confdb_key_incdec.header.size = sizeof(res_lib_confdb_key_incdec); res_lib_confdb_key_incdec.header.id = MESSAGE_RES_CONFDB_KEY_DECREMENT; res_lib_confdb_key_incdec.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_key_incdec, sizeof(res_lib_confdb_key_incdec)); } static void message_handler_req_lib_confdb_key_replace (void *conn, void *message) { - struct req_lib_confdb_key_replace *req_lib_confdb_key_replace = (struct req_lib_confdb_key_replace *)message; + const struct req_lib_confdb_key_replace *req_lib_confdb_key_replace + = message; mar_res_header_t res; int ret = CS_OK; if (api->object_key_replace(req_lib_confdb_key_replace->object_handle, req_lib_confdb_key_replace->key_name.value, req_lib_confdb_key_replace->key_name.length, req_lib_confdb_key_replace->new_value.value, req_lib_confdb_key_replace->new_value.length)) ret = CS_ERR_ACCESS; res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_KEY_REPLACE; res.error = ret; api->ipc_response_send(conn, &res, sizeof(res)); } static void message_handler_req_lib_confdb_key_delete (void *conn, void *message) { struct req_lib_confdb_key_delete *req_lib_confdb_key_delete = (struct req_lib_confdb_key_delete *)message; mar_res_header_t res; int ret = CS_OK; if (api->object_key_delete(req_lib_confdb_key_delete->object_handle, req_lib_confdb_key_delete->key_name.value, req_lib_confdb_key_delete->key_name.length)) ret = CS_ERR_ACCESS; res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_KEY_DELETE; res.error = ret; api->ipc_response_send(conn, &res, sizeof(res)); } static void message_handler_req_lib_confdb_object_parent_get (void *conn, void *message) { struct req_lib_confdb_object_parent_get *req_lib_confdb_object_parent_get = (struct req_lib_confdb_object_parent_get *)message; struct res_lib_confdb_object_parent_get res_lib_confdb_object_parent_get; hdb_handle_t object_handle; int ret = CS_OK; if (api->object_parent_get(req_lib_confdb_object_parent_get->object_handle, &object_handle)) ret = CS_ERR_ACCESS; res_lib_confdb_object_parent_get.parent_object_handle = object_handle; res_lib_confdb_object_parent_get.header.size = sizeof(res_lib_confdb_object_parent_get); res_lib_confdb_object_parent_get.header.id = MESSAGE_RES_CONFDB_OBJECT_CREATE; res_lib_confdb_object_parent_get.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_object_parent_get, sizeof(res_lib_confdb_object_parent_get)); } static void message_handler_req_lib_confdb_key_iter (void *conn, void *message) { struct req_lib_confdb_key_iter *req_lib_confdb_key_iter = (struct req_lib_confdb_key_iter *)message; struct res_lib_confdb_key_iter res_lib_confdb_key_iter; void *key_name; int key_name_len; void *value; int value_len; int ret = CS_OK; if (api->object_key_iter_from(req_lib_confdb_key_iter->parent_object_handle, req_lib_confdb_key_iter->next_entry, &key_name, &key_name_len, &value, &value_len)) ret = CS_ERR_ACCESS; else { memcpy(res_lib_confdb_key_iter.key_name.value, key_name, key_name_len); memcpy(res_lib_confdb_key_iter.value.value, value, value_len); res_lib_confdb_key_iter.key_name.length = key_name_len; res_lib_confdb_key_iter.value.length = value_len; } res_lib_confdb_key_iter.header.size = sizeof(res_lib_confdb_key_iter); res_lib_confdb_key_iter.header.id = MESSAGE_RES_CONFDB_KEY_ITER; res_lib_confdb_key_iter.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_key_iter, sizeof(res_lib_confdb_key_iter)); } static void message_handler_req_lib_confdb_object_iter (void *conn, void *message) { struct req_lib_confdb_object_iter *req_lib_confdb_object_iter = (struct req_lib_confdb_object_iter *)message; struct res_lib_confdb_object_iter res_lib_confdb_object_iter; int object_name_len; int ret = CS_OK; if (!req_lib_confdb_object_iter->find_handle) { api->object_find_create(req_lib_confdb_object_iter->parent_object_handle, NULL, 0, &res_lib_confdb_object_iter.find_handle); } else res_lib_confdb_object_iter.find_handle = req_lib_confdb_object_iter->find_handle; if (api->object_find_next(res_lib_confdb_object_iter.find_handle, &res_lib_confdb_object_iter.object_handle)) { ret = CS_ERR_ACCESS; api->object_find_destroy(res_lib_confdb_object_iter.find_handle); } else { api->object_name_get(res_lib_confdb_object_iter.object_handle, (char *)res_lib_confdb_object_iter.object_name.value, &object_name_len); res_lib_confdb_object_iter.object_name.length = object_name_len; } res_lib_confdb_object_iter.header.size = sizeof(res_lib_confdb_object_iter); res_lib_confdb_object_iter.header.id = MESSAGE_RES_CONFDB_OBJECT_ITER; res_lib_confdb_object_iter.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_object_iter, sizeof(res_lib_confdb_object_iter)); } static void message_handler_req_lib_confdb_object_find (void *conn, void *message) { struct req_lib_confdb_object_find *req_lib_confdb_object_find = (struct req_lib_confdb_object_find *)message; struct res_lib_confdb_object_find res_lib_confdb_object_find; int ret = CS_OK; if (!req_lib_confdb_object_find->find_handle) { api->object_find_create(req_lib_confdb_object_find->parent_object_handle, req_lib_confdb_object_find->object_name.value, req_lib_confdb_object_find->object_name.length, &res_lib_confdb_object_find.find_handle); } else res_lib_confdb_object_find.find_handle = req_lib_confdb_object_find->find_handle; if (api->object_find_next(res_lib_confdb_object_find.find_handle, &res_lib_confdb_object_find.object_handle)) { ret = CS_ERR_ACCESS; api->object_find_destroy(res_lib_confdb_object_find.find_handle); } res_lib_confdb_object_find.header.size = sizeof(res_lib_confdb_object_find); res_lib_confdb_object_find.header.id = MESSAGE_RES_CONFDB_OBJECT_FIND; res_lib_confdb_object_find.header.error = ret; api->ipc_response_send(conn, &res_lib_confdb_object_find, sizeof(res_lib_confdb_object_find)); } static void message_handler_req_lib_confdb_write (void *conn, void *message) { struct res_lib_confdb_write res_lib_confdb_write; int ret = CS_OK; const char *error_string = NULL; if (api->object_write_config(&error_string)) ret = CS_ERR_ACCESS; res_lib_confdb_write.header.size = sizeof(res_lib_confdb_write); res_lib_confdb_write.header.id = MESSAGE_RES_CONFDB_WRITE; res_lib_confdb_write.header.error = ret; if (error_string) { strcpy((char *)res_lib_confdb_write.error.value, error_string); res_lib_confdb_write.error.length = strlen(error_string) + 1; } else res_lib_confdb_write.error.length = 0; api->ipc_response_send(conn, &res_lib_confdb_write, sizeof(res_lib_confdb_write)); } static void message_handler_req_lib_confdb_reload (void *conn, void *message) { struct req_lib_confdb_reload *req_lib_confdb_reload = (struct req_lib_confdb_reload *)message; struct res_lib_confdb_reload res_lib_confdb_reload; int ret = CS_OK; const char *error_string = NULL; if (api->object_reload_config(req_lib_confdb_reload->flush, &error_string)) ret = CS_ERR_ACCESS; res_lib_confdb_reload.header.size = sizeof(res_lib_confdb_reload); res_lib_confdb_reload.header.id = MESSAGE_RES_CONFDB_RELOAD; res_lib_confdb_reload.header.error = ret; if(error_string) { strcpy((char *)res_lib_confdb_reload.error.value, error_string); res_lib_confdb_reload.error.length = strlen(error_string) + 1; } else res_lib_confdb_reload.error.length = 0; api->ipc_response_send(conn, &res_lib_confdb_reload, sizeof(res_lib_confdb_reload)); } static void confdb_notify_lib_of_key_change(object_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const void *object_name_pt, int object_name_len, const void *key_name_pt, int key_name_len, const void *key_value_pt, int key_value_len, void *priv_data_pt) { struct res_lib_confdb_key_change_callback res; res.header.size = sizeof(res); res.header.id = MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK; res.header.error = CS_OK; // handle & type res.change_type = change_type; res.parent_object_handle = parent_object_handle; res.object_handle = object_handle; //object memcpy(res.object_name.value, object_name_pt, object_name_len); res.object_name.length = object_name_len; //key name memcpy(res.key_name.value, key_name_pt, key_name_len); res.key_name.length = key_name_len; //key value memcpy(res.key_value.value, key_value_pt, key_value_len); res.key_value.length = key_value_len; api->ipc_dispatch_send(priv_data_pt, &res, sizeof(res)); } static void confdb_notify_lib_of_new_object(hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const uint8_t *name_pt, int name_len, void *priv_data_pt) { struct res_lib_confdb_object_create_callback res; res.header.size = sizeof(res); res.header.id = MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK; res.header.error = CS_OK; res.parent_object_handle = parent_object_handle; res.object_handle = object_handle; memcpy(res.name.value, name_pt, name_len); res.name.length = name_len; api->ipc_dispatch_send(priv_data_pt, &res, sizeof(res)); } static void confdb_notify_lib_of_destroyed_object( hdb_handle_t parent_object_handle, const uint8_t *name_pt, int name_len, void *priv_data_pt) { struct res_lib_confdb_object_destroy_callback res; res.header.size = sizeof(res); res.header.id = MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK; res.header.error = CS_OK; res.parent_object_handle = parent_object_handle; memcpy(res.name.value, name_pt, name_len); res.name.length = name_len; api->ipc_dispatch_send(priv_data_pt, &res, sizeof(res)); } static void message_handler_req_lib_confdb_track_start (void *conn, void *message) { struct req_lib_confdb_object_track_start *req = (struct req_lib_confdb_object_track_start *)message; mar_res_header_t res; api->object_track_start(req->object_handle, req->flags, confdb_notify_lib_of_key_change, confdb_notify_lib_of_new_object, confdb_notify_lib_of_destroyed_object, NULL, conn); res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_TRACK_START; res.error = CS_OK; api->ipc_response_send(conn, &res, sizeof(res)); } static void message_handler_req_lib_confdb_track_stop (void *conn, void *message) { mar_res_header_t res; api->object_track_stop(confdb_notify_lib_of_key_change, confdb_notify_lib_of_new_object, confdb_notify_lib_of_destroyed_object, NULL, conn); res.size = sizeof(res); res.id = MESSAGE_RES_CONFDB_TRACK_STOP; res.error = CS_OK; api->ipc_response_send(conn, &res, sizeof(res)); } diff --git a/services/votequorum.c b/services/votequorum.c index 784d2cca..635b9830 100644 --- a/services/votequorum.c +++ b/services/votequorum.c @@ -1,1699 +1,1700 @@ /* * Copyright (c) 2009 Red Hat, Inc. * * All rights reserved. * * Author: Christine Caulfield (ccaulfie@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - 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. * - Neither the name of the MontaVista Software, Inc. 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 COPYRIGHT HOLDERS AND CONTIBUTORS "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 COPYRIGHT OWNER 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. */ #include #include #ifndef COROSYNC_BSD #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VOTEQUORUM_MAJOR_VERSION 6 #define VOTEQUORUM_MINOR_VERSION 3 #define VOTEQUORUM_PATCH_VERSION 0 /* Silly default to prevent accidents! */ #define DEFAULT_EXPECTED 1024 #define DEFAULT_QDEV_POLL 10000 #define DEFAULT_LEAVE_TMO 10000 LOGSYS_DECLARE_SUBSYS ("VOTEQ", LOG_INFO); enum quorum_message_req_types { MESSAGE_REQ_EXEC_VOTEQUORUM_NODEINFO = 0, MESSAGE_REQ_EXEC_VOTEQUORUM_RECONFIGURE = 1, MESSAGE_REQ_EXEC_VOTEQUORUM_KILLNODE = 2, }; #define NODE_FLAGS_BEENDOWN 1 #define NODE_FLAGS_SEESDISALLOWED 8 #define NODE_FLAGS_HASSTATE 16 #define NODE_FLAGS_QDISK 32 #define NODE_FLAGS_REMOVED 64 #define NODE_FLAGS_US 128 typedef enum { NODESTATE_JOINING=1, NODESTATE_MEMBER, NODESTATE_DEAD, NODESTATE_LEAVING, NODESTATE_DISALLOWED } nodestate_t; /* This structure is tacked onto the start of a cluster message packet for our * own nefarious purposes. */ struct q_protheader { unsigned char tgtport; /* Target port number */ unsigned char srcport; /* Source (originating) port number */ unsigned short pad; unsigned int flags; int srcid; /* Node ID of the sender */ int tgtid; /* Node ID of the target */ } __attribute__((packed)); struct cluster_node { int flags; int node_id; unsigned int expected_votes; unsigned int votes; time_t join_time; nodestate_t state; struct timeval last_hello; /* Only used for quorum devices */ struct list_head list; }; static int quorum_flags; #define VOTEQUORUM_FLAG_FEATURE_DISALLOWED 1 #define VOTEQUORUM_FLAG_FEATURE_TWONODE 1 static int quorum; static int cluster_is_quorate; static int first_trans = 1; static unsigned int quorumdev_poll = DEFAULT_QDEV_POLL; static unsigned int leaving_timeout = DEFAULT_LEAVE_TMO; static struct cluster_node *us; static struct cluster_node *quorum_device = NULL; static char quorum_device_name[VOTEQUORUM_MAX_QDISK_NAME_LEN]; static corosync_timer_handle_t quorum_device_timer; static corosync_timer_handle_t leaving_timer; static struct list_head cluster_members_list; static struct corosync_api_v1 *corosync_api; static struct list_head trackers_list; static unsigned int quorum_members[PROCESSOR_COUNT_MAX+1]; static int quorum_members_entries = 0; static struct memb_ring_id quorum_ringid; static hdb_handle_t group_handle; #define max(a,b) (((a) > (b)) ? (a) : (b)) static struct cluster_node *find_node_by_nodeid(int nodeid); static struct cluster_node *allocate_node(int nodeid); static const char *kill_reason(int reason); static struct corosync_tpg_group quorum_group[1] = { { .group = "VOTEQ", .group_len = 5}, }; #define list_iterate(v, head) \ for (v = (head)->next; v != head; v = v->next) struct quorum_pd { unsigned char track_flags; int tracking_enabled; uint64_t tracking_context; struct list_head list; void *conn; }; /* * Service Interfaces required by service_message_handler struct */ static void votequorum_init(struct corosync_api_v1 *api, quorum_set_quorate_fn_t report); static void quorum_confchg_fn ( enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id); static void quorum_deliver_fn(unsigned int nodeid, struct iovec *iovec, unsigned int iov_len, int endian_conversion_required); static int votequorum_exec_init_fn (struct corosync_api_v1 *corosync_api); static int quorum_lib_init_fn (void *conn); static int quorum_lib_exit_fn (void *conn); static void message_handler_req_exec_quorum_nodeinfo ( void *message, unsigned int nodeid); static void message_handler_req_exec_quorum_reconfigure ( void *message, unsigned int nodeid); static void message_handler_req_exec_quorum_killnode ( void *message, unsigned int nodeid); static void message_handler_req_lib_votequorum_getinfo (void *conn, void *message); static void message_handler_req_lib_votequorum_setexpected (void *conn, void *message); static void message_handler_req_lib_votequorum_setvotes (void *conn, void *message); static void message_handler_req_lib_votequorum_qdisk_register (void *conn, void *message); static void message_handler_req_lib_votequorum_qdisk_unregister (void *conn, void *message); static void message_handler_req_lib_votequorum_qdisk_poll (void *conn, void *message); static void message_handler_req_lib_votequorum_qdisk_getinfo (void *conn, void *message); static void message_handler_req_lib_votequorum_setstate (void *conn, void *message); static void message_handler_req_lib_votequorum_leaving (void *conn, void *message); static void message_handler_req_lib_votequorum_trackstart (void *conn, void *msg); static void message_handler_req_lib_votequorum_trackstop (void *conn, void *msg); static int quorum_exec_send_nodeinfo(void); static int quorum_exec_send_reconfigure(int param, int nodeid, int value); static int quorum_exec_send_killnode(int nodeid, unsigned int reason); static void add_votequorum_config_notification(hdb_handle_t quorum_object_handle); static void recalculate_quorum(int allow_decrease, int by_current_nodes); /* * Library Handler Definition */ static struct corosync_lib_handler quorum_lib_service[] = { { /* 0 */ .lib_handler_fn = message_handler_req_lib_votequorum_getinfo, .response_size = sizeof (struct res_lib_votequorum_getinfo), .response_id = MESSAGE_RES_VOTEQUORUM_GETINFO, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 1 */ .lib_handler_fn = message_handler_req_lib_votequorum_setexpected, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 2 */ .lib_handler_fn = message_handler_req_lib_votequorum_setvotes, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 3 */ .lib_handler_fn = message_handler_req_lib_votequorum_qdisk_register, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 4 */ .lib_handler_fn = message_handler_req_lib_votequorum_qdisk_unregister, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 5 */ .lib_handler_fn = message_handler_req_lib_votequorum_qdisk_poll, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 6 */ .lib_handler_fn = message_handler_req_lib_votequorum_qdisk_getinfo, .response_size = sizeof (struct res_lib_votequorum_qdisk_getinfo), .response_id = MESSAGE_RES_VOTEQUORUM_QDISK_GETINFO, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 7 */ .lib_handler_fn = message_handler_req_lib_votequorum_setstate, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 8 */ .lib_handler_fn = message_handler_req_lib_votequorum_leaving, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 9 */ .lib_handler_fn = message_handler_req_lib_votequorum_trackstart, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED }, { /* 10 */ .lib_handler_fn = message_handler_req_lib_votequorum_trackstop, .response_size = sizeof (struct res_lib_votequorum_status), .response_id = MESSAGE_RES_VOTEQUORUM_STATUS, .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED } }; static quorum_set_quorate_fn_t set_quorum; /* * lcrso object definition */ static struct quorum_services_api_ver1 votequorum_iface_ver0 = { .init = votequorum_init }; static struct corosync_service_engine quorum_service_handler = { .name = "corosync votes quorum service v0.90", .id = VOTEQUORUM_SERVICE, .private_data_size = sizeof (struct quorum_pd), .allow_inquorate = CS_LIB_ALLOW_INQUORATE, .flow_control = COROSYNC_LIB_FLOW_CONTROL_REQUIRED, .lib_init_fn = quorum_lib_init_fn, .lib_exit_fn = quorum_lib_exit_fn, .lib_engine = quorum_lib_service, .lib_engine_count = sizeof (quorum_lib_service) / sizeof (struct corosync_lib_handler), .exec_init_fn = votequorum_exec_init_fn, .exec_engine = NULL, .exec_engine_count = 0, .confchg_fn = NULL, }; /* * Dynamic loader definition */ static struct corosync_service_engine *quorum_get_service_handler_ver0 (void); static struct corosync_service_engine_iface_ver0 quorum_service_handler_iface = { .corosync_get_service_engine_ver0 = quorum_get_service_handler_ver0 }; static struct lcr_iface corosync_quorum_ver0[2] = { { .name = "corosync_votequorum", .version = 0, .versions_replace = 0, .versions_replace_count = 0, .dependencies = 0, .dependency_count = 0, .constructor = NULL, .destructor = NULL, .interfaces = (void **)(void *)&votequorum_iface_ver0 }, { .name = "corosync_votequorum_iface", .version = 0, .versions_replace = 0, .versions_replace_count = 0, .dependencies = 0, .dependency_count = 0, .constructor = NULL, .destructor = NULL, .interfaces = NULL } }; static struct lcr_comp quorum_comp_ver0 = { .iface_count = 2, .ifaces = corosync_quorum_ver0 }; static struct corosync_service_engine *quorum_get_service_handler_ver0 (void) { return (&quorum_service_handler); } __attribute__ ((constructor)) static void quorum_comp_register (void) { lcr_interfaces_set (&corosync_quorum_ver0[0], &votequorum_iface_ver0); lcr_interfaces_set (&corosync_quorum_ver0[1], &quorum_service_handler_iface); lcr_component_register (&quorum_comp_ver0); } static void votequorum_init(struct corosync_api_v1 *api, quorum_set_quorate_fn_t report) { ENTER(); set_quorum = report; /* Load the library-servicing part of this module */ api->service_link_and_init(api, "corosync_votequorum_iface", 0); LEAVE(); } /* Message types */ #define VOTEQUORUM_MSG_NODEINFO 5 #define VOTEQUORUM_MSG_KILLNODE 6 #define VOTEQUORUM_MSG_RECONFIGURE 8 struct req_exec_quorum_nodeinfo { unsigned char cmd; unsigned char first_trans; unsigned int votes; unsigned int expected_votes; unsigned int major_version; /* Not backwards compatible */ unsigned int minor_version; /* Backwards compatible */ unsigned int patch_version; /* Backwards/forwards compatible */ unsigned int config_version; unsigned int flags; } __attribute__((packed)); /* Parameters for RECONFIG command */ #define RECONFIG_PARAM_EXPECTED_VOTES 1 #define RECONFIG_PARAM_NODE_VOTES 2 #define RECONFIG_PARAM_LEAVING 3 struct req_exec_quorum_reconfigure { unsigned char cmd; unsigned char param; unsigned short pad; int nodeid; unsigned int value; }; struct req_exec_quorum_killnode { unsigned char cmd; unsigned char pad1; uint16_t reason; int nodeid; }; /* These just make the access a little neater */ -static inline int objdb_get_string(struct corosync_api_v1 *corosync, unsigned int object_service_handle, +static inline int objdb_get_string(const struct corosync_api_v1 *corosync, + unsigned int object_service_handle, char *key, char **value) { int res; *value = NULL; if ( !(res = corosync_api->object_key_get(object_service_handle, key, strlen(key), (void *)value, NULL))) { if (*value) return 0; } return -1; } -static inline void objdb_get_int(struct corosync_api_v1 *corosync, +static inline void objdb_get_int(const struct corosync_api_v1 *corosync, unsigned int object_service_handle, const char *key, unsigned int *intvalue, unsigned int default_value) { char *value = NULL; *intvalue = default_value; if (!corosync_api->object_key_get(object_service_handle, key, strlen(key), (void *)&value, NULL)) { if (value) { *intvalue = atoi(value); } } } static int votequorum_send_message(void *message, int len) { struct iovec iov[2]; struct q_protheader header; header.tgtport = 0; header.srcport = 0; header.flags = 0; header.srcid = us->node_id; header.tgtid = 0; iov[0].iov_base = &header; iov[0].iov_len = sizeof(header); iov[1].iov_base = message; iov[1].iov_len = len; return corosync_api->tpg_joined_mcast(group_handle, iov, 2, TOTEM_AGREED); } static void read_quorum_config(unsigned int quorum_handle) { unsigned int value = 0; int cluster_members = 0; struct list_head *tmp; struct cluster_node *node; log_printf(LOG_INFO, "Reading configuration\n"); objdb_get_int(corosync_api, quorum_handle, "expected_votes", &us->expected_votes, DEFAULT_EXPECTED); objdb_get_int(corosync_api, quorum_handle, "votes", &us->votes, 1); objdb_get_int(corosync_api, quorum_handle, "quorumdev_poll", &quorumdev_poll, DEFAULT_QDEV_POLL); objdb_get_int(corosync_api, quorum_handle, "leaving_timeout", &leaving_timeout, DEFAULT_LEAVE_TMO); objdb_get_int(corosync_api, quorum_handle, "disallowed", &value, 0); if (value) quorum_flags |= VOTEQUORUM_FLAG_FEATURE_DISALLOWED; else quorum_flags &= ~VOTEQUORUM_FLAG_FEATURE_DISALLOWED; objdb_get_int(corosync_api, quorum_handle, "two_node", &value, 0); if (value) quorum_flags |= VOTEQUORUM_FLAG_FEATURE_TWONODE; else quorum_flags &= ~VOTEQUORUM_FLAG_FEATURE_TWONODE; /* * two_node mode is invalid if there are more than 2 nodes in the cluster! */ list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); cluster_members++; } if (quorum_flags & VOTEQUORUM_FLAG_FEATURE_TWONODE && cluster_members > 2) { log_printf(LOG_WARNING, "quorum.two_node was set but there are more than 2 nodes in the cluster. It will be ignored."); quorum_flags &= ~VOTEQUORUM_FLAG_FEATURE_TWONODE; } } static int votequorum_exec_init_fn (struct corosync_api_v1 *api) { hdb_handle_t object_handle; hdb_handle_t find_handle; ENTER(); corosync_api = api; list_init(&cluster_members_list); list_init(&trackers_list); /* Allocate a cluster_node for us */ us = allocate_node(corosync_api->totem_nodeid_get()); if (!us) return (1); us->flags |= NODE_FLAGS_US; us->state = NODESTATE_MEMBER; us->expected_votes = DEFAULT_EXPECTED; us->votes = 1; time(&us->join_time); /* Get configuration variables */ corosync_api->object_find_create(OBJECT_PARENT_HANDLE, "quorum", strlen("quorum"), &find_handle); if (corosync_api->object_find_next(find_handle, &object_handle) == 0) { read_quorum_config(object_handle); } recalculate_quorum(0, 0); /* Listen for changes */ add_votequorum_config_notification(object_handle); corosync_api->object_find_destroy(find_handle); api->tpg_init(&group_handle, quorum_deliver_fn, quorum_confchg_fn); api->tpg_join(group_handle, quorum_group, 1); LEAVE(); return (0); } static int quorum_lib_exit_fn (void *conn) { struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn); ENTER(); if (quorum_pd->tracking_enabled) { list_del (&quorum_pd->list); list_init (&quorum_pd->list); } LEAVE(); return (0); } static int send_quorum_notification(void *conn, uint64_t context) { struct res_lib_votequorum_notification *res_lib_votequorum_notification; struct list_head *tmp; struct cluster_node *node; int cluster_members = 0; int i = 0; int size; char *buf; ENTER(); list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); cluster_members++; } if (quorum_device) cluster_members++; size = sizeof(struct res_lib_votequorum_notification) + sizeof(struct votequorum_node) * cluster_members; buf = alloca(size); if (!buf) { LEAVE(); return -1; } res_lib_votequorum_notification = (struct res_lib_votequorum_notification *)buf; res_lib_votequorum_notification->quorate = cluster_is_quorate; res_lib_votequorum_notification->node_list_entries = cluster_members; res_lib_votequorum_notification->context = context; list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); res_lib_votequorum_notification->node_list[i].nodeid = node->node_id; res_lib_votequorum_notification->node_list[i++].state = node->state; } if (quorum_device) { res_lib_votequorum_notification->node_list[i].nodeid = 0; res_lib_votequorum_notification->node_list[i++].state = quorum_device->state | 0x80; } res_lib_votequorum_notification->header.id = MESSAGE_RES_VOTEQUORUM_NOTIFICATION; res_lib_votequorum_notification->header.size = size; res_lib_votequorum_notification->header.error = CS_OK; /* Send it to all interested parties */ if (conn) { int ret = corosync_api->ipc_dispatch_send(conn, buf, size); LEAVE(); return ret; } else { struct quorum_pd *qpd; list_iterate(tmp, &trackers_list) { qpd = list_entry(tmp, struct quorum_pd, list); res_lib_votequorum_notification->context = qpd->tracking_context; corosync_api->ipc_dispatch_send(qpd->conn, buf, size); } } LEAVE(); return 0; } static void send_expectedvotes_notification(void) { struct res_lib_votequorum_expectedvotes_notification res_lib_votequorum_expectedvotes_notification; struct quorum_pd *qpd; struct list_head *tmp; log_printf(LOG_DEBUG, "Sending expected votes callback\n"); res_lib_votequorum_expectedvotes_notification.header.id = MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION; res_lib_votequorum_expectedvotes_notification.header.size = sizeof(res_lib_votequorum_expectedvotes_notification); res_lib_votequorum_expectedvotes_notification.header.error = CS_OK; res_lib_votequorum_expectedvotes_notification.expected_votes = us->expected_votes; list_iterate(tmp, &trackers_list) { qpd = list_entry(tmp, struct quorum_pd, list); res_lib_votequorum_expectedvotes_notification.context = qpd->tracking_context; corosync_api->ipc_dispatch_send(qpd->conn, &res_lib_votequorum_expectedvotes_notification, sizeof(struct res_lib_votequorum_expectedvotes_notification)); } } static void set_quorate(int total_votes) { int quorate; ENTER(); if (quorum > total_votes) { quorate = 0; } else { quorate = 1; } if (cluster_is_quorate && !quorate) log_printf(LOG_INFO, "quorum lost, blocking activity\n"); if (!cluster_is_quorate && quorate) log_printf(LOG_INFO, "quorum regained, resuming activity\n"); /* If we are newly quorate, then kill any DISALLOWED nodes */ if (!cluster_is_quorate && quorate) { struct cluster_node *node = NULL; struct list_head *tmp; list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); if (node->state == NODESTATE_DISALLOWED) quorum_exec_send_killnode(node->node_id, VOTEQUORUM_REASON_KILL_REJOIN); } } cluster_is_quorate = quorate; set_quorum(quorum_members, quorum_members_entries, quorate, &quorum_ringid); ENTER(); } static int calculate_quorum(int allow_decrease, int max_expected, unsigned int *ret_total_votes) { struct list_head *nodelist; struct cluster_node *node; unsigned int total_votes = 0; unsigned int highest_expected = 0; unsigned int newquorum, q1, q2; unsigned int total_nodes = 0; ENTER(); list_iterate(nodelist, &cluster_members_list) { node = list_entry(nodelist, struct cluster_node, list); log_printf(LOG_DEBUG, "node %x state=%d, votes=%d, expected=%d\n", node->node_id, node->state, node->votes, node->expected_votes); if (node->state == NODESTATE_MEMBER) { if (max_expected) node->expected_votes = max_expected; else highest_expected = max(highest_expected, node->expected_votes); total_votes += node->votes; total_nodes++; } } if (quorum_device && quorum_device->state == NODESTATE_MEMBER) total_votes += quorum_device->votes; if (max_expected > 0) highest_expected = max_expected; /* This quorum calculation is taken from the OpenVMS Cluster Systems * manual, but, then, you guessed that didn't you */ q1 = (highest_expected + 2) / 2; q2 = (total_votes + 2) / 2; newquorum = max(q1, q2); /* Normally quorum never decreases but the system administrator can * force it down by setting expected votes to a maximum value */ if (!allow_decrease) newquorum = max(quorum, newquorum); /* The special two_node mode allows each of the two nodes to retain * quorum if the other fails. Only one of the two should live past * fencing (as both nodes try to fence each other in split-brain.) * Also: if there are more than two nodes, force us inquorate to avoid * any damage or confusion. */ if ((quorum_flags & VOTEQUORUM_FLAG_FEATURE_TWONODE) && total_nodes <= 2) newquorum = 1; if (ret_total_votes) *ret_total_votes = total_votes; LEAVE(); return newquorum; } /* Recalculate cluster quorum, set quorate and notify changes */ static void recalculate_quorum(int allow_decrease, int by_current_nodes) { unsigned int total_votes = 0; int cluster_members = 0; struct list_head *nodelist; struct cluster_node *node; ENTER(); list_iterate(nodelist, &cluster_members_list) { node = list_entry(nodelist, struct cluster_node, list); if (node->state == NODESTATE_MEMBER) { if (by_current_nodes) cluster_members++; total_votes += node->votes; } } /* Keep expected_votes at the highest number of votes in the cluster */ log_printf(LOG_DEBUG, "total_votes=%d, expected_votes=%d\n", total_votes, us->expected_votes); if (total_votes > us->expected_votes) { us->expected_votes = total_votes; send_expectedvotes_notification(); } quorum = calculate_quorum(allow_decrease, cluster_members, &total_votes); set_quorate(total_votes); send_quorum_notification(NULL, 0L); LEAVE(); } static int have_disallowed(void) { struct cluster_node *node; struct list_head *tmp; list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); if (node->state == NODESTATE_DISALLOWED) return 1; } return 0; } static void node_add_ordered(struct cluster_node *newnode) { struct cluster_node *node = NULL; struct list_head *tmp; struct list_head *newlist = &newnode->list; list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); if (newnode->node_id < node->node_id) break; } if (!node) list_add(&newnode->list, &cluster_members_list); else { newlist->prev = tmp->prev; newlist->next = tmp; tmp->prev->next = newlist; tmp->prev = newlist; } } static struct cluster_node *allocate_node(int nodeid) { struct cluster_node *cl; cl = malloc(sizeof(struct cluster_node)); if (cl) { memset(cl, 0, sizeof(struct cluster_node)); cl->node_id = nodeid; if (nodeid) node_add_ordered(cl); } return cl; } static struct cluster_node *find_node_by_nodeid(int nodeid) { struct cluster_node *node; struct list_head *tmp; list_iterate(tmp, &cluster_members_list) { node = list_entry(tmp, struct cluster_node, list); if (node->node_id == nodeid) return node; } return NULL; } static int quorum_exec_send_nodeinfo() { struct req_exec_quorum_nodeinfo req_exec_quorum_nodeinfo; int ret; ENTER(); req_exec_quorum_nodeinfo.cmd = VOTEQUORUM_MSG_NODEINFO; req_exec_quorum_nodeinfo.expected_votes = us->expected_votes; req_exec_quorum_nodeinfo.votes = us->votes; req_exec_quorum_nodeinfo.major_version = VOTEQUORUM_MAJOR_VERSION; req_exec_quorum_nodeinfo.minor_version = VOTEQUORUM_MINOR_VERSION; req_exec_quorum_nodeinfo.patch_version = VOTEQUORUM_PATCH_VERSION; req_exec_quorum_nodeinfo.flags = us->flags; req_exec_quorum_nodeinfo.first_trans = first_trans; if (have_disallowed()) req_exec_quorum_nodeinfo.flags |= NODE_FLAGS_SEESDISALLOWED; ret = votequorum_send_message(&req_exec_quorum_nodeinfo, sizeof(req_exec_quorum_nodeinfo)); LEAVE(); return ret; } static int quorum_exec_send_reconfigure(int param, int nodeid, int value) { struct req_exec_quorum_reconfigure req_exec_quorum_reconfigure; int ret; ENTER(); req_exec_quorum_reconfigure.cmd = VOTEQUORUM_MSG_RECONFIGURE; req_exec_quorum_reconfigure.param = param; req_exec_quorum_reconfigure.nodeid = nodeid; req_exec_quorum_reconfigure.value = value; ret = votequorum_send_message(&req_exec_quorum_reconfigure, sizeof(req_exec_quorum_reconfigure)); LEAVE(); return ret; } static int quorum_exec_send_killnode(int nodeid, unsigned int reason) { struct req_exec_quorum_killnode req_exec_quorum_killnode; int ret; ENTER(); req_exec_quorum_killnode.cmd = VOTEQUORUM_MSG_KILLNODE; req_exec_quorum_killnode.nodeid = nodeid; req_exec_quorum_killnode.reason = reason; ret = votequorum_send_message(&req_exec_quorum_killnode, sizeof(req_exec_quorum_killnode)); LEAVE(); return ret; } static void quorum_confchg_fn ( enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id) { int i; int leaving = 0; struct cluster_node *node; ENTER(); if (member_list_entries > 1) first_trans = 0; if (left_list_entries) { for (i = 0; i< left_list_entries; i++) { node = find_node_by_nodeid(left_list[i]); if (node) { if (node->state == NODESTATE_LEAVING) leaving = 1; node->state = NODESTATE_DEAD; node->flags |= NODE_FLAGS_BEENDOWN; } } recalculate_quorum(leaving, leaving); } if (member_list_entries) { memcpy(quorum_members, member_list, sizeof(unsigned int) * member_list_entries); quorum_members_entries = member_list_entries; if (quorum_device) { quorum_members[quorum_members_entries++] = 0; } quorum_exec_send_nodeinfo(); } memcpy(&quorum_ringid, ring_id, sizeof(*ring_id)); LEAVE(); } static void exec_quorum_nodeinfo_endian_convert (void *msg) { struct req_exec_quorum_nodeinfo *nodeinfo = (struct req_exec_quorum_nodeinfo *)msg; nodeinfo->votes = swab32(nodeinfo->votes); nodeinfo->expected_votes = swab32(nodeinfo->expected_votes); nodeinfo->major_version = swab32(nodeinfo->major_version); nodeinfo->minor_version = swab32(nodeinfo->minor_version); nodeinfo->patch_version = swab32(nodeinfo->patch_version); nodeinfo->config_version = swab32(nodeinfo->config_version); nodeinfo->flags = swab32(nodeinfo->flags); } static void exec_quorum_reconfigure_endian_convert (void *msg) { struct req_exec_quorum_reconfigure *reconfigure = (struct req_exec_quorum_reconfigure *)msg; reconfigure->nodeid = swab32(reconfigure->nodeid); reconfigure->value = swab32(reconfigure->value); } static void exec_quorum_killnode_endian_convert (void *msg) { struct req_exec_quorum_killnode *killnode = (struct req_exec_quorum_killnode *)msg; killnode->reason = swab16(killnode->reason); killnode->nodeid = swab32(killnode->nodeid); } static void quorum_deliver_fn(unsigned int nodeid, struct iovec *iovec, unsigned int iov_len, int endian_conversion_required) { struct q_protheader *header = iovec->iov_base; char *buf; ENTER(); if (endian_conversion_required) { header->srcid = swab32(header->srcid); header->tgtid = swab32(header->tgtid); header->flags = swab32(header->flags); } /* Only pass on messages for us or everyone */ if (header->tgtport == 0 && (header->tgtid == us->node_id || header->tgtid == 0)) { buf = (char *)(iovec->iov_base) + sizeof(struct q_protheader); switch (*buf) { case VOTEQUORUM_MSG_NODEINFO: if (endian_conversion_required) exec_quorum_nodeinfo_endian_convert(buf); message_handler_req_exec_quorum_nodeinfo (buf, header->srcid); break; case VOTEQUORUM_MSG_RECONFIGURE: if (endian_conversion_required) exec_quorum_reconfigure_endian_convert(buf); message_handler_req_exec_quorum_reconfigure (buf, header->srcid); break; case VOTEQUORUM_MSG_KILLNODE: if (endian_conversion_required) exec_quorum_killnode_endian_convert(buf); message_handler_req_exec_quorum_killnode (buf, header->srcid); break; /* Just ignore other messages */ } } LEAVE(); } static void message_handler_req_exec_quorum_nodeinfo ( void *message, unsigned int nodeid) { struct req_exec_quorum_nodeinfo *req_exec_quorum_nodeinfo = (struct req_exec_quorum_nodeinfo *)message; struct cluster_node *node; int old_votes; int old_expected; nodestate_t old_state; int new_node = 0; ENTER(); log_printf(LOG_LEVEL_DEBUG, "got nodeinfo message from cluster node %d\n", nodeid); node = find_node_by_nodeid(nodeid); if (!node) { node = allocate_node(nodeid); new_node = 1; } if (!node) { corosync_api->error_memory_failure(); return; } /* * If the node sending the message sees disallowed nodes and we don't, then * we have to leave */ if (req_exec_quorum_nodeinfo->flags & NODE_FLAGS_SEESDISALLOWED && !have_disallowed()) { /* Must use syslog directly here or the message will never arrive */ syslog(LOG_CRIT, "[VOTEQ]: Joined a cluster with disallowed nodes. must die"); corosync_api->fatal_error(2, __FILE__, __LINE__); exit(2); } old_votes = node->votes; old_expected = node->expected_votes; old_state = node->state; /* Update node state */ if (req_exec_quorum_nodeinfo->minor_version >= 2) node->votes = req_exec_quorum_nodeinfo->votes; node->expected_votes = req_exec_quorum_nodeinfo->expected_votes; node->state = NODESTATE_MEMBER; /* Check flags for disallowed (if enabled) */ if (quorum_flags & VOTEQUORUM_FLAG_FEATURE_DISALLOWED) { if ((req_exec_quorum_nodeinfo->flags & NODE_FLAGS_HASSTATE && node->flags & NODE_FLAGS_BEENDOWN) || (req_exec_quorum_nodeinfo->flags & NODE_FLAGS_HASSTATE && req_exec_quorum_nodeinfo->first_trans && !(node->flags & NODE_FLAGS_US) && (us->flags & NODE_FLAGS_HASSTATE))) { if (node->state != NODESTATE_DISALLOWED) { if (cluster_is_quorate) { log_printf(LOG_CRIT, "Killing node %d because it has rejoined the cluster with existing state", node->node_id); node->state = NODESTATE_DISALLOWED; quorum_exec_send_killnode(nodeid, VOTEQUORUM_REASON_KILL_REJOIN); } else { log_printf(LOG_CRIT, "Node %d not joined to quorum because it has existing state", node->node_id); node->state = NODESTATE_DISALLOWED; } } } } node->flags &= ~NODE_FLAGS_BEENDOWN; if (new_node || old_votes != node->votes || old_expected != node->expected_votes || old_state != node->state) recalculate_quorum(0, 0); LEAVE(); } static void message_handler_req_exec_quorum_killnode ( void *message, unsigned int nodeid) { struct req_exec_quorum_killnode *req_exec_quorum_killnode = (struct req_exec_quorum_killnode *)message; if (req_exec_quorum_killnode->nodeid == corosync_api->totem_nodeid_get()) { log_printf(LOG_CRIT, "Killed by node %d: %s\n", nodeid, kill_reason(req_exec_quorum_killnode->reason)); corosync_api->fatal_error(1, __FILE__, __LINE__); exit(1); } } static void message_handler_req_exec_quorum_reconfigure ( void *message, unsigned int nodeid) { struct req_exec_quorum_reconfigure *req_exec_quorum_reconfigure = (struct req_exec_quorum_reconfigure *)message; struct cluster_node *node; struct list_head *nodelist; log_printf(LOG_LEVEL_DEBUG, "got reconfigure message from cluster node %d\n", nodeid); node = find_node_by_nodeid(req_exec_quorum_reconfigure->nodeid); if (!node) return; switch(req_exec_quorum_reconfigure->param) { case RECONFIG_PARAM_EXPECTED_VOTES: list_iterate(nodelist, &cluster_members_list) { node = list_entry(nodelist, struct cluster_node, list); if (node->state == NODESTATE_MEMBER && node->expected_votes > req_exec_quorum_reconfigure->value) { node->expected_votes = req_exec_quorum_reconfigure->value; } } send_expectedvotes_notification(); recalculate_quorum(1, 0); /* Allow decrease */ break; case RECONFIG_PARAM_NODE_VOTES: node->votes = req_exec_quorum_reconfigure->value; recalculate_quorum(1, 0); /* Allow decrease */ break; case RECONFIG_PARAM_LEAVING: if (req_exec_quorum_reconfigure->value == 1 && node->state == NODESTATE_MEMBER) node->state = NODESTATE_LEAVING; if (req_exec_quorum_reconfigure->value == 0 && node->state == NODESTATE_LEAVING) node->state = NODESTATE_MEMBER; break; } } static int quorum_lib_init_fn (void *conn) { struct quorum_pd *pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn); ENTER(); list_init (&pd->list); pd->conn = conn; LEAVE(); return (0); } /* * Someone called votequorum_leave AGES ago! * Assume they forgot to shut down the node. */ static void leaving_timer_fn(void *arg) { ENTER(); if (us->state == NODESTATE_LEAVING) us->state = NODESTATE_MEMBER; /* Tell everyone else we made a mistake */ quorum_exec_send_reconfigure(RECONFIG_PARAM_LEAVING, us->node_id, 0); LEAVE(); } /* Message from the library */ static void message_handler_req_lib_votequorum_getinfo (void *conn, void *message) { struct req_lib_votequorum_getinfo *req_lib_votequorum_getinfo = (struct req_lib_votequorum_getinfo *)message; struct res_lib_votequorum_getinfo res_lib_votequorum_getinfo; struct cluster_node *node; unsigned int highest_expected = 0; unsigned int total_votes = 0; cs_error_t error = CS_OK; log_printf(LOG_LEVEL_DEBUG, "got getinfo request on %p for node %d\n", conn, req_lib_votequorum_getinfo->nodeid); if (req_lib_votequorum_getinfo->nodeid) { node = find_node_by_nodeid(req_lib_votequorum_getinfo->nodeid); } else { node = us; } if (node) { struct cluster_node *iternode; struct list_head *nodelist; list_iterate(nodelist, &cluster_members_list) { iternode = list_entry(nodelist, struct cluster_node, list); if (iternode->state == NODESTATE_MEMBER) { highest_expected = max(highest_expected, iternode->expected_votes); total_votes += iternode->votes; } } if (quorum_device && quorum_device->state == NODESTATE_MEMBER) { total_votes += quorum_device->votes; } res_lib_votequorum_getinfo.votes = us->votes; res_lib_votequorum_getinfo.expected_votes = us->expected_votes; res_lib_votequorum_getinfo.highest_expected = highest_expected; res_lib_votequorum_getinfo.quorum = quorum; res_lib_votequorum_getinfo.total_votes = total_votes; res_lib_votequorum_getinfo.flags = 0; res_lib_votequorum_getinfo.nodeid = node->node_id; if (us->flags & NODE_FLAGS_HASSTATE) res_lib_votequorum_getinfo.flags |= VOTEQUORUM_INFO_FLAG_HASSTATE; if (quorum_flags & VOTEQUORUM_FLAG_FEATURE_TWONODE) res_lib_votequorum_getinfo.flags |= VOTEQUORUM_INFO_FLAG_TWONODE; if (cluster_is_quorate) res_lib_votequorum_getinfo.flags |= VOTEQUORUM_INFO_FLAG_QUORATE; if (us->flags & NODE_FLAGS_SEESDISALLOWED) res_lib_votequorum_getinfo.flags |= VOTEQUORUM_INFO_FLAG_DISALLOWED; } else { error = CS_ERR_NOT_EXIST; } res_lib_votequorum_getinfo.header.size = sizeof(res_lib_votequorum_getinfo); res_lib_votequorum_getinfo.header.id = MESSAGE_RES_VOTEQUORUM_GETINFO; res_lib_votequorum_getinfo.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_getinfo, sizeof(res_lib_votequorum_getinfo)); log_printf(LOG_LEVEL_DEBUG, "getinfo response error: %d\n", error); } /* Message from the library */ static void message_handler_req_lib_votequorum_setexpected (void *conn, void *message) { struct req_lib_votequorum_setexpected *req_lib_votequorum_setexpected = (struct req_lib_votequorum_setexpected *)message; struct res_lib_votequorum_status res_lib_votequorum_status; cs_error_t error = CS_OK; unsigned int newquorum; unsigned int total_votes; ENTER(); /* * If there are disallowed nodes, then we can't allow the user * to bypass them by fiddling with expected votes. */ if (quorum_flags & VOTEQUORUM_FLAG_FEATURE_DISALLOWED && have_disallowed()) { error = CS_ERR_EXIST; goto error_exit; } /* Validate new expected votes */ newquorum = calculate_quorum(1, req_lib_votequorum_setexpected->expected_votes, &total_votes); if (newquorum < total_votes / 2 || newquorum > total_votes) { error = CS_ERR_INVALID_PARAM; goto error_exit; } quorum_exec_send_reconfigure(RECONFIG_PARAM_EXPECTED_VOTES, us->node_id, req_lib_votequorum_setexpected->expected_votes); /* send status */ error_exit: res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } /* Message from the library */ static void message_handler_req_lib_votequorum_setvotes (void *conn, void *message) { struct req_lib_votequorum_setvotes *req_lib_votequorum_setvotes = (struct req_lib_votequorum_setvotes *)message; struct res_lib_votequorum_status res_lib_votequorum_status; struct cluster_node *node; unsigned int newquorum; unsigned int total_votes; unsigned int saved_votes; cs_error_t error = CS_OK; ENTER(); node = find_node_by_nodeid(req_lib_votequorum_setvotes->nodeid); if (!node) { error = CS_ERR_NAME_NOT_FOUND; goto error_exit; } /* Check votes is valid */ saved_votes = node->votes; node->votes = req_lib_votequorum_setvotes->votes; newquorum = calculate_quorum(1, 0, &total_votes); if (newquorum < total_votes / 2 || newquorum > total_votes) { node->votes = saved_votes; error = CS_ERR_INVALID_PARAM; goto error_exit; } if (!req_lib_votequorum_setvotes->nodeid) req_lib_votequorum_setvotes->nodeid = corosync_api->totem_nodeid_get(); quorum_exec_send_reconfigure(RECONFIG_PARAM_NODE_VOTES, req_lib_votequorum_setvotes->nodeid, req_lib_votequorum_setvotes->votes); error_exit: /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void message_handler_req_lib_votequorum_leaving (void *conn, void *message) { struct res_lib_votequorum_status res_lib_votequorum_status; cs_error_t error = CS_OK; ENTER(); quorum_exec_send_reconfigure(RECONFIG_PARAM_LEAVING, us->node_id, 1); /* * If we don't shut down in a sensible amount of time then cancel the * leave status. */ if (leaving_timeout) corosync_api->timer_add_duration((unsigned long long)leaving_timeout*1000000, NULL, leaving_timer_fn, &leaving_timer); /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void quorum_device_timer_fn(void *arg) { struct timeval now; ENTER(); if (!quorum_device || quorum_device->state == NODESTATE_DEAD) return; gettimeofday(&now, NULL); if (quorum_device->last_hello.tv_sec + quorumdev_poll/1000 < now.tv_sec) { quorum_device->state = NODESTATE_DEAD; log_printf(LOG_INFO, "lost contact with quorum device\n"); recalculate_quorum(0, 0); } else { corosync_api->timer_add_duration((unsigned long long)quorumdev_poll*1000000, quorum_device, quorum_device_timer_fn, &quorum_device_timer); } LEAVE(); } static void message_handler_req_lib_votequorum_qdisk_register (void *conn, void *message) { struct req_lib_votequorum_qdisk_register *req_lib_votequorum_qdisk_register = (struct req_lib_votequorum_qdisk_register *)message; struct res_lib_votequorum_status res_lib_votequorum_status; cs_error_t error = CS_OK; ENTER(); if (quorum_device) { error = CS_ERR_EXIST; } else { quorum_device = allocate_node(0); quorum_device->state = NODESTATE_DEAD; quorum_device->votes = req_lib_votequorum_qdisk_register->votes; strcpy(quorum_device_name, req_lib_votequorum_qdisk_register->name); list_add(&quorum_device->list, &cluster_members_list); } /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void message_handler_req_lib_votequorum_qdisk_unregister (void *conn, void *message) { struct res_lib_votequorum_status res_lib_votequorum_status; cs_error_t error = CS_OK; ENTER(); if (quorum_device) { struct cluster_node *node = quorum_device; quorum_device = NULL; list_del(&node->list); free(node); recalculate_quorum(0, 0); } else { error = CS_ERR_NOT_EXIST; } /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void message_handler_req_lib_votequorum_qdisk_poll (void *conn, void *message) { struct req_lib_votequorum_qdisk_poll *req_lib_votequorum_qdisk_poll = (struct req_lib_votequorum_qdisk_poll *)message; struct res_lib_votequorum_status res_lib_votequorum_status; cs_error_t error = CS_OK; ENTER(); if (quorum_device) { if (req_lib_votequorum_qdisk_poll->state) { gettimeofday(&quorum_device->last_hello, NULL); if (quorum_device->state == NODESTATE_DEAD) { quorum_device->state = NODESTATE_MEMBER; recalculate_quorum(0, 0); corosync_api->timer_add_duration((unsigned long long)quorumdev_poll*1000000, quorum_device, quorum_device_timer_fn, &quorum_device_timer); } } else { if (quorum_device->state == NODESTATE_MEMBER) { quorum_device->state = NODESTATE_DEAD; recalculate_quorum(0, 0); corosync_api->timer_delete(quorum_device_timer); } } } else { error = CS_ERR_NOT_EXIST; } /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void message_handler_req_lib_votequorum_qdisk_getinfo (void *conn, void *message) { struct res_lib_votequorum_qdisk_getinfo res_lib_votequorum_qdisk_getinfo; cs_error_t error = CS_OK; ENTER(); if (quorum_device) { log_printf(LOG_LEVEL_DEBUG, "got qdisk_getinfo state %d\n", quorum_device->state); res_lib_votequorum_qdisk_getinfo.votes = quorum_device->votes; if (quorum_device->state == NODESTATE_MEMBER) res_lib_votequorum_qdisk_getinfo.state = 1; else res_lib_votequorum_qdisk_getinfo.state = 0; strcpy(res_lib_votequorum_qdisk_getinfo.name, quorum_device_name); } else { error = CS_ERR_NOT_EXIST; } /* send status */ res_lib_votequorum_qdisk_getinfo.header.size = sizeof(res_lib_votequorum_qdisk_getinfo); res_lib_votequorum_qdisk_getinfo.header.id = MESSAGE_RES_VOTEQUORUM_GETINFO; res_lib_votequorum_qdisk_getinfo.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_qdisk_getinfo, sizeof(res_lib_votequorum_qdisk_getinfo)); LEAVE(); } static void message_handler_req_lib_votequorum_setstate (void *conn, void *message) { struct res_lib_votequorum_status res_lib_votequorum_status; cs_error_t error = CS_OK; ENTER(); us->flags |= NODE_FLAGS_HASSTATE; /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void message_handler_req_lib_votequorum_trackstart (void *conn, void *msg) { struct req_lib_votequorum_trackstart *req_lib_votequorum_trackstart = (struct req_lib_votequorum_trackstart *)msg; struct res_lib_votequorum_status res_lib_votequorum_status; struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn); ENTER(); /* * If an immediate listing of the current cluster membership * is requested, generate membership list */ if (req_lib_votequorum_trackstart->track_flags & CS_TRACK_CURRENT || req_lib_votequorum_trackstart->track_flags & CS_TRACK_CHANGES) { log_printf(LOG_LEVEL_DEBUG, "sending initial status to %p\n", conn); send_quorum_notification(conn, req_lib_votequorum_trackstart->context); } /* * Record requests for tracking */ if (req_lib_votequorum_trackstart->track_flags & CS_TRACK_CHANGES || req_lib_votequorum_trackstart->track_flags & CS_TRACK_CHANGES_ONLY) { quorum_pd->track_flags = req_lib_votequorum_trackstart->track_flags; quorum_pd->tracking_enabled = 1; quorum_pd->tracking_context = req_lib_votequorum_trackstart->context; list_add (&quorum_pd->list, &trackers_list); } /* Send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = CS_OK; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static void message_handler_req_lib_votequorum_trackstop (void *conn, void *msg) { struct res_lib_votequorum_status res_lib_votequorum_status; struct quorum_pd *quorum_pd = (struct quorum_pd *)corosync_api->ipc_private_data_get (conn); int error = CS_OK; ENTER(); if (quorum_pd->tracking_enabled) { error = CS_OK; quorum_pd->tracking_enabled = 0; list_del (&quorum_pd->list); list_init (&quorum_pd->list); } else { error = CS_ERR_NOT_EXIST; } /* send status */ res_lib_votequorum_status.header.size = sizeof(res_lib_votequorum_status); res_lib_votequorum_status.header.id = MESSAGE_RES_VOTEQUORUM_STATUS; res_lib_votequorum_status.header.error = error; corosync_api->ipc_response_send(conn, &res_lib_votequorum_status, sizeof(res_lib_votequorum_status)); LEAVE(); } static const char *kill_reason(int reason) { static char msg[1024]; switch (reason) { case VOTEQUORUM_REASON_KILL_REJECTED: return "our membership application was rejected"; case VOTEQUORUM_REASON_KILL_APPLICATION: return "we were killed by an application request"; case VOTEQUORUM_REASON_KILL_REJOIN: return "we rejoined the cluster without a full restart"; default: sprintf(msg, "we got kill message number %d", reason); return msg; } } static void reread_config(hdb_handle_t object_handle) { unsigned int old_votes; unsigned int old_expected; old_votes = us->votes; old_expected = us->expected_votes; /* * Reload the configuration */ read_quorum_config(object_handle); /* * Check for fundamental changes that we need to propogate */ if (old_votes != us->votes) { quorum_exec_send_reconfigure(RECONFIG_PARAM_NODE_VOTES, us->node_id, us->votes); } if (old_expected != us->expected_votes) { quorum_exec_send_reconfigure(RECONFIG_PARAM_EXPECTED_VOTES, us->node_id, us->expected_votes); } } static void quorum_key_change_notify(object_change_type_t change_type, hdb_handle_t parent_object_handle, hdb_handle_t object_handle, const void *object_name_pt, - int object_name_len, - const void *key_name_pt, int key_len, - const void *key_value_pt, int key_value_len, - void *priv_data_pt) + size_t object_name_len, + const void *key_name_pt, size_t key_len, + const void *key_value_pt, size_t key_value_len, + const void *priv_data_pt) { if (memcmp(object_name_pt, "quorum", object_name_len) == 0) reread_config(object_handle); } /* Called when the objdb is reloaded */ static void votequorum_objdb_reload_notify( objdb_reload_notify_type_t type, int flush, - void *priv_data_pt) + const void *priv_data_pt) { /* * A new quorum {} key might exist, cancel the * existing notification at the start of reload, * and start a new one on the new object when * it's all settled. */ if (type == OBJDB_RELOAD_NOTIFY_START) { corosync_api->object_track_stop( quorum_key_change_notify, NULL, NULL, NULL, NULL); } if (type == OBJDB_RELOAD_NOTIFY_END || type == OBJDB_RELOAD_NOTIFY_FAILED) { hdb_handle_t find_handle; hdb_handle_t object_handle; corosync_api->object_find_create(OBJECT_PARENT_HANDLE, "quorum", strlen("quorum"), &find_handle); if (corosync_api->object_find_next(find_handle, &object_handle) == 0) { add_votequorum_config_notification(object_handle); reread_config(object_handle); } else { log_printf(LOG_LEVEL_ERROR, "votequorum objdb tracking stopped, cannot find quorum{} handle in objdb\n"); } } } static void add_votequorum_config_notification( hdb_handle_t quorum_object_handle) { corosync_api->object_track_start(quorum_object_handle, 1, quorum_key_change_notify, NULL, NULL, NULL, NULL); /* * Reload notify must be on the parent object */ corosync_api->object_track_start(OBJECT_PARENT_HANDLE, 1, NULL, NULL, NULL, votequorum_objdb_reload_notify, NULL); }