diff --git a/qdevices/Makefile.am b/qdevices/Makefile.am index ab1163af..545c9a45 100644 --- a/qdevices/Makefile.am +++ b/qdevices/Makefile.am @@ -1,144 +1,145 @@ # Copyright (c) 2012-2016 Red Hat, Inc. # # Authors: Fabio M. Di Nitto (fdinitto@redhat.com) # Jan Friesse (jfriesse@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. MAINTAINERCLEANFILES = Makefile.in if BUILD_QDEVICES SUBDIRS = sbin_PROGRAMS = corosync-qnetd corosync-qdevice corosync-qnetd-tool \ corosync-qdevice-tool sbin_SCRIPTS = corosync-qnetd-certutil corosync-qdevice-net-certutil EXTRA_DIST = corosync-qdevice-net-certutil.sh corosync-qnetd-certutil.sh corosync_qnetd_SOURCES = corosync-qnetd.c \ dynar.c dynar.h msg.c msg.h msgio.c msgio.h \ nss-sock.c nss-sock.h qnetd-client.c qnetd-client.h \ qnetd-client-list.c qnetd-client-list.h qnetd-log.c qnetd-log.h \ pr-poll-array.c pr-poll-array.h timer-list.c timer-list.h tlv.c tlv.h \ send-buffer-list.c send-buffer-list.h node-list.c node-list.h \ qnetd-algo-test.c qnetd-algo-test.h qnetd-algorithm.c qnetd-algorithm.h \ qnetd-algo-utils.c qnetd-algo-utils.h \ qnetd-algo-ffsplit.c qnetd-algo-ffsplit.h \ qnetd-cluster-list.c qnetd-cluster-list.h \ qnetd-client-send.c qnetd-client-send.h \ qnetd-algo-2nodelms.c qnetd-algo-2nodelms.h qnetd-algo-lms.c qnetd-algo-lms.h \ utils.c utils.h qnetd-instance.c qnetd-instance.h \ qnetd-client-net.c qnetd-client-net.h \ qnetd-client-msg-received.c qnetd-client-msg-received.h \ qnetd-log-debug.c qnetd-log-debug.h \ qnetd-client-algo-timer.c qnetd-client-algo-timer.h \ qnetd-dpd-timer.c qnetd-dpd-timer.h \ qnetd-ipc.c qnetd-ipc.h unix-socket-ipc.c unix-socket-ipc.h \ dynar-simple-lex.c dynar-simple-lex.h dynar-str.c dynar-str.h \ unix-socket-client.c unix-socket-client.h \ unix-socket-client-list.c unix-socket-client-list.h \ unix-socket.c unix-socket.h qnetd-ipc-cmd.c qnetd-ipc-cmd.h \ qnetd-poll-array-user-data.h qnet-config.h dynar-getopt-lex.c \ dynar-getopt-lex.h qnetd-advanced-settings.c corosync_qdevice_SOURCES = corosync-qdevice.c \ qdevice-cmap.c qdevice-cmap.h \ qdevice-instance.c qdevice-instance.h node-list.c node-list.h \ utils.c utils.h qdevice-log.c qdevice-log.h \ qdevice-log-debug.c qdevice-log-debug.h \ qdevice-votequorum.c qdevice-votequorum.h \ qdevice-model.c qdevice-model.h qdevice-model-net.c qdevice-model-net.h \ qdevice-net-instance.c qdevice-net-instance.h dynar.c dynar.h \ send-buffer-list.c send-buffer-list.h timer-list.c timer-list.h \ msg.c msg.h msgio.c msgio.h nss-sock.c nss-sock.h tlv.c tlv.h \ unix-socket.c unix-socket.h unix-socket-client.c unix-socket-client.h \ unix-socket-client-list.c unix-socket-client-list.h \ unix-socket-ipc.c unix-socket-ipc.h qdevice-ipc.c qdevice-ipc.h \ pr-poll-array.c pr-poll-array.h dynar-simple-lex.c dynar-simple-lex.h \ dynar-str.c dynar-str.h qdevice-ipc-cmd.c qdevice-ipc-cmd.h \ qdevice-net-ipc-cmd.c qdevice-net-ipc-cmd.h \ qdevice-net-poll.c qdevice-net-poll.h \ qdevice-net-send.c qdevice-net-send.h \ qdevice-net-votequorum.c qdevice-net-votequorum.h \ qdevice-net-socket.c qdevice-net-socket.h \ qdevice-net-nss.c qdevice-net-nss.h \ qdevice-net-msg-received.c qdevice-net-msg-received.h \ qdevice-net-cast-vote-timer.c qdevice-net-cast-vote-timer.h \ qdevice-net-echo-request-timer.c qdevice-net-echo-request-timer.h \ qdevice-net-algorithm.c qdevice-net-algorithm.h \ qdevice-net-algo-test.c qdevice-net-algo-test.h \ qdevice-net-algo-ffsplit.c qdevice-net-algo-ffsplit.h \ qdevice-net-algo-2nodelms.c qdevice-net-algo-2nodelms.h \ qdevice-net-algo-lms.c qdevice-net-algo-lms.h \ qdevice-net-poll-array-user-data.h \ qdevice-config.h qnet-config.h qdevice-net-disconnect-reason.h \ - qdevice-model-type.h + qdevice-model-type.h qdevice-advanced-settings.c \ + qdevice-advanced-settings.h dynar-getopt-lex.c dynar-getopt-lex.h corosync_qnetd_tool_SOURCES = corosync-qnetd-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \ dynar-str.c dynar-str.h corosync_qdevice_tool_SOURCES = corosync-qdevice-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \ dynar-str.c dynar-str.h corosync_qnetd_CFLAGS = $(nss_CFLAGS) corosync_qnetd_LDADD = $(nss_LIBS) corosync_qdevice_CFLAGS = $(nss_CFLAGS) corosync_qdevice_LDADD = $(nss_LIBS) $(LIBQB_LIBS) $(top_builddir)/lib/libcmap.la \ $(top_builddir)/lib/libvotequorum.la corosync-qnetd-certutil: corosync-qnetd-certutil.sh sed -e 's#@''DATADIR@#${datadir}#g' \ -e 's#@''BASHPATH@#${BASHPATH}#g' \ -e 's#@''COROSYSCONFDIR@#${COROSYSCONFDIR}#g' \ $< > $@ corosync-qdevice-net-certutil: corosync-qdevice-net-certutil.sh sed -e 's#@''DATADIR@#${datadir}#g' \ -e 's#@''BASHPATH@#${BASHPATH}#g' \ -e 's#@''COROSYSCONFDIR@#${COROSYSCONFDIR}#g' \ $< > $@ TESTS = qnetd-cluster-list.test dynar.test dynar-simple-lex.test \ dynar-getopt-lex.test check_PROGRAMS = qnetd-cluster-list.test dynar.test dynar-simple-lex.test \ dynar-getopt-lex.test qnetd_cluster_list_test_SOURCES = qnetd-cluster-list.c test-qnetd-cluster-list.c \ qnetd-client-list.c qnetd-client.c dynar.c node-list.c \ send-buffer-list.c qnetd_cluster_list_test_CFLAGS = $(nss_CFLAGS) qnetd_cluster_list_test_LDADD = $(nss_LIBS) dynar_test_SOURCES = test-dynar.c dynar.c dynar-str.c dynar_simple_lex_test_SOURCES = test-dynar-simple-lex.c dynar.c dynar-str.c dynar-simple-lex.c dynar_getopt_lex_test_SOURCES = test-dynar-getopt-lex.c dynar.c dynar-str.c dynar-getopt-lex.c endif diff --git a/qdevices/corosync-qdevice-tool.c b/qdevices/corosync-qdevice-tool.c index c1971f6b..b3f5c5d8 100644 --- a/qdevices/corosync-qdevice-tool.c +++ b/qdevices/corosync-qdevice-tool.c @@ -1,280 +1,280 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-config.h" #include "dynar.h" #include "dynar-str.h" #include "utils.h" #include "unix-socket.h" #define IPC_READ_BUF_SIZE 512 enum qdevice_tool_operation { QDEVICE_TOOL_OPERATION_NONE, QDEVICE_TOOL_OPERATION_SHUTDOWN, QDEVICE_TOOL_OPERATION_STATUS, }; enum qdevice_tool_exit_code { QDEVICE_TOOL_EXIT_CODE_NO_ERROR = 0, QDEVICE_TOOL_EXIT_CODE_USAGE = 1, QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR = 2, QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT = 3, QDEVICE_TOOL_EXIT_CODE_QDEVICE_RETURNED_ERROR = 4, }; static void usage(void) { printf("usage: %s [-Hhsv] [-p qdevice_ipc_socket_path]\n", QDEVICE_TOOL_PROGRAM_NAME); } static void cli_parse(int argc, char * const argv[], enum qdevice_tool_operation *operation, int *verbose, char **socket_path) { int ch; *operation = QDEVICE_TOOL_OPERATION_NONE; *verbose = 0; - *socket_path = strdup(QDEVICE_LOCAL_SOCKET_FILE); + *socket_path = strdup(QDEVICE_DEFAULT_LOCAL_SOCKET_FILE); if (*socket_path == NULL) { errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't alloc memory for socket path string"); } while ((ch = getopt(argc, argv, "Hhsvp:")) != -1) { switch (ch) { case 'H': *operation = QDEVICE_TOOL_OPERATION_SHUTDOWN; break; case 's': *operation = QDEVICE_TOOL_OPERATION_STATUS; break; case 'v': *verbose = 1; break; case 'p': free(*socket_path); *socket_path = strdup(optarg); if (*socket_path == NULL) { errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't alloc memory for socket path string"); } break; case 'h': case '?': usage(); exit(QDEVICE_TOOL_EXIT_CODE_USAGE); break; } } if (*operation == QDEVICE_TOOL_OPERATION_NONE) { usage(); exit(QDEVICE_TOOL_EXIT_CODE_USAGE); } } static int store_command(struct dynar *str, enum qdevice_tool_operation operation, int verbose) { const char *nline = "\n\0"; const int nline_len = 2; switch (operation) { case QDEVICE_TOOL_OPERATION_NONE: errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Unhandled operation none"); break; case QDEVICE_TOOL_OPERATION_SHUTDOWN: if (dynar_str_cat(str, "shutdown ") != 0) { return (-1); } break; case QDEVICE_TOOL_OPERATION_STATUS: if (dynar_str_cat(str, "status ") != 0) { return (-1); } break; } if (verbose) { if (dynar_str_cat(str, "verbose ") != 0) { return (-1); } } if (dynar_cat(str, nline, nline_len) != 0) { return (-1); } return (0); } /* * -1 - Internal error (can't alloc memory) * 0 - No error * 1 - IPC returned error * 2 - Unknown status line */ static int read_ipc_reply(FILE *f) { struct dynar read_str; int ch; int status_readed; int res; static const char *ok_str = "OK"; static const char *err_str = "Error"; int err_set; char c; dynar_init(&read_str, IPC_READ_BUF_SIZE); status_readed = 0; err_set = 0; res = 0; while ((ch = fgetc(f)) != EOF) { if (status_readed) { putc(ch, (err_set ? stderr : stdout)); } else { if (ch == '\r') { } else if (ch == '\n') { status_readed = 1; c = '\0'; if (dynar_cat(&read_str, &c, sizeof(c)) != 0) { res = -1; goto exit_destroy; } if (strcasecmp(dynar_data(&read_str), ok_str) == 0) { } else if (strcasecmp(dynar_data(&read_str), err_str) == 0) { err_set = 1; res = 1; fprintf(stderr, "Error: "); } else { res = 2; goto exit_destroy; } } else { c = ch; if (dynar_cat(&read_str, &c, sizeof(c)) != 0) { res = -1; goto exit_destroy; } } } } exit_destroy: dynar_destroy(&read_str); return (res); } int main(int argc, char * const argv[]) { enum qdevice_tool_operation operation; int verbose; char *socket_path; int sock_fd; FILE *sock; struct dynar send_str; int res; int exit_code; exit_code = QDEVICE_TOOL_EXIT_CODE_NO_ERROR; cli_parse(argc, argv, &operation, &verbose, &socket_path); - dynar_init(&send_str, QDEVICE_IPC_MAX_RECEIVE_SIZE); + dynar_init(&send_str, QDEVICE_DEFAULT_IPC_MAX_RECEIVE_SIZE); sock_fd = unix_socket_client_create(socket_path, 0); if (sock_fd == -1) { err(QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT, "Can't connect to QDevice socket (is QDevice running?)"); } sock = fdopen(sock_fd, "w+t"); if (sock == NULL) { err(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't open QDevice socket fd"); } if (store_command(&send_str, operation, verbose) != 0) { errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't store command"); } if (fprintf(sock, "%s", dynar_data(&send_str)) != strlen(dynar_data(&send_str)) || fflush(sock) != 0) { errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't send command"); } res = read_ipc_reply(sock); switch (res) { case -1: errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Internal error during IPC status line read"); break; case 0: break; case 1: exit_code = QDEVICE_TOOL_EXIT_CODE_QDEVICE_RETURNED_ERROR; break; case 2: errx(QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT, "Unknown status line returned by IPC server"); break; } if (fclose(sock) != 0) { warn("Can't close QDevice socket"); } free(socket_path); dynar_destroy(&send_str); return (exit_code); } diff --git a/qdevices/corosync-qdevice.c b/qdevices/corosync-qdevice.c index e4e6ff83..254b9de2 100644 --- a/qdevices/corosync-qdevice.c +++ b/qdevices/corosync-qdevice.c @@ -1,199 +1,250 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "dynar.h" +#include "dynar-str.h" +#include "dynar-getopt-lex.h" +#include "qdevice-advanced-settings.h" #include "qdevice-config.h" #include "qdevice-cmap.h" #include "qdevice-ipc.h" #include "qdevice-log.h" #include "qdevice-model.h" #include "qdevice-votequorum.h" #include "utils.h" struct qdevice_instance *global_instance; static void signal_int_handler(int sig) { qdevice_log(LOG_DEBUG, "SIGINT received - closing local unix socket"); qdevice_ipc_close(global_instance); } static void signal_term_handler(int sig) { qdevice_log(LOG_DEBUG, "SIGTERM received - closing server socket"); qdevice_ipc_close(global_instance); } static void signal_handlers_register(void) { struct sigaction act; act.sa_handler = signal_int_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, NULL); act.sa_handler = signal_term_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; sigaction(SIGTERM, &act, NULL); } static void usage(void) { - printf("usage: %s [-dfh]\n", QDEVICE_PROGRAM_NAME); + printf("usage: %s [-dfh] [-S option=value[,option2=value2,...]]\n", QDEVICE_PROGRAM_NAME); } static void -cli_parse(int argc, char * const argv[], int *foreground, int *force_debug) +cli_parse_long_opt(struct qdevice_advanced_settings *advanced_settings, const char *long_opt) +{ + struct dynar_getopt_lex lex; + struct dynar dynar_long_opt; + const char *opt; + const char *val; + int res; + + dynar_init(&dynar_long_opt, strlen(long_opt) + 1); + if (dynar_str_cpy(&dynar_long_opt, long_opt) != 0) { + errx(1, "Can't alloc memory for long option"); + } + + dynar_getopt_lex_init(&lex, &dynar_long_opt); + + while (dynar_getopt_lex_token_next(&lex) == 0 && strcmp(dynar_data(&lex.option), "") != 0) { + opt = dynar_data(&lex.option); + val = dynar_data(&lex.value); + + res = qdevice_advanced_settings_set(advanced_settings, opt, val); + switch (res) { + case -1: + errx(1, "Unknown option '%s'", opt); + break; + case -2: + errx(1, "Invalid value '%s' for option '%s'", val, opt); + break; + } + } + + dynar_getopt_lex_destroy(&lex); + dynar_destroy(&dynar_long_opt); +} + +static void +cli_parse(int argc, char * const argv[], int *foreground, int *force_debug, + struct qdevice_advanced_settings *advanced_settings) { int ch; *foreground = 0; *force_debug = 0; - while ((ch = getopt(argc, argv, "dfh")) != -1) { + while ((ch = getopt(argc, argv, "dfhS:")) != -1) { switch (ch) { case 'd': *force_debug = 1; break; case 'f': *foreground = 1; break; + case 'S': + cli_parse_long_opt(advanced_settings, optarg); + break; case 'h': case '?': usage(); exit(1); break; } } } int main(int argc, char * const argv[]) { struct qdevice_instance instance; + struct qdevice_advanced_settings advanced_settings; int foreground; int force_debug; int lock_file; int another_instance_running; - cli_parse(argc, argv, &foreground, &force_debug); + if (qdevice_advanced_settings_init(&advanced_settings) != 0) { + errx(1, "Can't alloc memory for advanced settings"); + } + + cli_parse(argc, argv, &foreground, &force_debug, &advanced_settings); - qdevice_instance_init(&instance); + qdevice_instance_init(&instance, &advanced_settings); qdevice_cmap_init(&instance); qdevice_log_init(&instance, force_debug); /* * Daemonize */ if (!foreground) { utils_tty_detach(); } - if ((lock_file = utils_flock(QDEVICE_LOCK_FILE, getpid(), &another_instance_running)) == -1) { + if ((lock_file = utils_flock(advanced_settings.lock_file, getpid(), + &another_instance_running)) == -1) { if (another_instance_running) { qdevice_log(LOG_ERR, "Another instance is running"); } else { qdevice_log_err(LOG_ERR, "Can't aquire lock"); } exit(1); } qdevice_log(LOG_DEBUG, "Initializing votequorum"); qdevice_votequorum_init(&instance); qdevice_log(LOG_DEBUG, "Initializing local socket"); if (qdevice_ipc_init(&instance) != 0) { return (1); } qdevice_log(LOG_DEBUG, "Registering qdevice models"); qdevice_model_register_all(); qdevice_log(LOG_DEBUG, "Configuring qdevice"); if (qdevice_instance_configure_from_cmap(&instance) != 0) { return (1); } qdevice_log(LOG_DEBUG, "Getting configuration node list"); if (qdevice_cmap_store_config_node_list(&instance) != 0) { return (1); } qdevice_log(LOG_DEBUG, "Initializing qdevice model"); if (qdevice_model_init(&instance) != 0) { return (1); } qdevice_log(LOG_DEBUG, "Initializing cmap tracking"); if (qdevice_cmap_add_track(&instance) != 0) { return (1); } global_instance = &instance; signal_handlers_register(); qdevice_log(LOG_DEBUG, "Running qdevice model"); if (qdevice_model_run(&instance) != 0) { return (1); } qdevice_log(LOG_DEBUG, "Removing cmap tracking"); if (qdevice_cmap_del_track(&instance) != 0) { return (1); } qdevice_log(LOG_DEBUG, "Destorying qdevice model"); qdevice_model_destroy(&instance); qdevice_ipc_destroy(&instance); qdevice_votequorum_destroy(&instance); qdevice_cmap_destroy(&instance); qdevice_log_close(&instance); qdevice_instance_destroy(&instance); + qdevice_advanced_settings_destroy(&advanced_settings); return (0); } diff --git a/qdevices/corosync-qnetd.c b/qdevices/corosync-qnetd.c index 493a1207..c6b8b0dc 100644 --- a/qdevices/corosync-qnetd.c +++ b/qdevices/corosync-qnetd.c @@ -1,653 +1,653 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qnet-config.h" #include "dynar.h" #include "dynar-str.h" #include "dynar-getopt-lex.h" #include "nss-sock.h" #include "pr-poll-array.h" #include "qnetd-advanced-settings.h" #include "qnetd-algorithm.h" #include "qnetd-instance.h" #include "qnetd-ipc.h" #include "qnetd-log.h" #include "qnetd-client-net.h" #include "qnetd-client-msg-received.h" #include "qnetd-poll-array-user-data.h" #include "utils.h" #include "msg.h" /* * This is global variable used for comunication with main loop and signal (calls close) */ struct qnetd_instance *global_instance; enum tlv_decision_algorithm_type qnetd_static_supported_decision_algorithms[QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE] = { TLV_DECISION_ALGORITHM_TYPE_TEST, TLV_DECISION_ALGORITHM_TYPE_FFSPLIT, TLV_DECISION_ALGORITHM_TYPE_2NODELMS, TLV_DECISION_ALGORITHM_TYPE_LMS, }; static void qnetd_err_nss(void) { qnetd_log_nss(LOG_CRIT, "NSS error"); exit(1); } static void qnetd_warn_nss(void) { qnetd_log_nss(LOG_WARNING, "NSS warning"); } static PRPollDesc * qnetd_pr_poll_array_create(struct qnetd_instance *instance) { struct pr_poll_array *poll_array; const struct qnetd_client_list *client_list; struct qnetd_client *client; PRPollDesc *poll_desc; struct qnetd_poll_array_user_data *user_data; const struct unix_socket_client_list *ipc_client_list; struct unix_socket_client *ipc_client; poll_array = &instance->poll_array; client_list = &instance->clients; ipc_client_list = &instance->local_ipc.clients; pr_poll_array_clean(poll_array); if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) { return (NULL); } poll_desc->fd = instance->server.socket; poll_desc->in_flags = PR_POLL_READ; user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET; if (qnetd_ipc_is_closed(instance)) { qnetd_log(LOG_DEBUG, "Listening socket is closed"); return (NULL); } if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) { return (NULL); } poll_desc->fd = instance->ipc_socket_poll_fd; poll_desc->in_flags = PR_POLL_READ; user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET; TAILQ_FOREACH(client, client_list, entries) { if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) { return (NULL); } poll_desc->fd = client->socket; poll_desc->in_flags = PR_POLL_READ; if (!send_buffer_list_empty(&client->send_buffer_list)) { poll_desc->in_flags |= PR_POLL_WRITE; } user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT; user_data->client = client; } TAILQ_FOREACH(ipc_client, ipc_client_list, entries) { if (!ipc_client->reading_line && !ipc_client->writing_buffer) { continue; } if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) { return (NULL); } poll_desc->fd = ((struct qnetd_ipc_user_data *)ipc_client->user_data)->nspr_poll_fd; if (ipc_client->reading_line) { poll_desc->in_flags |= PR_POLL_READ; } if (ipc_client->writing_buffer) { poll_desc->in_flags |= PR_POLL_WRITE; } user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT; user_data->ipc_client = ipc_client; } pr_poll_array_gc(poll_array); return (poll_array->array); } static int qnetd_poll(struct qnetd_instance *instance) { struct qnetd_client *client; PRPollDesc *pfds; PRInt32 poll_res; ssize_t i; int client_disconnect; struct qnetd_poll_array_user_data *user_data; struct unix_socket_client *ipc_client; client = NULL; client_disconnect = 0; pfds = qnetd_pr_poll_array_create(instance); if (pfds == NULL) { return (-1); } if ((poll_res = PR_Poll(pfds, pr_poll_array_size(&instance->poll_array), timer_list_time_to_expire(&instance->main_timer_list))) >= 0) { timer_list_expire(&instance->main_timer_list); /* * Walk thru pfds array and process events */ for (i = 0; i < pr_poll_array_size(&instance->poll_array); i++) { user_data = pr_poll_array_get_user_data(&instance->poll_array, i); client = NULL; ipc_client = NULL; client_disconnect = 0; switch (user_data->type) { case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET: break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT: client = user_data->client; client_disconnect = client->schedule_disconnect; break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET: break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT: ipc_client = user_data->ipc_client; client_disconnect = ipc_client->schedule_disconnect; } if (!client_disconnect && poll_res > 0 && pfds[i].out_flags & PR_POLL_READ) { switch (user_data->type) { case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET: qnetd_client_net_accept(instance); break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT: if (qnetd_client_net_read(instance, client) == -1) { client_disconnect = 1; } break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET: qnetd_ipc_accept(instance, &ipc_client); break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT: qnetd_ipc_io_read(instance, ipc_client); break; } } if (!client_disconnect && poll_res > 0 && pfds[i].out_flags & PR_POLL_WRITE) { switch (user_data->type) { case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET: /* * Poll write on listen socket -> fatal error */ qnetd_log(LOG_CRIT, "POLL_WRITE on listening socket"); return (-1); break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT: if (qnetd_client_net_write(instance, client) == -1) { client_disconnect = 1; } break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET: qnetd_log(LOG_CRIT, "POLL_WRITE on listening IPC socket"); return (-1); break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT: qnetd_ipc_io_write(instance, ipc_client); break; } } if (!client_disconnect && poll_res > 0 && (pfds[i].out_flags & (PR_POLL_ERR|PR_POLL_NVAL|PR_POLL_HUP|PR_POLL_EXCEPT)) && !(pfds[i].out_flags & (PR_POLL_READ|PR_POLL_WRITE))) { switch (user_data->type) { case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET: case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET: if (pfds[i].out_flags != PR_POLL_NVAL) { /* * Poll ERR on listening socket is fatal error. * POLL_NVAL is used as a signal to quit poll loop. */ qnetd_log(LOG_CRIT, "POLL_ERR (%u) on listening " "socket", pfds[i].out_flags); } else { qnetd_log(LOG_DEBUG, "Listening socket is closed"); } return (-1); break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT: qnetd_log(LOG_DEBUG, "POLL_ERR (%u) on client socket. " "Disconnecting.", pfds[i].out_flags); client_disconnect = 1; break; case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT: qnetd_log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket." " Disconnecting.", pfds[i].out_flags); client_disconnect = 1; break; } } /* * If client is scheduled for disconnect, disconnect it */ if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT && client_disconnect) { qnetd_instance_client_disconnect(instance, client, 0); } else if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT && (client_disconnect || ipc_client->schedule_disconnect)) { qnetd_ipc_client_disconnect(instance, ipc_client); } } } return (0); } static void signal_int_handler(int sig) { qnetd_log(LOG_DEBUG, "SIGINT received - closing server IPC socket"); qnetd_ipc_close(global_instance); } static void signal_term_handler(int sig) { qnetd_log(LOG_DEBUG, "SIGTERM received - closing server IPC socket"); qnetd_ipc_close(global_instance); } static void signal_handlers_register(void) { struct sigaction act; act.sa_handler = signal_int_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, NULL); act.sa_handler = signal_term_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; sigaction(SIGTERM, &act, NULL); } static void usage(void) { printf("usage: %s [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME); - printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value]\n", ""); + printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]\n", ""); } static void display_version(void) { enum msg_type *supported_messages; size_t no_supported_messages; size_t zi; msg_get_supported_messages(&supported_messages, &no_supported_messages); printf("Corosync Qdevice Network Daemon, version '%s'\n\n", VERSION); printf("Supported algorithms: "); for (zi = 0; zi < QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE; zi++) { if (zi != 0) { printf(", "); } printf("%s (%u)", tlv_decision_algorithm_type_to_str(qnetd_static_supported_decision_algorithms[zi]), qnetd_static_supported_decision_algorithms[zi]); } printf("\n"); printf("Supported message types: "); for (zi = 0; zi < no_supported_messages; zi++) { if (zi != 0) { printf(", "); } printf("%s (%u)", msg_type_to_str(supported_messages[zi]), supported_messages[zi]); } printf("\n"); } static void cli_parse_long_opt(struct qnetd_advanced_settings *advanced_settings, const char *long_opt) { struct dynar_getopt_lex lex; struct dynar dynar_long_opt; const char *opt; const char *val; int res; dynar_init(&dynar_long_opt, strlen(long_opt) + 1); if (dynar_str_cpy(&dynar_long_opt, long_opt) != 0) { errx(1, "Can't alloc memory for long option"); } dynar_getopt_lex_init(&lex, &dynar_long_opt); while (dynar_getopt_lex_token_next(&lex) == 0 && strcmp(dynar_data(&lex.option), "") != 0) { opt = dynar_data(&lex.option); val = dynar_data(&lex.value); res = qnetd_advanced_settings_set(advanced_settings, opt, val); switch (res) { case -1: errx(1, "Unknown option '%s'", opt); break; case -2: errx(1, "Invalid value '%s' for option '%s'", val, opt); break; } } dynar_getopt_lex_destroy(&lex); dynar_destroy(&dynar_long_opt); } static void cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port, int *foreground, int *debug_log, int *bump_log_priority, enum tlv_tls_supported *tls_supported, int *client_cert_required, size_t *max_clients, PRIntn *address_family, struct qnetd_advanced_settings *advanced_settings) { int ch; char *ep; long long int tmpll; *host_addr = NULL; *host_port = QNETD_DEFAULT_HOST_PORT; *foreground = 0; *debug_log = 0; *bump_log_priority = 0; *tls_supported = QNETD_DEFAULT_TLS_SUPPORTED; *client_cert_required = QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED; *max_clients = QNETD_DEFAULT_MAX_CLIENTS; *address_family = PR_AF_UNSPEC; while ((ch = getopt(argc, argv, "46dfhvc:l:m:p:S:s:")) != -1) { switch (ch) { case '4': *address_family = PR_AF_INET; break; case '6': *address_family = PR_AF_INET6; break; case 'f': *foreground = 1; break; case 'd': if (*debug_log) { *bump_log_priority = 1; } *debug_log = 1; break; case 'c': if ((*client_cert_required = utils_parse_bool_str(optarg)) == -1) { errx(1, "client_cert_required should be on/yes/1, off/no/0"); } break; case 'l': free(*host_addr); *host_addr = strdup(optarg); if (*host_addr == NULL) { errx(1, "Can't alloc memory for host addr string"); } break; case 'm': errno = 0; tmpll = strtoll(optarg, &ep, 10); if (tmpll < 0 || errno != 0 || *ep != '\0') { errx(1, "max clients value %s is invalid", optarg); } *max_clients = (size_t)tmpll; break; case 'p': *host_port = strtol(optarg, &ep, 10); if (*host_port <= 0 || *host_port > ((uint16_t)~0) || *ep != '\0') { errx(1, "host port must be in range 0-65535"); } break; case 'S': cli_parse_long_opt(advanced_settings, optarg); break; case 's': if (strcasecmp(optarg, "on") == 0) { *tls_supported = QNETD_DEFAULT_TLS_SUPPORTED; } else if (strcasecmp(optarg, "off") == 0) { *tls_supported = TLV_TLS_UNSUPPORTED; } else if (strcasecmp(optarg, "req") == 0) { *tls_supported = TLV_TLS_REQUIRED; } else { errx(1, "tls must be one of on, off, req"); } break; case 'v': display_version(); exit(1); break; case 'h': case '?': usage(); exit(1); break; } } } int main(int argc, char * const argv[]) { struct qnetd_instance instance; struct qnetd_advanced_settings advanced_settings; char *host_addr; uint16_t host_port; int foreground; int debug_log; int bump_log_priority; enum tlv_tls_supported tls_supported; int client_cert_required; size_t max_clients; PRIntn address_family; int lock_file; int another_instance_running; if (qnetd_advanced_settings_init(&advanced_settings) != 0) { errx(1, "Can't alloc memory for advanced settings"); } cli_parse(argc, argv, &host_addr, &host_port, &foreground, &debug_log, &bump_log_priority, &tls_supported, &client_cert_required, &max_clients, &address_family, &advanced_settings); if (foreground) { qnetd_log_init(QNETD_LOG_TARGET_STDERR); } else { qnetd_log_init(QNETD_LOG_TARGET_SYSLOG); } qnetd_log_set_debug(debug_log); qnetd_log_set_priority_bump(bump_log_priority); /* * Daemonize */ if (!foreground) { utils_tty_detach(); } if ((lock_file = utils_flock(advanced_settings.lock_file, getpid(), &another_instance_running)) == -1) { if (another_instance_running) { qnetd_log(LOG_ERR, "Another instance is running"); } else { qnetd_log_err(LOG_ERR, "Can't acquire lock"); } exit(1); } qnetd_log(LOG_DEBUG, "Initializing nss"); if (nss_sock_init_nss((tls_supported != TLV_TLS_UNSUPPORTED ? advanced_settings.nss_db_dir : NULL)) != 0) { qnetd_err_nss(); } if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) { qnetd_err_nss(); } if (qnetd_instance_init(&instance, tls_supported, client_cert_required, max_clients, &advanced_settings) == -1) { qnetd_log(LOG_ERR, "Can't initialize qnetd"); exit(1); } instance.host_addr = host_addr; instance.host_port = host_port; if (tls_supported != TLV_TLS_UNSUPPORTED && qnetd_instance_init_certs(&instance) == -1) { qnetd_err_nss(); } qnetd_log(LOG_DEBUG, "Initializing local socket"); if (qnetd_ipc_init(&instance) != 0) { return (1); } qnetd_log(LOG_DEBUG, "Creating listening socket"); instance.server.socket = nss_sock_create_listen_socket(instance.host_addr, instance.host_port, address_family); if (instance.server.socket == NULL) { qnetd_err_nss(); } if (nss_sock_set_non_blocking(instance.server.socket) != 0) { qnetd_err_nss(); } if (PR_Listen(instance.server.socket, instance.advanced_settings->listen_backlog) != PR_SUCCESS) { qnetd_err_nss(); } global_instance = &instance; signal_handlers_register(); qnetd_log(LOG_DEBUG, "Registering algorithms"); if (qnetd_algorithm_register_all() != 0) { exit(1); } qnetd_log(LOG_DEBUG, "QNetd ready to provide service"); /* * MAIN LOOP */ while (qnetd_poll(&instance) == 0) { } /* * Cleanup */ qnetd_ipc_destroy(&instance); if (PR_Close(instance.server.socket) != PR_SUCCESS) { qnetd_warn_nss(); } CERT_DestroyCertificate(instance.server.cert); SECKEY_DestroyPrivateKey(instance.server.private_key); SSL_ClearSessionCache(); SSL_ShutdownServerSessionIDCache(); qnetd_instance_destroy(&instance); qnetd_advanced_settings_destroy(&advanced_settings); if (NSS_Shutdown() != SECSuccess) { qnetd_warn_nss(); } if (PR_Cleanup() != PR_SUCCESS) { qnetd_warn_nss(); } qnetd_log_close(); return (0); } diff --git a/qdevices/qdevice-advanced-settings.c b/qdevices/qdevice-advanced-settings.c new file mode 100644 index 00000000..f0109601 --- /dev/null +++ b/qdevices/qdevice-advanced-settings.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "dynar.h" +#include "dynar-getopt-lex.h" +#include "dynar-str.h" +#include "qdevice-config.h" +#include "qnet-config.h" +#include "qdevice-advanced-settings.h" +#include "utils.h" + +int +qdevice_advanced_settings_init(struct qdevice_advanced_settings *settings) +{ + + memset(settings, 0, sizeof(*settings)); + if ((settings->lock_file = strdup(QDEVICE_DEFAULT_LOCK_FILE)) == NULL) { + return (-1); + } + if ((settings->local_socket_file = strdup(QDEVICE_DEFAULT_LOCAL_SOCKET_FILE)) == NULL) { + return (-1); + } + settings->local_socket_backlog = QDEVICE_DEFAULT_LOCAL_SOCKET_BACKLOG; + settings->max_cs_try_again = QDEVICE_DEFAULT_MAX_CS_TRY_AGAIN; + if ((settings->votequorum_device_name = strdup(QDEVICE_DEFAULT_VOTEQUORUM_DEVICE_NAME)) == NULL) { + return (-1); + } + settings->ipc_max_clients = QDEVICE_DEFAULT_IPC_MAX_CLIENTS; + settings->ipc_max_receive_size = QDEVICE_DEFAULT_IPC_MAX_RECEIVE_SIZE; + settings->ipc_max_send_size = QDEVICE_DEFAULT_IPC_MAX_SEND_SIZE; + if ((settings->net_nss_db_dir = strdup(QDEVICE_NET_DEFAULT_NSS_DB_DIR)) == NULL) { + return (-1); + } + settings->net_initial_msg_receive_size = QDEVICE_NET_DEFAULT_INITIAL_MSG_RECEIVE_SIZE; + settings->net_initial_msg_send_size = QDEVICE_NET_DEFAULT_INITIAL_MSG_SEND_SIZE; + settings->net_min_msg_send_size = QDEVICE_NET_DEFAULT_MIN_MSG_SEND_SIZE; + settings->net_max_msg_receive_size = QDEVICE_NET_DEFAULT_MAX_MSG_RECEIVE_SIZE; + settings->net_max_send_buffers = QDEVICE_NET_DEFAULT_MAX_SEND_BUFFERS; + if ((settings->net_nss_qnetd_cn = strdup(QDEVICE_NET_DEFAULT_NSS_QNETD_CN)) == NULL) { + return (-1); + } + if ((settings->net_nss_client_cert_nickname = + strdup(QDEVICE_NET_DEFAULT_NSS_CLIENT_CERT_NICKNAME)) == NULL) { + return (-1); + } + settings->net_heartbeat_interval_min = QDEVICE_NET_DEFAULT_HEARTBEAT_INTERVAL_MIN; + settings->net_heartbeat_interval_max = QDEVICE_NET_DEFAULT_HEARTBEAT_INTERVAL_MAX; + settings->net_min_connect_timeout = QDEVICE_NET_DEFAULT_MIN_CONNECT_TIMEOUT; + settings->net_max_connect_timeout = QDEVICE_NET_DEFAULT_MAX_CONNECT_TIMEOUT; + settings->net_delay_before_reconnect = QDEVICE_NET_DEFAULT_DELAY_BEFORE_RECONNECT; + settings->net_test_algorithm_enabled = QDEVICE_NET_DEFAULT_TEST_ALGORITHM_ENABLED; + + return (0); +} + +void +qdevice_advanced_settings_destroy(struct qdevice_advanced_settings *settings) +{ + + free(settings->local_socket_file); + free(settings->lock_file); + free(settings->votequorum_device_name); + free(settings->net_nss_db_dir); + free(settings->net_nss_qnetd_cn); + free(settings->net_nss_client_cert_nickname); +} + +/* + * 0 - No error + * -1 - Unknown option + * -2 - Incorrect value + */ +int +qdevice_advanced_settings_set(struct qdevice_advanced_settings *settings, + const char *option, const char *value) +{ + long long int tmpll; + char *ep; + + if (strcasecmp(option, "lock_file") == 0) { + free(settings->lock_file); + + if ((settings->lock_file = strdup(value)) == NULL) { + return (-1); + } + } else if (strcasecmp(option, "local_socket_file") == 0) { + free(settings->local_socket_file); + + if ((settings->local_socket_file = strdup(value)) == NULL) { + return (-1); + } + } else if (strcasecmp(option, "local_socket_backlog") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_MIN_LOCAL_SOCKET_BACKLOG || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->local_socket_backlog = (int)tmpll; + } else if (strcasecmp(option, "max_cs_try_again") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_MIN_MAX_CS_TRY_AGAIN || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->max_cs_try_again = (int)tmpll; + } else if (strcasecmp(option, "votequorum_device_name") == 0) { + free(settings->votequorum_device_name); + + if ((settings->votequorum_device_name = strdup(value)) == NULL) { + return (-1); + } + } else if (strcasecmp(option, "ipc_max_clients") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_MIN_IPC_MAX_CLIENTS || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->ipc_max_clients = (size_t)tmpll; + } else if (strcasecmp(option, "ipc_max_receive_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->ipc_max_receive_size = (size_t)tmpll; + } else if (strcasecmp(option, "ipc_max_send_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->ipc_max_send_size = (size_t)tmpll; + } else if (strcasecmp(option, "net_nss_db_dir") == 0) { + free(settings->net_nss_db_dir); + + if ((settings->net_nss_db_dir = strdup(value)) == NULL) { + return (-1); + } + } else if (strcasecmp(option, "net_initial_msg_receive_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_initial_msg_receive_size = (size_t)tmpll; + } else if (strcasecmp(option, "net_initial_msg_send_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_initial_msg_send_size = (size_t)tmpll; + } else if (strcasecmp(option, "net_min_msg_send_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_min_msg_send_size = (size_t)tmpll; + } else if (strcasecmp(option, "net_max_msg_receive_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_max_msg_receive_size = (size_t)tmpll; + } else if (strcasecmp(option, "net_max_send_buffers") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_MAX_SEND_BUFFERS || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_max_send_buffers = (size_t)tmpll; + } else if (strcasecmp(option, "net_nss_qnetd_cn") == 0) { + free(settings->net_nss_qnetd_cn); + + if ((settings->net_nss_qnetd_cn = strdup(value)) == NULL) { + return (-1); + } + } else if (strcasecmp(option, "net_nss_client_cert_nickname") == 0) { + free(settings->net_nss_client_cert_nickname); + + if ((settings->net_nss_client_cert_nickname = strdup(value)) == NULL) { + return (-1); + } + } else if (strcasecmp(option, "net_heartbeat_interval_min") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_HEARTBEAT_INTERVAL || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_heartbeat_interval_min = (uint32_t)tmpll; + } else if (strcasecmp(option, "net_heartbeat_interval_max") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_HEARTBEAT_INTERVAL || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_heartbeat_interval_max = (uint32_t)tmpll; + } else if (strcasecmp(option, "net_min_connect_timeout") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_CONNECT_TIMEOUT || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_min_connect_timeout = (uint32_t)tmpll; + } else if (strcasecmp(option, "net_max_connect_timeout") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_CONNECT_TIMEOUT || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_max_connect_timeout = (uint32_t)tmpll; + } else if (strcasecmp(option, "net_delay_before_reconnect") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QDEVICE_NET_MIN_DELAY_BEFORE_RECONNECT || errno != 0 || *ep != '\0') { + return (-2); + } + + settings->net_delay_before_reconnect = (int)tmpll; + } else if (strcasecmp(option, "net_test_algorithm_enabled") == 0) { + if ((tmpll = utils_parse_bool_str(value)) == -1) { + return (-2); + } + + settings->net_test_algorithm_enabled = (uint8_t)tmpll; + } else { + return (-1); + } + + return (0); +} diff --git a/qdevices/qdevice-config.h b/qdevices/qdevice-advanced-settings.h similarity index 58% copy from qdevices/qdevice-config.h copy to qdevices/qdevice-advanced-settings.h index 6fc6ac6c..f9f5d2ce 100644 --- a/qdevices/qdevice-config.h +++ b/qdevices/qdevice-advanced-settings.h @@ -1,81 +1,82 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 _QDEVICE_CONFIG_H_ -#define _QDEVICE_CONFIG_H_ - -#include - -#include -#include +#ifndef _QDEVICE_ADVANCED_SETTINGS_H_ +#define _QDEVICE_ADVANCED_SETTINGS_H_ #ifdef __cplusplus extern "C" { #endif -/* - * There are "hardcoded" defines for qdevice. It's not so good - * idea to change them as long as you are not 100% sure what you are doing. - */ -#define QDEVICE_LOCK_FILE LOCALSTATEDIR"/run/corosync-qdevice.pid" -#define QDEVICE_LOCAL_SOCKET_FILE LOCALSTATEDIR"/run/corosync-qdevice.sock" -#define QDEVICE_LOCAL_SOCKET_BACKLOG 10 - -#define QDEVICE_MAX_CS_TRY_AGAIN 10 +struct qdevice_advanced_settings { + char *lock_file; + char *local_socket_file; + int local_socket_backlog; + int max_cs_try_again; + char *votequorum_device_name; + size_t ipc_max_clients; + size_t ipc_max_send_size; + size_t ipc_max_receive_size; -#define QDEVICE_PROGRAM_NAME "corosync-qdevice" -#define QDEVICE_LOG_SUBSYS "QDEVICE" -#define QDEVICE_LOG_DEFAULT_TO_STDERR 1 -#define QDEVICE_LOG_DEFAULT_TO_SYSLOG 1 -#define QDEVICE_LOG_DEFAULT_TO_LOGFILE 0 -#define QDEVICE_LOG_DEFAULT_SYSLOG_FACILITY LOG_DAEMON -#define QDEVICE_LOG_DEFAULT_SYSLOG_PRIORITY LOG_INFO -#define QDEVICE_LOG_DEFAULT_DEBUG 0 -#define QDEVICE_LOG_DEFAULT_FILELINE 0 -#define QDEVICE_LOG_DEFAULT_TIMESTAMP 0 -#define QDEVICE_LOG_DEFAULT_FUNCTION_NAME 0 + /* + * Related to model NET + */ + char *net_nss_db_dir; + size_t net_initial_msg_receive_size; + size_t net_initial_msg_send_size; + size_t net_min_msg_send_size; + size_t net_max_msg_receive_size; + size_t net_max_send_buffers; + char *net_nss_qnetd_cn; + char *net_nss_client_cert_nickname; + uint32_t net_heartbeat_interval_min; + uint32_t net_heartbeat_interval_max; + uint32_t net_min_connect_timeout; + uint32_t net_max_connect_timeout; + int net_delay_before_reconnect; + uint8_t net_test_algorithm_enabled; +}; -#define QDEVICE_VOTEQUORUM_DEVICE_NAME "Qdevice" +extern int qdevice_advanced_settings_init(struct qdevice_advanced_settings *settings); -#define QDEVICE_IPC_MAX_CLIENTS 10 -#define QDEVICE_IPC_MAX_RECEIVE_SIZE (4*1024) -#define QDEVICE_IPC_MAX_SEND_SIZE (64*1024) +extern int qdevice_advanced_settings_set(struct qdevice_advanced_settings *settings, + const char *option, const char *value); -#define QDEVICE_TOOL_PROGRAM_NAME "corosync-qdevice-tool" +extern void qdevice_advanced_settings_destroy(struct qdevice_advanced_settings *settings); #ifdef __cplusplus } #endif -#endif /* _QDEVICE_CONFIG_H_ */ +#endif /* _QDEVICE_ADVANCED_SETTINGS_H_ */ diff --git a/qdevices/qdevice-cmap.c b/qdevices/qdevice-cmap.c index a04444f0..bdd7c77a 100644 --- a/qdevices/qdevice-cmap.c +++ b/qdevices/qdevice-cmap.c @@ -1,458 +1,458 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-config.h" #include "qdevice-cmap.h" #include "qdevice-log.h" #include "qdevice-log-debug.h" #include "qdevice-model.h" #include "utils.h" static uint32_t qdevice_cmap_autogenerate_node_id(const char *addr, int clear_node_high_byte) { struct addrinfo *ainfo; struct addrinfo ahints; int ret, i; memset(&ahints, 0, sizeof(ahints)); ahints.ai_socktype = SOCK_DGRAM; ahints.ai_protocol = IPPROTO_UDP; /* * Hardcoded AF_INET because autogenerated nodeid is valid only for ipv4 */ ahints.ai_family = AF_INET; ret = getaddrinfo(addr, NULL, &ahints, &ainfo); if (ret != 0) return (0); if (ainfo->ai_family != AF_INET) { freeaddrinfo(ainfo); return (0); } memcpy(&i, &((struct sockaddr_in *)ainfo->ai_addr)->sin_addr, sizeof(struct in_addr)); freeaddrinfo(ainfo); ret = htonl(i); if (clear_node_high_byte) { ret &= 0x7FFFFFFF; } return (ret); } int qdevice_cmap_get_nodelist(cmap_handle_t cmap_handle, struct node_list *list) { cs_error_t cs_err; cmap_iter_handle_t iter_handle; char key_name[CMAP_KEYNAME_MAXLEN + 1]; char tmp_key[CMAP_KEYNAME_MAXLEN + 1]; int res; int ret_value; unsigned int node_pos; uint32_t node_id; uint32_t data_center_id; char *tmp_str; char *addr0_str; int clear_node_high_byte; ret_value = 0; node_list_init(list); cs_err = cmap_iter_init(cmap_handle, "nodelist.node.", &iter_handle); if (cs_err != CS_OK) { return (-1); } while ((cs_err = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL)) == CS_OK) { res = sscanf(key_name, "nodelist.node.%u.%s", &node_pos, tmp_key); if (res != 2) { continue; } if (strcmp(tmp_key, "ring0_addr") != 0) { continue; } snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos); cs_err = cmap_get_uint32(cmap_handle, tmp_key, &node_id); if (cs_err == CS_ERR_NOT_EXIST) { /* * Nodeid doesn't exists -> autogenerate node id */ clear_node_high_byte = 0; if (cmap_get_string(cmap_handle, "totem.clear_node_high_bit", &tmp_str) == CS_OK) { if (strcmp (tmp_str, "yes") == 0) { clear_node_high_byte = 1; } free(tmp_str); } if (cmap_get_string(cmap_handle, key_name, &addr0_str) != CS_OK) { return (-1); } node_id = qdevice_cmap_autogenerate_node_id(addr0_str, clear_node_high_byte); free(addr0_str); } else if (cs_err != CS_OK) { ret_value = -1; goto iter_finalize; } snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.datacenterid", node_pos); if (cmap_get_uint32(cmap_handle, tmp_key, &data_center_id) != CS_OK) { data_center_id = 0; } if (node_list_add(list, node_id, data_center_id, TLV_NODE_STATE_NOT_SET) == NULL) { ret_value = -1; goto iter_finalize; } } iter_finalize: cmap_iter_finalize(cmap_handle, iter_handle); if (ret_value != 0) { node_list_free(list); } return (ret_value); } int qdevice_cmap_get_config_version(cmap_handle_t cmap_handle, uint64_t *config_version) { int res; if (cmap_get_uint64(cmap_handle, "totem.config_version", config_version) == CS_OK) { res = 0; } else { *config_version = 0; res = -1; } return (res); } int qdevice_cmap_store_config_node_list(struct qdevice_instance *instance) { int res; node_list_free(&instance->config_node_list); if (qdevice_cmap_get_nodelist(instance->cmap_handle, &instance->config_node_list) != 0) { qdevice_log(LOG_ERR, "Can't get configuration node list."); return (-1); } res = qdevice_cmap_get_config_version(instance->cmap_handle, &instance->config_node_list_version); instance->config_node_list_version_set = (res == 0); return (0); } void qdevice_cmap_init(struct qdevice_instance *instance) { cs_error_t res; int no_retries; no_retries = 0; while ((res = cmap_initialize(&instance->cmap_handle)) == CS_ERR_TRY_AGAIN && - no_retries++ < QDEVICE_MAX_CS_TRY_AGAIN) { + no_retries++ < instance->advanced_settings->max_cs_try_again) { (void)poll(NULL, 0, 1000); } if (res != CS_OK) { errx(1, "Failed to initialize the cmap API. Error %s", cs_strerror(res)); } if ((res = cmap_context_set(instance->cmap_handle, (void *)instance)) != CS_OK) { errx(1, "Can't set cmap context. Error %s", cs_strerror(res)); } cmap_fd_get(instance->cmap_handle, &instance->cmap_poll_fd); } static void qdevice_cmap_node_list_event(struct qdevice_instance *instance) { struct node_list nlist; int config_version_set; uint64_t config_version; qdevice_log(LOG_DEBUG, "Node list configuration possibly changed"); if (qdevice_cmap_get_nodelist(instance->cmap_handle, &nlist) != 0) { qdevice_log(LOG_ERR, "Can't get configuration node list."); if (qdevice_model_get_config_node_list_failed(instance) != 0) { qdevice_log(LOG_DEBUG, "qdevice_model_get_config_node_list_failed returned error -> exit"); exit(2); } return ; } config_version_set = (qdevice_cmap_get_config_version(instance->cmap_handle, &config_version) == 0); if (node_list_eq(&instance->config_node_list, &nlist)) { return ; } qdevice_log(LOG_DEBUG, "Node list changed"); if (config_version_set) { qdevice_log(LOG_DEBUG, " config_version = "UTILS_PRI_CONFIG_VERSION, config_version); } qdevice_log_debug_dump_node_list(&nlist); if (qdevice_model_config_node_list_changed(instance, &nlist, config_version_set, config_version) != 0) { qdevice_log(LOG_DEBUG, "qdevice_model_config_node_list_changed returned error -> exit"); exit(2); } node_list_free(&instance->config_node_list); if (node_list_clone(&instance->config_node_list, &nlist) != 0) { qdevice_log(LOG_ERR, "Can't allocate instance->config_node_list clone"); node_list_free(&nlist); if (qdevice_model_get_config_node_list_failed(instance) != 0) { qdevice_log(LOG_DEBUG, "qdevice_model_get_config_node_list_failed returned error -> exit"); exit(2); } return ; } instance->config_node_list_version_set = config_version_set; if (config_version_set) { instance->config_node_list_version = config_version; } } static void qdevice_cmap_logging_event(struct qdevice_instance *instance) { qdevice_log(LOG_DEBUG, "Logging configuration possibly changed"); qdevice_log_configure(instance); } static void qdevice_cmap_reload_cb(cmap_handle_t cmap_handle, cmap_track_handle_t cmap_track_handle, int32_t event, const char *key_name, struct cmap_notify_value new_value, struct cmap_notify_value old_value, void *user_data) { cs_error_t cs_res; uint8_t reload; struct qdevice_instance *instance; int node_list_event; int logging_event; const char *node_list_prefix_str; const char *logging_prefix_str; node_list_event = 0; logging_event = 0; node_list_prefix_str = "nodelist."; logging_prefix_str = "logging."; if (cmap_context_get(cmap_handle, (const void **)&instance) != CS_OK) { qdevice_log(LOG_ERR, "Fatal error. Can't get cmap context"); exit(1); } /* * Wait for full reload */ if (strcmp(key_name, "config.totemconfig_reload_in_progress") == 0 && new_value.type == CMAP_VALUETYPE_UINT8 && new_value.len == sizeof(reload)) { reload = 1; if (memcmp(new_value.data, &reload, sizeof(reload)) == 0) { /* * Ignore nodelist changes */ instance->cmap_reload_in_progress = 1; return ; } else { instance->cmap_reload_in_progress = 0; node_list_event = 1; logging_event = 1; } } if (instance->cmap_reload_in_progress) { return ; } if (((cs_res = cmap_get_uint8(cmap_handle, "config.totemconfig_reload_in_progress", &reload)) == CS_OK) && reload == 1) { return ; } if (strncmp(key_name, node_list_prefix_str, strlen(node_list_prefix_str)) == 0) { node_list_event = 1; } if (strncmp(key_name, logging_prefix_str, strlen(logging_prefix_str)) == 0) { logging_event = 1; } if (logging_event) { qdevice_cmap_logging_event(instance); } if (node_list_event) { qdevice_cmap_node_list_event(instance); } } int qdevice_cmap_add_track(struct qdevice_instance *instance) { cs_error_t res; res = cmap_track_add(instance->cmap_handle, "config.totemconfig_reload_in_progress", CMAP_TRACK_ADD | CMAP_TRACK_MODIFY, qdevice_cmap_reload_cb, NULL, &instance->cmap_reload_track_handle); if (res != CS_OK) { qdevice_log(LOG_ERR, "Can't initialize cmap totemconfig_reload_in_progress tracking"); return (-1); } res = cmap_track_add(instance->cmap_handle, "nodelist.", CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX, qdevice_cmap_reload_cb, NULL, &instance->cmap_nodelist_track_handle); if (res != CS_OK) { qdevice_log(LOG_ERR, "Can't initialize cmap nodelist tracking"); return (-1); } res = cmap_track_add(instance->cmap_handle, "logging.", CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX, qdevice_cmap_reload_cb, NULL, &instance->cmap_logging_track_handle); if (res != CS_OK) { qdevice_log(LOG_ERR, "Can't initialize logging tracking"); return (-1); } return (0); } int qdevice_cmap_del_track(struct qdevice_instance *instance) { cs_error_t res; res = cmap_track_delete(instance->cmap_handle, instance->cmap_reload_track_handle); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Can't delete cmap totemconfig_reload_in_progress tracking"); } res = cmap_track_delete(instance->cmap_handle, instance->cmap_nodelist_track_handle); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Can't delete cmap nodelist tracking"); } res = cmap_track_delete(instance->cmap_handle, instance->cmap_logging_track_handle); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Can't delete cmap logging tracking"); } return (0); } void qdevice_cmap_destroy(struct qdevice_instance *instance) { cs_error_t res; res = cmap_finalize(instance->cmap_handle); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Can't finalize cmap. Error %s", cs_strerror(res)); } } int qdevice_cmap_dispatch(struct qdevice_instance *instance) { cs_error_t res; res = cmap_dispatch(instance->cmap_handle, CS_DISPATCH_ALL); if (res != CS_OK && res != CS_ERR_TRY_AGAIN) { qdevice_log(LOG_ERR, "Can't dispatch cmap messages"); return (-1); } return (0); } diff --git a/qdevices/qdevice-config.h b/qdevices/qdevice-config.h index 6fc6ac6c..aab5f80f 100644 --- a/qdevices/qdevice-config.h +++ b/qdevices/qdevice-config.h @@ -1,81 +1,86 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 _QDEVICE_CONFIG_H_ #define _QDEVICE_CONFIG_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /* * There are "hardcoded" defines for qdevice. It's not so good - * idea to change them as long as you are not 100% sure what you are doing. + * idea to change them as long as you are not 100% sure what you are doing. Also + * most of them can be changed in CLI via advanced_settings (-S). */ -#define QDEVICE_LOCK_FILE LOCALSTATEDIR"/run/corosync-qdevice.pid" -#define QDEVICE_LOCAL_SOCKET_FILE LOCALSTATEDIR"/run/corosync-qdevice.sock" -#define QDEVICE_LOCAL_SOCKET_BACKLOG 10 +#define QDEVICE_DEFAULT_LOCK_FILE LOCALSTATEDIR"/run/corosync-qdevice.pid" +#define QDEVICE_DEFAULT_LOCAL_SOCKET_FILE LOCALSTATEDIR"/run/corosync-qdevice.sock" +#define QDEVICE_DEFAULT_LOCAL_SOCKET_BACKLOG 10 +#define QDEVICE_MIN_LOCAL_SOCKET_BACKLOG 1 -#define QDEVICE_MAX_CS_TRY_AGAIN 10 +#define QDEVICE_DEFAULT_MAX_CS_TRY_AGAIN 10 +#define QDEVICE_MIN_MAX_CS_TRY_AGAIN 1 #define QDEVICE_PROGRAM_NAME "corosync-qdevice" #define QDEVICE_LOG_SUBSYS "QDEVICE" #define QDEVICE_LOG_DEFAULT_TO_STDERR 1 #define QDEVICE_LOG_DEFAULT_TO_SYSLOG 1 #define QDEVICE_LOG_DEFAULT_TO_LOGFILE 0 #define QDEVICE_LOG_DEFAULT_SYSLOG_FACILITY LOG_DAEMON #define QDEVICE_LOG_DEFAULT_SYSLOG_PRIORITY LOG_INFO #define QDEVICE_LOG_DEFAULT_DEBUG 0 #define QDEVICE_LOG_DEFAULT_FILELINE 0 #define QDEVICE_LOG_DEFAULT_TIMESTAMP 0 #define QDEVICE_LOG_DEFAULT_FUNCTION_NAME 0 -#define QDEVICE_VOTEQUORUM_DEVICE_NAME "Qdevice" +#define QDEVICE_DEFAULT_VOTEQUORUM_DEVICE_NAME "Qdevice" -#define QDEVICE_IPC_MAX_CLIENTS 10 -#define QDEVICE_IPC_MAX_RECEIVE_SIZE (4*1024) -#define QDEVICE_IPC_MAX_SEND_SIZE (64*1024) +#define QDEVICE_DEFAULT_IPC_MAX_CLIENTS 10 +#define QDEVICE_MIN_IPC_MAX_CLIENTS 0 +#define QDEVICE_DEFAULT_IPC_MAX_RECEIVE_SIZE (4*1024) +#define QDEVICE_DEFAULT_IPC_MAX_SEND_SIZE (64*1024) +#define QDEVICE_MIN_IPC_RECEIVE_SEND_SIZE 1024 #define QDEVICE_TOOL_PROGRAM_NAME "corosync-qdevice-tool" #ifdef __cplusplus } #endif #endif /* _QDEVICE_CONFIG_H_ */ diff --git a/qdevices/qdevice-instance.c b/qdevices/qdevice-instance.c index b73fdb3a..862e0029 100644 --- a/qdevices/qdevice-instance.c +++ b/qdevices/qdevice-instance.c @@ -1,97 +1,99 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-instance.h" #include "qdevice-log.h" #include "qdevice-model.h" int -qdevice_instance_init(struct qdevice_instance *instance) +qdevice_instance_init(struct qdevice_instance *instance, + const struct qdevice_advanced_settings *advanced_settings) { memset(instance, 0, sizeof(*instance)); node_list_init(&instance->config_node_list); instance->vq_last_poll = ((time_t) -1); + instance->advanced_settings = advanced_settings; return (0); } int qdevice_instance_destroy(struct qdevice_instance *instance) { node_list_free(&instance->config_node_list); return (0); } int qdevice_instance_configure_from_cmap(struct qdevice_instance *instance) { char *str; if (cmap_get_string(instance->cmap_handle, "quorum.device.model", &str) != CS_OK) { qdevice_log(LOG_ERR, "Can't read quorum.device.model cmap key."); return (-1); } if (qdevice_model_str_to_type(str, &instance->model_type) != 0) { qdevice_log(LOG_ERR, "Configured device model %s is not supported.", str); free(str); return (-1); } free(str); if (cmap_get_uint32(instance->cmap_handle, "runtime.votequorum.this_node_id", &instance->node_id) != CS_OK) { qdevice_log(LOG_ERR, "Unable to retrive this node nodeid."); return (-1); } if (cmap_get_uint32(instance->cmap_handle, "quorum.device.timeout", &instance->heartbeat_interval) != CS_OK) { instance->heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_TIMEOUT; } if (cmap_get_uint32(instance->cmap_handle, "quorum.device.sync_timeout", &instance->sync_heartbeat_interval) != CS_OK) { instance->sync_heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_SYNC_TIMEOUT; } return (0); } diff --git a/qdevices/qdevice-instance.h b/qdevices/qdevice-instance.h index 5a9d3120..bf7b951d 100644 --- a/qdevices/qdevice-instance.h +++ b/qdevices/qdevice-instance.h @@ -1,115 +1,119 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 _QDEVICE_INSTANCE_H_ #define _QDEVICE_INSTANCE_H_ #include #include #include #include #include +#include "qdevice-advanced-settings.h" #include "qdevice-model-type.h" #include "node-list.h" #include "unix-socket-ipc.h" #ifdef __cplusplus extern "C" { #endif struct qdevice_instance { cmap_handle_t cmap_handle; int cmap_poll_fd; int cmap_reload_in_progress; cmap_track_handle_t cmap_reload_track_handle; cmap_track_handle_t cmap_nodelist_track_handle; cmap_track_handle_t cmap_logging_track_handle; votequorum_handle_t votequorum_handle; int votequorum_poll_fd; struct unix_socket_ipc local_ipc; enum qdevice_model_type model_type; uint32_t node_id; uint32_t heartbeat_interval; /* Heartbeat interval during normal operation */ uint32_t sync_heartbeat_interval; /* Heartbeat interval during corosync sync */ struct node_list config_node_list; int config_node_list_version_set; uint64_t config_node_list_version; /* * Copy of votequorum_quorum_notify_fn callback paramters. * Set after model callback is called. */ uint32_t vq_quorum_quorate; uint32_t vq_quorum_node_list_entries; votequorum_node_t *vq_quorum_node_list; /* * Copy of votequorum_nodelist_notify_fn callback paramters. * Set after model callback is called. */ votequorum_ring_id_t vq_node_list_ring_id; uint32_t vq_node_list_entries; uint32_t *vq_node_list; /* * Copy of votequorum_expectedvotes_notify_fn callback parameters. * Set after model callback is called. */ uint32_t vq_expected_votes; time_t vq_last_poll; int vq_last_poll_cast_vote; void *model_data; + + const struct qdevice_advanced_settings *advanced_settings; }; -extern int qdevice_instance_init(struct qdevice_instance *instance); +extern int qdevice_instance_init(struct qdevice_instance *instance, + const struct qdevice_advanced_settings *advanced_settings); extern int qdevice_instance_destroy(struct qdevice_instance *instance); extern int qdevice_instance_configure_from_cmap(struct qdevice_instance *instance); #ifdef __cplusplus } #endif #endif /* _QDEVICE_INSTANCE_H_ */ diff --git a/qdevices/qdevice-ipc.c b/qdevices/qdevice-ipc.c index 9b8ff574..6312441a 100644 --- a/qdevices/qdevice-ipc.c +++ b/qdevices/qdevice-ipc.c @@ -1,332 +1,335 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-config.h" #include "qdevice-ipc.h" #include "qdevice-log.h" #include "unix-socket-ipc.h" #include "dynar-simple-lex.h" #include "dynar-str.h" #include "qdevice-ipc-cmd.h" int qdevice_ipc_init(struct qdevice_instance *instance) { - if (unix_socket_ipc_init(&instance->local_ipc, QDEVICE_LOCAL_SOCKET_FILE, - QDEVICE_LOCAL_SOCKET_BACKLOG, QDEVICE_IPC_MAX_CLIENTS, QDEVICE_IPC_MAX_RECEIVE_SIZE, - QDEVICE_IPC_MAX_SEND_SIZE) != 0) { + if (unix_socket_ipc_init(&instance->local_ipc, + instance->advanced_settings->local_socket_file, + instance->advanced_settings->local_socket_backlog, + instance->advanced_settings->ipc_max_clients, + instance->advanced_settings->ipc_max_receive_size, + instance->advanced_settings->ipc_max_send_size) != 0) { qdevice_log_err(LOG_ERR, "Can't create unix socket"); return (-1); } return (0); } int qdevice_ipc_close(struct qdevice_instance *instance) { int res; res = unix_socket_ipc_close(&instance->local_ipc); if (res != 0) { qdevice_log_err(LOG_WARNING, "Can't close local IPC"); } return (res); } int qdevice_ipc_is_closed(struct qdevice_instance *instance) { return (unix_socket_ipc_is_closed(&instance->local_ipc)); } int qdevice_ipc_destroy(struct qdevice_instance *instance) { int res; struct unix_socket_client *client; const struct unix_socket_client_list *ipc_client_list; ipc_client_list = &instance->local_ipc.clients; TAILQ_FOREACH(client, ipc_client_list, entries) { free(client->user_data); } res = unix_socket_ipc_destroy(&instance->local_ipc); if (res != 0) { qdevice_log_err(LOG_WARNING, "Can't destroy local IPC"); } return (res); } int qdevice_ipc_accept(struct qdevice_instance *instance, struct unix_socket_client **res_client) { int res; int accept_res; accept_res = unix_socket_ipc_accept(&instance->local_ipc, res_client); switch (accept_res) { case -1: qdevice_log_err(LOG_ERR, "Can't accept local IPC connection"); res = -1; goto return_res; break; case -2: qdevice_log(LOG_ERR, "Maximum IPC clients reached. Not accepting connection"); res = -1; goto return_res; break; case -3: qdevice_log(LOG_ERR, "Can't add client to list"); res = -1; goto return_res; break; default: unix_socket_client_read_line(*res_client, 1); res = 0; break; } (*res_client)->user_data = malloc(sizeof(struct qdevice_ipc_user_data)); if ((*res_client)->user_data == NULL) { qdevice_log(LOG_ERR, "Can't alloc IPC client user data"); res = -1; qdevice_ipc_client_disconnect(instance, *res_client); } memset((*res_client)->user_data, 0, sizeof(struct qdevice_ipc_user_data)); return_res: return (res); } void qdevice_ipc_client_disconnect(struct qdevice_instance *instance, struct unix_socket_client *client) { free(client->user_data); unix_socket_ipc_client_disconnect(&instance->local_ipc, client); } int qdevice_ipc_send_error(struct qdevice_instance *instance, struct unix_socket_client *client, const char *error_fmt, ...) { va_list ap; int res; va_start(ap, error_fmt); res = ((dynar_str_cpy(&client->send_buffer, "Error\n") == 0) && (dynar_str_vcatf(&client->send_buffer, error_fmt, ap) > 0) && (dynar_str_cat(&client->send_buffer, "\n") == 0)); va_end(ap); if (res) { unix_socket_client_write_buffer(client, 1); } else { qdevice_log(LOG_ERR, "Can't send ipc error to client (buffer too small)"); } return (res ? 0 : -1); } int qdevice_ipc_send_buffer(struct qdevice_instance *instance, struct unix_socket_client *client) { if (dynar_str_prepend(&client->send_buffer, "OK\n") != 0) { qdevice_log(LOG_ERR, "Can't send ipc message to client (buffer too small)"); if (qdevice_ipc_send_error(instance, client, "Internal IPC buffer too small") != 0) { return (-1); } return (0); } unix_socket_client_write_buffer(client, 1); return (0); } static void qdevice_ipc_parse_line(struct qdevice_instance *instance, struct unix_socket_client *client) { struct dynar_simple_lex lex; struct dynar *token; char *str; struct qdevice_ipc_user_data *ipc_user_data; int verbose; ipc_user_data = (struct qdevice_ipc_user_data *)client->user_data; dynar_simple_lex_init(&lex, &client->receive_buffer, DYNAR_SIMPLE_LEX_TYPE_PLAIN); token = dynar_simple_lex_token_next(&lex); verbose = 0; if (token == NULL) { qdevice_log(LOG_ERR, "Can't alloc memory for simple lex"); if (qdevice_ipc_send_error(instance, client, "Command too long") != 0) { client->schedule_disconnect = 1; } return; } str = dynar_data(token); if (strcasecmp(str, "") == 0) { qdevice_log(LOG_DEBUG, "IPC client doesn't send command"); if (qdevice_ipc_send_error(instance, client, "No command specified") != 0) { client->schedule_disconnect = 1; } } else if (strcasecmp(str, "shutdown") == 0) { qdevice_log(LOG_DEBUG, "IPC client requested shutdown"); ipc_user_data->shutdown_requested = 1; if (qdevice_ipc_send_buffer(instance, client) != 0) { client->schedule_disconnect = 1; } } else if (strcasecmp(str, "status") == 0) { token = dynar_simple_lex_token_next(&lex); str = dynar_data(token); if (token != NULL && strcmp(str, "") != 0) { if (strcasecmp(str, "verbose") == 0) { verbose = 1; } } if (qdevice_ipc_cmd_status(instance, &client->send_buffer, verbose) != 0) { if (qdevice_ipc_send_error(instance, client, "Can't get QDevice status") != 0) { client->schedule_disconnect = 1; } } else { if (qdevice_ipc_send_buffer(instance, client) != 0) { client->schedule_disconnect = 1; } } } else { qdevice_log(LOG_DEBUG, "IPC client sent unknown command"); if (qdevice_ipc_send_error(instance, client, "Unknown command '%s'", str) != 0) { client->schedule_disconnect = 1; } } dynar_simple_lex_destroy(&lex); } void qdevice_ipc_io_read(struct qdevice_instance *instance, struct unix_socket_client *client) { int res; res = unix_socket_client_io_read(client); switch (res) { case 0: /* * Partial read */ break; case -1: qdevice_log(LOG_DEBUG, "IPC client closed connection"); client->schedule_disconnect = 1; break; case -2: qdevice_log(LOG_ERR, "Can't store message from IPC client. Disconnecting client."); client->schedule_disconnect = 1; break; case -3: qdevice_log_err(LOG_ERR, "Can't receive message from IPC client. Disconnecting client."); client->schedule_disconnect = 1; break; case 1: /* * Full message received */ unix_socket_client_read_line(client, 0); qdevice_ipc_parse_line(instance, client); break; } } void qdevice_ipc_io_write(struct qdevice_instance *instance, struct unix_socket_client *client) { int res; struct qdevice_ipc_user_data *ipc_user_data; ipc_user_data = (struct qdevice_ipc_user_data *)client->user_data; res = unix_socket_client_io_write(client); switch (res) { case 0: /* * Partial send */ break; case -1: qdevice_log(LOG_DEBUG, "IPC client closed connection"); client->schedule_disconnect = 1; break; case -2: qdevice_log_err(LOG_ERR, "Can't send message to IPC client. Disconnecting client"); client->schedule_disconnect = 1; break; case 1: /* * Full message sent */ unix_socket_client_write_buffer(client, 0); client->schedule_disconnect = 1; if (ipc_user_data->shutdown_requested) { qdevice_ipc_close(instance); } break; } } diff --git a/qdevices/qdevice-model-net.c b/qdevices/qdevice-model-net.c index 2927338a..900cac7e 100644 --- a/qdevices/qdevice-model-net.c +++ b/qdevices/qdevice-model-net.c @@ -1,508 +1,509 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-model.h" #include "qdevice-model-net.h" #include "qdevice-log.h" #include "qdevice-net-cast-vote-timer.h" #include "qdevice-net-instance.h" #include "qdevice-net-ipc-cmd.h" #include "qdevice-net-algorithm.h" #include "qdevice-net-poll.h" #include "qdevice-net-send.h" #include "qdevice-net-votequorum.h" #include "qnet-config.h" #include "nss-sock.h" int qdevice_model_net_init(struct qdevice_instance *instance) { struct qdevice_net_instance *net_instance; qdevice_log(LOG_DEBUG, "Initializing qdevice_net_instance"); if (qdevice_net_instance_init_from_cmap(instance) != 0) { return (-1); } net_instance = instance->model_data; qdevice_log(LOG_DEBUG, "Registering algorithms"); if (qdevice_net_algorithm_register_all() != 0) { return (-1); } qdevice_log(LOG_DEBUG, "Initializing NSS"); if (nss_sock_init_nss((net_instance->tls_supported != TLV_TLS_UNSUPPORTED ? - (char *)QDEVICE_NET_NSS_DB_DIR : NULL)) != 0) { + instance->advanced_settings->net_nss_db_dir : NULL)) != 0) { qdevice_log_nss(LOG_ERR, "Can't init nss"); return (-1); } if (qdevice_net_cast_vote_timer_update(net_instance, TLV_VOTE_ASK_LATER) != 0) { qdevice_log(LOG_ERR, "Can't update cast vote timer"); return (-1); } if (qdevice_net_algorithm_init(net_instance) != 0) { qdevice_log(LOG_ERR, "Algorithm init failed"); return (-1); } return (0); } int qdevice_model_net_destroy(struct qdevice_instance *instance) { struct qdevice_net_instance *net_instance; net_instance = instance->model_data; qdevice_log(LOG_DEBUG, "Destroying algorithm"); qdevice_net_algorithm_destroy(net_instance); qdevice_log(LOG_DEBUG, "Destroying qdevice_net_instance"); qdevice_net_instance_destroy(net_instance); qdevice_log(LOG_DEBUG, "Shutting down NSS"); SSL_ClearSessionCache(); if (NSS_Shutdown() != SECSuccess) { qdevice_log_nss(LOG_WARNING, "Can't shutdown NSS"); } if (PR_Cleanup() != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Can't shutdown NSPR"); } free(net_instance); return (0); } static int qdevice_model_net_timer_connect_timeout(void *data1, void *data2) { struct qdevice_net_instance *instance; instance = (struct qdevice_net_instance *)data1; qdevice_log(LOG_ERR, "Connect timeout"); instance->schedule_disconnect = 1; instance->connect_timer = NULL; instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_CONNECT_TO_THE_SERVER; return (0); } static PRIntn qdevice_model_net_get_af(const struct qdevice_net_instance *instance) { PRIntn af; af = PR_AF_UNSPEC; if (instance->force_ip_version == 4) { af = PR_AF_INET; } if (instance->force_ip_version == 6) { af = PR_AF_INET6; } return (af); } int qdevice_model_net_run(struct qdevice_instance *instance) { struct qdevice_net_instance *net_instance; int try_connect; int res; enum tlv_vote vote; net_instance = instance->model_data; qdevice_log(LOG_DEBUG, "Executing qdevice-net"); try_connect = 1; while (try_connect) { net_instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT; net_instance->socket = NULL; net_instance->connect_timer = timer_list_add(&net_instance->main_timer_list, net_instance->connect_timeout, qdevice_model_net_timer_connect_timeout, (void *)net_instance, NULL); if (net_instance->connect_timer == NULL) { qdevice_log(LOG_CRIT, "Can't schedule connect timer"); try_connect = 0; break; } qdevice_log(LOG_DEBUG, "Trying connect to qnetd server %s:%u (timeout = %ums)", net_instance->host_addr, net_instance->host_port, net_instance->connect_timeout); res = nss_sock_non_blocking_client_init(net_instance->host_addr, net_instance->host_port, qdevice_model_net_get_af(net_instance), &net_instance->non_blocking_client); if (res == -1) { qdevice_log_nss(LOG_ERR, "Can't initialize non blocking client connection"); } res = nss_sock_non_blocking_client_try_next(&net_instance->non_blocking_client); if (res == -1) { qdevice_log_nss(LOG_ERR, "Can't connect to qnetd host"); nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client); } while (qdevice_net_poll(net_instance) == 0) { }; if (net_instance->connect_timer != NULL) { timer_list_delete(&net_instance->main_timer_list, net_instance->connect_timer); net_instance->connect_timer = NULL; } if (net_instance->echo_request_timer != NULL) { timer_list_delete(&net_instance->main_timer_list, net_instance->echo_request_timer); net_instance->echo_request_timer = NULL; } try_connect = qdevice_net_disconnect_reason_try_reconnect(net_instance->disconnect_reason); vote = TLV_VOTE_NO_CHANGE; if (qdevice_net_algorithm_disconnected(net_instance, net_instance->disconnect_reason, &try_connect, &vote) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error, force exit"); return (-1); } else { qdevice_log(LOG_ERR, "Algorithm result vote is %s", tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_ERR, "qdevice_model_net_run fatal error. " " Can't update cast vote timer vote"); } if (qdevice_net_disconnect_reason_force_disconnect(net_instance->disconnect_reason)) { try_connect = 0; } if (net_instance->socket != NULL) { if (PR_Close(net_instance->socket) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close connection"); } net_instance->socket = NULL; } if (!net_instance->non_blocking_client.destroyed) { nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client); } if (net_instance->non_blocking_client.socket != NULL) { if (PR_Close(net_instance->non_blocking_client.socket) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close non-blocking client connection"); } net_instance->non_blocking_client.socket = NULL; } qdevice_net_instance_clean(net_instance); if (try_connect) { /* * Give qnetd server a little time before reconnect */ - (void)poll(NULL, 0, random() % 1000); + (void)poll(NULL, 0, + random() % instance->advanced_settings->net_delay_before_reconnect); } } return (0); } /* * Called when cmap reload (or nodelist) was requested. * * nlist is node list * config_version is valid only if config_version_set != 0 * * Should return 0 if processing should continue or -1 to call exit */ int qdevice_model_net_config_node_list_changed(struct qdevice_instance *instance, const struct node_list *nlist, int config_version_set, uint64_t config_version) { struct qdevice_net_instance *net_instance; int send_node_list; enum tlv_vote vote; net_instance = instance->model_data; if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { /* * Nodelist changed, but connection to qnetd not initiated yet. */ send_node_list = 0; if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } else { vote = TLV_VOTE_NO_CHANGE; } } else { send_node_list = 1; vote = TLV_VOTE_NO_CHANGE; } if (qdevice_net_algorithm_config_node_list_changed(net_instance, nlist, config_version_set, config_version, &send_node_list, &vote) != 0) { qdevice_log(LOG_ERR, "Algorithm returned error, force exit"); return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s node list and result vote is %s", (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_config_node_list_changed fatal error. " " Can't update cast vote timer vote"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; } if (send_node_list) { if (qdevice_net_send_config_node_list(net_instance, nlist, config_version_set, config_version, 0) != 0) { net_instance->schedule_disconnect = 1; net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; } } return (0); } /* * Called when cmap reload (or nodelist) was requested, but it was not possible to * get node list. * * Should return 0 if processing should continue or -1 to call exit */ int qdevice_model_net_get_config_node_list_failed(struct qdevice_instance *instance) { struct qdevice_net_instance *net_instance; net_instance = instance->model_data; net_instance->schedule_disconnect = 1; net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (0); } int qdevice_model_net_votequorum_quorum_notify(struct qdevice_instance *instance, uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[]) { struct qdevice_net_instance *net_instance; int send_node_list; enum tlv_vote vote; net_instance = instance->model_data; if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { /* * Nodelist changed, but connection to qnetd not initiated yet. */ send_node_list = 0; if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } else { vote = TLV_VOTE_NO_CHANGE; } } else { send_node_list = 1; vote = TLV_VOTE_NO_CHANGE; } if (qdevice_net_algorithm_votequorum_quorum_notify(net_instance, quorate, node_list_entries, node_list, &send_node_list, &vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_QUORUM_NOTIFY_ERR; net_instance->schedule_disconnect = 1; } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s list and result vote is %s", (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_quorum_notify fatal error. " " Can't update cast vote timer vote"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; } if (send_node_list) { if (qdevice_net_send_quorum_node_list(net_instance, (quorate ? TLV_QUORATE_QUORATE : TLV_QUORATE_INQUORATE), node_list_entries, node_list) != 0) { /* * Fatal error -> schedule disconnect */ net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; net_instance->schedule_disconnect = 1; } } return (0); } int qdevice_model_net_votequorum_node_list_notify(struct qdevice_instance *instance, votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[]) { struct qdevice_net_instance *net_instance; struct tlv_ring_id tlv_rid; enum tlv_vote vote; int send_node_list; net_instance = instance->model_data; qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id); if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { /* * Nodelist changed, but connection to qnetd not initiated yet. */ send_node_list = 0; if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) { vote = TLV_VOTE_NACK; } else { vote = TLV_VOTE_NO_CHANGE; } } else { send_node_list = 1; vote = TLV_VOTE_NO_CHANGE; } if (qdevice_net_algorithm_votequorum_node_list_notify(net_instance, &tlv_rid, node_list_entries, node_list, &send_node_list, &vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_NOTIFY_ERR; net_instance->schedule_disconnect = 1; } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s list and result vote is %s", (send_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } if (send_node_list) { if (qdevice_net_send_membership_node_list(net_instance, &tlv_rid, node_list_entries, node_list) != 0) { /* * Fatal error -> schedule disconnect */ net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; net_instance->schedule_disconnect = 1; } } if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error " "Can't update cast vote timer"); net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; net_instance->schedule_disconnect = 1; } return (0); } int qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance, uint32_t expected_votes) { struct qdevice_net_instance *net_instance; net_instance = instance->model_data; qdevice_log(LOG_DEBUG, "qdevice_model_net_votequorum_expected_votes_notify" " (expected votes old=%"PRIu32" / new=%"PRIu32")", net_instance->qdevice_instance_ptr->vq_expected_votes, expected_votes); return (0); } int qdevice_model_net_ipc_cmd_status(struct qdevice_instance *instance, struct dynar *outbuf, int verbose) { struct qdevice_net_instance *net_instance; net_instance = instance->model_data; if (!qdevice_net_ipc_cmd_status(net_instance, outbuf, verbose)) { return (-1); } return (0); } static struct qdevice_model qdevice_model_net = { .name = "net", .init = qdevice_model_net_init, .destroy = qdevice_model_net_destroy, .run = qdevice_model_net_run, .get_config_node_list_failed = qdevice_model_net_get_config_node_list_failed, .config_node_list_changed = qdevice_model_net_config_node_list_changed, .votequorum_quorum_notify = qdevice_model_net_votequorum_quorum_notify, .votequorum_node_list_notify = qdevice_model_net_votequorum_node_list_notify, .votequorum_expected_votes_notify = qdevice_model_net_votequorum_expected_votes_notify, .ipc_cmd_status = qdevice_model_net_ipc_cmd_status, }; int qdevice_model_net_register(void) { return (qdevice_model_register(QDEVICE_MODEL_TYPE_NET, &qdevice_model_net)); } diff --git a/qdevices/qdevice-net-instance.c b/qdevices/qdevice-net-instance.c index d89218b8..13ff4581 100644 --- a/qdevices/qdevice-net-instance.c +++ b/qdevices/qdevice-net-instance.c @@ -1,394 +1,398 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-config.h" #include "qdevice-log.h" #include "qdevice-net-instance.h" #include "qnet-config.h" #include "utils.h" #include "qdevice-net-poll-array-user-data.h" #include "qdevice-ipc.h" /* * Needed for creating nspr handle from unix fd */ #include int -qdevice_net_instance_init(struct qdevice_net_instance *instance, size_t initial_receive_size, - size_t initial_send_size, size_t min_send_size, size_t max_send_buffers, - size_t max_receive_size, +qdevice_net_instance_init(struct qdevice_net_instance *instance, enum tlv_tls_supported tls_supported, enum tlv_decision_algorithm_type decision_algorithm, uint32_t heartbeat_interval, uint32_t sync_heartbeat_interval, uint32_t cast_vote_timer_interval, const char *host_addr, uint16_t host_port, const char *cluster_name, const struct tlv_tie_breaker *tie_breaker, uint32_t connect_timeout, - int force_ip_version, int cmap_fd, int votequorum_fd, int local_socket_fd) + int force_ip_version, int cmap_fd, int votequorum_fd, int local_socket_fd, + const struct qdevice_advanced_settings *advanced_settings) { memset(instance, 0, sizeof(*instance)); - instance->initial_receive_size = initial_receive_size; - instance->initial_send_size = initial_send_size; - instance->min_send_size = min_send_size; - instance->max_receive_size = max_receive_size; + instance->advanced_settings = advanced_settings; instance->decision_algorithm = decision_algorithm; instance->heartbeat_interval = heartbeat_interval; instance->sync_heartbeat_interval = sync_heartbeat_interval; instance->cast_vote_timer_interval = cast_vote_timer_interval; instance->cast_vote_timer = NULL; instance->host_addr = host_addr; instance->host_port = host_port; instance->cluster_name = cluster_name; instance->connect_timeout = connect_timeout; instance->last_msg_seq_num = 1; instance->echo_request_expected_msg_seq_num = 1; instance->echo_reply_received_msg_seq_num = 1; instance->force_ip_version = force_ip_version; instance->last_echo_reply_received_time = ((time_t) -1); instance->connected_since_time = ((time_t) -1); memcpy(&instance->tie_breaker, tie_breaker, sizeof(*tie_breaker)); - dynar_init(&instance->receive_buffer, initial_receive_size); + dynar_init(&instance->receive_buffer, advanced_settings->net_initial_msg_receive_size); - send_buffer_list_init(&instance->send_buffer_list, max_send_buffers, - initial_send_size); + send_buffer_list_init(&instance->send_buffer_list, advanced_settings->net_max_send_buffers, + advanced_settings->net_initial_msg_send_size); timer_list_init(&instance->main_timer_list); pr_poll_array_init(&instance->poll_array, sizeof(struct qdevice_net_poll_array_user_data)); instance->tls_supported = tls_supported; if ((instance->cmap_poll_fd = PR_CreateSocketPollFd(cmap_fd)) == NULL) { qdevice_log_nss(LOG_CRIT, "Can't create NSPR cmap poll fd"); return (-1); } if ((instance->votequorum_poll_fd = PR_CreateSocketPollFd(votequorum_fd)) == NULL) { qdevice_log_nss(LOG_CRIT, "Can't create NSPR votequorum poll fd"); return (-1); } if ((instance->ipc_socket_poll_fd = PR_CreateSocketPollFd(local_socket_fd)) == NULL) { qdevice_log_nss(LOG_CRIT, "Can't create NSPR IPC socket poll fd"); return (-1); } return (0); } void qdevice_net_instance_clean(struct qdevice_net_instance *instance) { dynar_clean(&instance->receive_buffer); send_buffer_list_free(&instance->send_buffer_list); instance->skipping_msg = 0; instance->msg_already_received_bytes = 0; instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_PREINIT_REPLY; instance->echo_request_expected_msg_seq_num = instance->echo_reply_received_msg_seq_num; instance->using_tls = 0; instance->tls_client_cert_sent = 0; instance->schedule_disconnect = 0; instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNDEFINED; instance->last_echo_reply_received_time = ((time_t) -1); instance->connected_since_time = ((time_t) -1); } int qdevice_net_instance_destroy(struct qdevice_net_instance *instance) { struct unix_socket_client *ipc_client; const struct unix_socket_client_list *ipc_client_list; struct qdevice_ipc_user_data *qdevice_ipc_user_data; PRFileDesc *prfd; ipc_client_list = &instance->qdevice_instance_ptr->local_ipc.clients; TAILQ_FOREACH(ipc_client, ipc_client_list, entries) { qdevice_ipc_user_data = (struct qdevice_ipc_user_data *)ipc_client->user_data; prfd = (PRFileDesc *)qdevice_ipc_user_data->model_data; if (PR_DestroySocketPollFd(prfd) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to destroy client IPC poll socket fd"); } } dynar_destroy(&instance->receive_buffer); send_buffer_list_free(&instance->send_buffer_list); pr_poll_array_destroy(&instance->poll_array); timer_list_free(&instance->main_timer_list); free((void *)instance->cluster_name); free((void *)instance->host_addr); if (PR_DestroySocketPollFd(instance->votequorum_poll_fd) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close votequorum connection fd"); } if (PR_DestroySocketPollFd(instance->cmap_poll_fd) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close votequorum connection fd"); } if (PR_DestroySocketPollFd(instance->ipc_socket_poll_fd) != PR_SUCCESS) { qdevice_log_nss(LOG_WARNING, "Unable to close local socket poll fd"); } return (0); } int qdevice_net_instance_init_from_cmap(struct qdevice_instance *instance) { char *str; cmap_handle_t cmap_handle; enum tlv_tls_supported tls_supported; int i; long int li; enum tlv_decision_algorithm_type decision_algorithm; struct tlv_tie_breaker tie_breaker; uint32_t heartbeat_interval; uint32_t sync_heartbeat_interval; uint32_t cast_vote_timer_interval; char *host_addr; int host_port; char *ep; char *cluster_name; uint32_t connect_timeout; struct qdevice_net_instance *net_instance; int force_ip_version; cmap_handle = instance->cmap_handle; net_instance = malloc(sizeof(*net_instance)); if (net_instance == NULL) { qdevice_log(LOG_ERR, "Can't alloc qdevice_net_instance"); return (-1); } /* * Check tls */ tls_supported = QDEVICE_NET_DEFAULT_TLS_SUPPORTED; if (cmap_get_string(cmap_handle, "quorum.device.net.tls", &str) == CS_OK) { if ((i = utils_parse_bool_str(str)) == -1) { if (strcasecmp(str, "required") != 0) { free(str); qdevice_log(LOG_ERR, "quorum.device.net.tls value is not valid."); goto error_free_instance; } else { tls_supported = TLV_TLS_REQUIRED; } } else { if (i == 1) { tls_supported = TLV_TLS_SUPPORTED; } else { tls_supported = TLV_TLS_UNSUPPORTED; } } free(str); } /* * Host */ if (cmap_get_string(cmap_handle, "quorum.device.net.host", &str) != CS_OK) { qdevice_log(LOG_ERR, "Qdevice net daemon address is not defined (quorum.device.net.host)"); goto error_free_instance; } host_addr = str; if (cmap_get_string(cmap_handle, "quorum.device.net.port", &str) == CS_OK) { host_port = strtol(str, &ep, 10); free(str); if (host_port <= 0 || host_port > ((uint16_t)~0) || *ep != '\0') { qdevice_log(LOG_ERR, "quorum.device.net.port must be in range 0-65535"); goto error_free_host_addr; } } else { host_port = QNETD_DEFAULT_HOST_PORT; } /* * Cluster name */ if (cmap_get_string(cmap_handle, "totem.cluster_name", &str) != CS_OK) { qdevice_log(LOG_ERR, "Cluster name (totem.cluster_name) has to be defined."); goto error_free_host_addr; } cluster_name = str; /* * Adjust qdevice timeouts to better suit qnetd */ cast_vote_timer_interval = instance->heartbeat_interval * 0.5; heartbeat_interval = instance->heartbeat_interval * 0.8; - if (heartbeat_interval < QDEVICE_NET_HEARTBEAT_INTERVAL_MIN) { + if (heartbeat_interval < instance->advanced_settings->net_heartbeat_interval_min) { qdevice_log(LOG_WARNING, "Heartbeat interval too small %"PRIu32". Adjusting to %"PRIu32".", - heartbeat_interval, QDEVICE_NET_HEARTBEAT_INTERVAL_MIN); - heartbeat_interval = QDEVICE_NET_HEARTBEAT_INTERVAL_MIN; + heartbeat_interval, instance->advanced_settings->net_heartbeat_interval_min); + heartbeat_interval = instance->advanced_settings->net_heartbeat_interval_min; } - if (heartbeat_interval > QDEVICE_NET_HEARTBEAT_INTERVAL_MAX) { + if (heartbeat_interval > instance->advanced_settings->net_heartbeat_interval_max) { qdevice_log(LOG_WARNING, "Heartbeat interval too big %"PRIu32". Adjusting to %"PRIu32".", - heartbeat_interval, QDEVICE_NET_HEARTBEAT_INTERVAL_MAX); - heartbeat_interval = QDEVICE_NET_HEARTBEAT_INTERVAL_MAX; + heartbeat_interval, instance->advanced_settings->net_heartbeat_interval_max); + heartbeat_interval = instance->advanced_settings->net_heartbeat_interval_max; } sync_heartbeat_interval = instance->sync_heartbeat_interval * 0.8; /* * Choose decision algorithm */ if (cmap_get_string(cmap_handle, "quorum.device.net.algorithm", &str) != CS_OK) { decision_algorithm = QDEVICE_NET_DEFAULT_ALGORITHM; } else { if (strcmp(str, "test") == 0) { decision_algorithm = TLV_DECISION_ALGORITHM_TYPE_TEST; } else if (strcmp(str, "ffsplit") == 0) { decision_algorithm = TLV_DECISION_ALGORITHM_TYPE_FFSPLIT; } else if (strcmp(str, "2nodelms") == 0) { decision_algorithm = TLV_DECISION_ALGORITHM_TYPE_2NODELMS; } else if (strcmp(str, "lms") == 0) { decision_algorithm = TLV_DECISION_ALGORITHM_TYPE_LMS; } else { qdevice_log(LOG_ERR, "Unknown decision algorithm %s", str); free(str); goto error_free_cluster_name; } free(str); } + if (decision_algorithm == TLV_DECISION_ALGORITHM_TYPE_TEST && + !instance->advanced_settings->net_test_algorithm_enabled) { + qdevice_log(LOG_ERR, "Test algorithm is not enabled. You can force enable it by " + "passing -S net_test_algorithm_enabled=on to %s command", QDEVICE_PROGRAM_NAME); + + goto error_free_cluster_name; + } /* * Load tie_breaker mode */ memset(&tie_breaker, 0, sizeof(tie_breaker)); if (cmap_get_string(cmap_handle, "quorum.device.net.tie_breaker", &str) != CS_OK) { tie_breaker.mode = QDEVICE_NET_DEFAULT_TIE_BREAKER_MODE; } else { if (strcmp(str, "lowest") == 0) { tie_breaker.mode = TLV_TIE_BREAKER_MODE_LOWEST; } else if (strcmp(str, "highest") == 0) { tie_breaker.mode = TLV_TIE_BREAKER_MODE_HIGHEST; } else { li = strtol(str, &ep, 10); if (li <= 0 || li > ((uint32_t)~0) || *ep != '\0') { qdevice_log(LOG_ERR, "tie_breaker must be lowest|highest|valid_node_id"); free(str); goto error_free_cluster_name; } tie_breaker.mode = TLV_TIE_BREAKER_MODE_NODE_ID; tie_breaker.node_id = li; } free(str); } /* * Get connect timeout */ if (cmap_get_string(cmap_handle, "quorum.device.net.connect_timeout", &str) != CS_OK) { connect_timeout = heartbeat_interval; } else { li = strtol(str, &ep, 10); - if (li < QDEVICE_NET_MIN_CONNECT_TIMEOUT || li > QDEVICE_NET_MAX_CONNECT_TIMEOUT || *ep != '\0') { - qdevice_log(LOG_ERR, "connect_timeout must be valid number in range <%lu,%lu>", - QDEVICE_NET_MIN_CONNECT_TIMEOUT, QDEVICE_NET_MAX_CONNECT_TIMEOUT); + if (li < instance->advanced_settings->net_min_connect_timeout || + li > instance->advanced_settings->net_max_connect_timeout || *ep != '\0') { + qdevice_log(LOG_ERR, "connect_timeout must be valid number in " + "range <%"PRIu32",%"PRIu32">", + instance->advanced_settings->net_min_connect_timeout, + instance->advanced_settings->net_max_connect_timeout); free(str); goto error_free_cluster_name; } connect_timeout = li; free(str); } if (cmap_get_string(cmap_handle, "quorum.device.net.force_ip_version", &str) != CS_OK) { force_ip_version = 0; } else { li = strtol(str, &ep, 10); if ((li != 0 && li != 4 && li != 6) || *ep != '\0') { qdevice_log(LOG_ERR, "force_ip_version must be one of 0|4|6"); free(str); goto error_free_cluster_name; } force_ip_version = li; free(str); } /* * Really initialize instance */ if (qdevice_net_instance_init(net_instance, - QDEVICE_NET_INITIAL_MSG_RECEIVE_SIZE, QDEVICE_NET_INITIAL_MSG_SEND_SIZE, - QDEVICE_NET_MIN_MSG_SEND_SIZE, QDEVICE_NET_MAX_SEND_BUFFERS, - QDEVICE_NET_MAX_MSG_RECEIVE_SIZE, tls_supported, decision_algorithm, heartbeat_interval, sync_heartbeat_interval, cast_vote_timer_interval, host_addr, host_port, cluster_name, &tie_breaker, connect_timeout, force_ip_version, instance->cmap_poll_fd, instance->votequorum_poll_fd, - instance->local_ipc.socket) == -1) { + instance->local_ipc.socket, instance->advanced_settings) == -1) { qdevice_log(LOG_ERR, "Can't initialize qdevice-net instance"); goto error_free_instance; } net_instance->qdevice_instance_ptr = instance; instance->model_data = net_instance; return (0); error_free_cluster_name: free(cluster_name); error_free_host_addr: free(host_addr); error_free_instance: free(net_instance); return (-1); } diff --git a/qdevices/qdevice-net-instance.h b/qdevices/qdevice-net-instance.h index 53db97c1..5cb44493 100644 --- a/qdevices/qdevice-net-instance.h +++ b/qdevices/qdevice-net-instance.h @@ -1,134 +1,130 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 _QDEVICE_NET_INSTANCE_H_ #define _QDEVICE_NET_INSTANCE_H_ #include #include #include #include "nss-sock.h" #include "qdevice-instance.h" #include "dynar.h" #include "node-list.h" #include "pr-poll-array.h" #include "qdevice-net-disconnect-reason.h" #include "send-buffer-list.h" #include "tlv.h" #include "timer-list.h" #ifdef __cplusplus extern "C" { #endif enum qdevice_net_instance_state { QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT, QDEVICE_NET_INSTANCE_STATE_SENDING_PREINIT_REPLY, QDEVICE_NET_INSTANCE_STATE_WAITING_PREINIT_REPLY, QDEVICE_NET_INSTANCE_STATE_WAITING_STARTTLS_BEING_SENT, QDEVICE_NET_INSTANCE_STATE_WAITING_INIT_REPLY, QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS, }; struct qdevice_net_instance { PRFileDesc *socket; - size_t initial_send_size; - size_t initial_receive_size; - size_t max_receive_size; - size_t min_send_size; struct dynar receive_buffer; struct send_buffer_list send_buffer_list; int skipping_msg; size_t msg_already_received_bytes; enum qdevice_net_instance_state state; uint32_t last_msg_seq_num; uint32_t echo_request_expected_msg_seq_num; uint32_t echo_reply_received_msg_seq_num; enum tlv_tls_supported tls_supported; int using_tls; int tls_client_cert_sent; uint32_t heartbeat_interval; /* Adjusted heartbeat interval during normal operation */ uint32_t sync_heartbeat_interval; /* Adjusted heartbeat interval during corosync sync */ uint32_t cast_vote_timer_interval; /* Timer for cast vote */ uint32_t connect_timeout; struct timer_list_entry *cast_vote_timer; enum tlv_vote cast_vote_timer_vote; const char *host_addr; uint16_t host_port; const char *cluster_name; enum tlv_decision_algorithm_type decision_algorithm; struct timer_list main_timer_list; struct timer_list_entry *echo_request_timer; int schedule_disconnect; PRFileDesc *votequorum_poll_fd; PRFileDesc *cmap_poll_fd; PRFileDesc *ipc_socket_poll_fd; struct tlv_ring_id last_sent_ring_id; struct tlv_tie_breaker tie_breaker; void *algorithm_data; enum qdevice_net_disconnect_reason disconnect_reason; struct qdevice_instance *qdevice_instance_ptr; struct nss_sock_non_blocking_client non_blocking_client; struct timer_list_entry *connect_timer; int force_ip_version; struct pr_poll_array poll_array; time_t last_echo_reply_received_time; time_t connected_since_time; + const struct qdevice_advanced_settings *advanced_settings; }; extern int qdevice_net_instance_init(struct qdevice_net_instance *instance, - size_t initial_receive_size, size_t initial_send_size, size_t min_send_size, - size_t max_send_buffers, size_t max_receive_size, enum tlv_tls_supported tls_supported, enum tlv_decision_algorithm_type decision_algorithm, uint32_t heartbeat_interval, uint32_t sync_heartbeat_interval, uint32_t cast_vote_timer_interval, const char *host_addr, uint16_t host_port, const char *cluster_name, const struct tlv_tie_breaker *tie_breaker, uint32_t connect_timeout, int force_ip_version, - int cmap_fd, int votequorum_fd, int local_socket_fd); + int cmap_fd, int votequorum_fd, int local_socket_fd, + const struct qdevice_advanced_settings *advanced_settings); extern void qdevice_net_instance_clean(struct qdevice_net_instance *instance); extern int qdevice_net_instance_destroy(struct qdevice_net_instance *instance); extern int qdevice_net_instance_init_from_cmap(struct qdevice_instance *instance); #ifdef __cplusplus } #endif #endif /* _QDEVICE_NET_INSTANCE_H_ */ diff --git a/qdevices/qdevice-net-msg-received.c b/qdevices/qdevice-net-msg-received.c index b20134b8..d66d2693 100644 --- a/qdevices/qdevice-net-msg-received.c +++ b/qdevices/qdevice-net-msg-received.c @@ -1,904 +1,906 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-log.h" #include "qdevice-net-algorithm.h" #include "qdevice-net-cast-vote-timer.h" #include "qdevice-net-msg-received.h" #include "qdevice-net-send.h" #include "qdevice-net-votequorum.h" #include "qdevice-net-echo-request-timer.h" #include "msg.h" #include "utils.h" /* * -1 - Incompatible tls combination * 0 - Don't use TLS * 1 - Use TLS */ static int qdevice_net_msg_received_check_tls_compatibility(enum tlv_tls_supported server_tls, enum tlv_tls_supported client_tls) { int res; res = -1; switch (server_tls) { case TLV_TLS_UNSUPPORTED: switch (client_tls) { case TLV_TLS_UNSUPPORTED: res = 0; break; case TLV_TLS_SUPPORTED: res = 0; break; case TLV_TLS_REQUIRED: res = -1; break; } break; case TLV_TLS_SUPPORTED: switch (client_tls) { case TLV_TLS_UNSUPPORTED: res = 0; break; case TLV_TLS_SUPPORTED: res = 1; break; case TLV_TLS_REQUIRED: res = 1; break; } break; case TLV_TLS_REQUIRED: switch (client_tls) { case TLV_TLS_UNSUPPORTED: res = -1; break; case TLV_TLS_SUPPORTED: res = 1; break; case TLV_TLS_REQUIRED: res = 1; break; } break; } return (res); } static void qdevice_net_msg_received_log_msg_decode_error(int ret) { switch (ret) { case -1: qdevice_log(LOG_WARNING, "Received message with option with invalid length"); break; case -2: qdevice_log(LOG_CRIT, "Can't allocate memory"); break; case -3: qdevice_log(LOG_WARNING, "Received inconsistent msg (tlv len > msg size)"); break; case -4: qdevice_log(LOG_ERR, "Received message with option with invalid value"); break; default: qdevice_log(LOG_ERR, "Unknown error occured when decoding message"); break; } } static int qdevice_net_msg_received_unexpected_msg(struct qdevice_net_instance *instance, const struct msg_decoded *msg, const char *msg_str) { qdevice_log(LOG_ERR, "Received unexpected %s message. Disconnecting from server", msg_str); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } static int qdevice_net_msg_received_init(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "init")); } static int qdevice_net_msg_received_preinit(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "preinit")); } static int qdevice_net_msg_check_seq_number(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { if (!msg->seq_number_set || msg->seq_number != instance->last_msg_seq_num) { qdevice_log(LOG_ERR, "Received message doesn't contain seq_number or " "it's not expected one."); return (-1); } return (0); } static int qdevice_net_msg_received_preinit_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { int res; struct send_buffer_list_entry *send_buffer; qdevice_log(LOG_DEBUG, "Received preinit reply msg"); if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_PREINIT_REPLY) { qdevice_log(LOG_ERR, "Received unexpected preinit reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } /* * Check TLS support */ if (!msg->tls_supported_set || !msg->tls_client_cert_required_set) { qdevice_log(LOG_ERR, "Required tls_supported or tls_client_cert_required " "option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } res = qdevice_net_msg_received_check_tls_compatibility(msg->tls_supported, instance->tls_supported); if (res == -1) { qdevice_log(LOG_ERR, "Incompatible tls configuration (server %u client %u)", msg->tls_supported, instance->tls_supported); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_TLS; return (-1); } else if (res == 1) { /* * Start TLS */ send_buffer = send_buffer_list_get_new(&instance->send_buffer_list); if (send_buffer == NULL) { qdevice_log(LOG_ERR, "Can't allocate send list buffer for " "starttls msg"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } instance->last_msg_seq_num++; if (msg_create_starttls(&send_buffer->buffer, 1, instance->last_msg_seq_num) == 0) { qdevice_log(LOG_ERR, "Can't allocate send buffer for starttls msg"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; send_buffer_list_discard_new(&instance->send_buffer_list, send_buffer); return (-1); } send_buffer_list_put(&instance->send_buffer_list, send_buffer); instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_STARTTLS_BEING_SENT; } else if (res == 0) { if (qdevice_net_send_init(instance) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } return (0); } static int qdevice_net_msg_received_init_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { size_t zi; int res; int send_config_node_list; int send_membership_node_list; int send_quorum_node_list; enum tlv_vote vote; struct tlv_ring_id tlv_rid; enum tlv_quorate quorate; qdevice_log(LOG_DEBUG, "Received init reply msg"); if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_INIT_REPLY) { qdevice_log(LOG_ERR, "Received unexpected init reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (!msg->reply_error_code_set) { qdevice_log(LOG_ERR, "Received init reply message without error code." "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->reply_error_code != TLV_REPLY_ERROR_CODE_NO_ERROR) { qdevice_log(LOG_ERR, "Received init reply message with error code %"PRIu16". " "Disconnecting from server", msg->reply_error_code); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ERROR; return (-1); } if (!msg->server_maximum_request_size_set || !msg->server_maximum_reply_size_set) { qdevice_log(LOG_ERR, "Required maximum_request_size or maximum_reply_size " "option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->supported_messages == NULL || msg->supported_options == NULL) { qdevice_log(LOG_ERR, "Required supported messages or supported options " "option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->supported_decision_algorithms == NULL) { qdevice_log(LOG_ERR, "Required supported decision algorithms option is unset"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } - if (msg->server_maximum_request_size < instance->min_send_size) { + if (msg->server_maximum_request_size < instance->advanced_settings->net_min_msg_send_size) { qdevice_log(LOG_ERR, "Server accepts maximum %zu bytes message but this client minimum " - "is %zu bytes.", msg->server_maximum_request_size, instance->min_send_size); + "is %zu bytes.", msg->server_maximum_request_size, + instance->advanced_settings->net_min_msg_send_size); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_MSG_SIZE; return (-1); } - if (msg->server_maximum_reply_size > instance->max_receive_size) { + if (msg->server_maximum_reply_size > instance->advanced_settings->net_max_msg_receive_size) { qdevice_log(LOG_ERR, "Server may send message up to %zu bytes message but this client maximum " - "is %zu bytes.", msg->server_maximum_reply_size, instance->max_receive_size); + "is %zu bytes.", msg->server_maximum_reply_size, + instance->advanced_settings->net_max_msg_receive_size); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_MSG_SIZE; return (-1); } /* * Change buffer sizes */ dynar_set_max_size(&instance->receive_buffer, msg->server_maximum_reply_size); send_buffer_list_set_max_buffer_size(&instance->send_buffer_list, msg->server_maximum_request_size); /* * Check if server supports decision algorithm we need */ res = 0; for (zi = 0; zi < msg->no_supported_decision_algorithms && !res; zi++) { if (msg->supported_decision_algorithms[zi] == instance->decision_algorithm) { res = 1; } } if (!res) { qdevice_log(LOG_ERR, "Server doesn't support required decision algorithm"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_DOESNT_SUPPORT_REQUIRED_ALGORITHM; return (-1); } /* * Finally fully connected so it's possible to remove connection timer */ if (instance->connect_timer != NULL) { timer_list_delete(&instance->main_timer_list, instance->connect_timer); instance->connect_timer = NULL; } /* * Server accepted heartbeat interval -> schedule regular sending of echo request */ qdevice_net_echo_request_timer_schedule(instance); send_config_node_list = 1; send_membership_node_list = 1; send_quorum_node_list = 1; vote = TLV_VOTE_WAIT_FOR_REPLY; if (qdevice_net_algorithm_connected(instance, &send_config_node_list, &send_membership_node_list, &send_quorum_node_list, &vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_CONNECTED_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm decided to %s config node list, %s membership " "node list, %s quorum node list and result vote is %s", (send_config_node_list ? "send" : "not send"), (send_membership_node_list ? "send" : "not send"), (send_quorum_node_list ? "send" : "not send"), tlv_vote_to_str(vote)); } /* * Now we can finally really send node list, votequorum node list and update timer */ if (send_config_node_list) { if (qdevice_net_send_config_node_list(instance, &instance->qdevice_instance_ptr->config_node_list, instance->qdevice_instance_ptr->config_node_list_version_set, instance->qdevice_instance_ptr->config_node_list_version, 1) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } if (send_membership_node_list) { qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &instance->qdevice_instance_ptr->vq_node_list_ring_id); if (qdevice_net_send_membership_node_list(instance, &tlv_rid, instance->qdevice_instance_ptr->vq_node_list_entries, instance->qdevice_instance_ptr->vq_node_list) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } if (send_quorum_node_list) { quorate = (instance->qdevice_instance_ptr->vq_quorum_quorate ? TLV_QUORATE_QUORATE : TLV_QUORATE_INQUORATE); if (qdevice_net_send_quorum_node_list(instance, quorate, instance->qdevice_instance_ptr->vq_quorum_node_list_entries, instance->qdevice_instance_ptr->vq_quorum_node_list) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } } if (qdevice_net_cast_vote_timer_update(instance, vote) != 0) { qdevice_log(LOG_CRIT, "qdevice_net_msg_received_set_option_reply fatal error. " " Can't update cast vote timer vote"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; } instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS; instance->connected_since_time = time(NULL); return (0); } static int qdevice_net_msg_received_starttls(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "starttls")); } static int qdevice_net_msg_received_server_error(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { if (!msg->reply_error_code_set) { qdevice_log(LOG_ERR, "Received server error without error code set. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; } else { qdevice_log(LOG_ERR, "Received server error %"PRIu16". " "Disconnecting from server", msg->reply_error_code); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ERROR; } return (-1); } static int qdevice_net_msg_received_set_option(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "set option")); } static int qdevice_net_msg_received_set_option_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected set option reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } qdevice_net_echo_request_timer_schedule(instance); return (0); } static int qdevice_net_msg_received_echo_request(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "echo request")); } static int qdevice_net_msg_received_echo_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { if (!msg->seq_number_set) { qdevice_log(LOG_ERR, "Received echo reply message doesn't contain seq_number."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->seq_number != instance->echo_request_expected_msg_seq_num) { qdevice_log(LOG_WARNING, "Received echo reply message seq_number is not expected one."); } if (qdevice_net_algorithm_echo_reply_received(instance, msg->seq_number, msg->seq_number == instance->echo_request_expected_msg_seq_num) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_ECHO_REPLY_RECEIVED_ERR; return (-1); } instance->echo_reply_received_msg_seq_num = msg->seq_number; instance->last_echo_reply_received_time = time(NULL); return (0); } static int qdevice_net_msg_received_node_list(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "node list")); } static int qdevice_net_msg_received_node_list_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { const char *str; enum tlv_vote result_vote; int res; int case_processed; if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected node list reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (!msg->vote_set || !msg->seq_number_set || !msg->node_list_type_set) { qdevice_log(LOG_ERR, "Received node list reply message without " "required options. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } if (msg->node_list_type == TLV_NODE_LIST_TYPE_MEMBERSHIP && !msg->ring_id_set) { qdevice_log(LOG_ERR, "Received node list reply message with type membership " "without ring id set. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } str = NULL; switch (msg->node_list_type) { case TLV_NODE_LIST_TYPE_INITIAL_CONFIG: str = "initial config"; break; case TLV_NODE_LIST_TYPE_CHANGED_CONFIG: str = "changed config"; break; case TLV_NODE_LIST_TYPE_MEMBERSHIP: str ="membership"; break; case TLV_NODE_LIST_TYPE_QUORUM: str ="quorum"; break; /* * Default is not defined intentionally. Compiler shows warning when new node list type * is added */ } if (str == NULL) { qdevice_log(LOG_CRIT, "qdevice_net_msg_received_node_list_reply fatal error. " "Unhandled node_list_type (debug output)"); exit(1); } qdevice_log(LOG_DEBUG, "Received %s node list reply", str); qdevice_log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); qdevice_log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); if (msg->ring_id_set) { qdevice_log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", msg->ring_id.node_id, msg->ring_id.seq); } /* * Call algorithm */ result_vote = msg->vote; case_processed = 0; switch (msg->node_list_type) { case TLV_NODE_LIST_TYPE_INITIAL_CONFIG: case TLV_NODE_LIST_TYPE_CHANGED_CONFIG: case_processed = 1; res = qdevice_net_algorithm_config_node_list_reply_received(instance, msg->seq_number, (msg->node_list_type == TLV_NODE_LIST_TYPE_INITIAL_CONFIG), &result_vote); break; case TLV_NODE_LIST_TYPE_MEMBERSHIP: case_processed = 1; res = qdevice_net_algorithm_membership_node_list_reply_received(instance, msg->seq_number, &msg->ring_id, &result_vote); break; case TLV_NODE_LIST_TYPE_QUORUM: case_processed = 1; res = qdevice_net_algorithm_quorum_node_list_reply_received(instance, msg->seq_number, &result_vote); break; /* * Default is not defined intentionally. Compiler shows warning when new node list type * is added */ } if (!case_processed) { qdevice_log(LOG_CRIT, "qdevice_net_msg_received_node_list_reply fatal error. " "Unhandled node_list_type (algorithm call)"); exit(1); } if (res != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_NODE_LIST_REPLY_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(msg->vote)); } if (result_vote != TLV_VOTE_NO_CHANGE) { if (msg->node_list_type == TLV_NODE_LIST_TYPE_MEMBERSHIP && !tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { qdevice_log(LOG_INFO, "Received membership node list reply with " "old ring id. Not updating timer"); } else { if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; return (-1); } } } return (0); } static int qdevice_net_msg_received_ask_for_vote(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "ask for vote")); } static int qdevice_net_msg_received_ask_for_vote_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { enum tlv_vote result_vote; if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected ask for vote reply message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (!msg->vote_set || !msg->seq_number_set) { qdevice_log(LOG_ERR, "Received node list reply message without " "required options. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } qdevice_log(LOG_DEBUG, "Received ask for vote reply"); qdevice_log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); qdevice_log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); result_vote = msg->vote; if (qdevice_net_algorithm_ask_for_vote_reply_received(instance, msg->seq_number, &result_vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_ASK_FOR_VOTE_REPLY_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(msg->vote)); } if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; return (-1); } return (0); } static int qdevice_net_msg_received_vote_info(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { struct send_buffer_list_entry *send_buffer; enum tlv_vote result_vote; if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { qdevice_log(LOG_ERR, "Received unexpected vote info message. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; return (-1); } if (!msg->vote_set || !msg->seq_number_set) { qdevice_log(LOG_ERR, "Received node list reply message without " "required options. Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; return (-1); } qdevice_log(LOG_DEBUG, "Received vote info"); qdevice_log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); qdevice_log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); result_vote = msg->vote; if (qdevice_net_algorithm_vote_info_received(instance, msg->seq_number, &result_vote) != 0) { qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTE_INFO_ERR; return (-1); } else { qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); } if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; return (-1); } /* * Create reply message */ send_buffer = send_buffer_list_get_new(&instance->send_buffer_list); if (send_buffer == NULL) { qdevice_log(LOG_ERR, "Can't allocate send list buffer for " "vote info reply msg"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } if (msg_create_vote_info_reply(&send_buffer->buffer, msg->seq_number) == 0) { qdevice_log(LOG_ERR, "Can't allocate send buffer for " "vote info reply list msg"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; send_buffer_list_discard_new(&instance->send_buffer_list, send_buffer); return (-1); } send_buffer_list_put(&instance->send_buffer_list, send_buffer); return (0); } static int qdevice_net_msg_received_vote_info_reply(struct qdevice_net_instance *instance, const struct msg_decoded *msg) { return (qdevice_net_msg_received_unexpected_msg(instance, msg, "vote info reply")); } int qdevice_net_msg_received(struct qdevice_net_instance *instance) { struct msg_decoded msg; int res; int ret_val; int msg_processed; msg_decoded_init(&msg); res = msg_decode(&instance->receive_buffer, &msg); if (res != 0) { /* * Error occurred. Disconnect. */ qdevice_net_msg_received_log_msg_decode_error(res); qdevice_log(LOG_ERR, "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_MSG_DECODE_ERROR; return (-1); } ret_val = 0; msg_processed = 0; switch (msg.type) { case MSG_TYPE_INIT: msg_processed = 1; ret_val = qdevice_net_msg_received_init(instance, &msg); break; case MSG_TYPE_PREINIT: msg_processed = 1; ret_val = qdevice_net_msg_received_preinit(instance, &msg); break; case MSG_TYPE_PREINIT_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_preinit_reply(instance, &msg); break; case MSG_TYPE_STARTTLS: msg_processed = 1; ret_val = qdevice_net_msg_received_starttls(instance, &msg); break; case MSG_TYPE_SERVER_ERROR: msg_processed = 1; ret_val = qdevice_net_msg_received_server_error(instance, &msg); break; case MSG_TYPE_INIT_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_init_reply(instance, &msg); break; case MSG_TYPE_SET_OPTION: msg_processed = 1; ret_val = qdevice_net_msg_received_set_option(instance, &msg); break; case MSG_TYPE_SET_OPTION_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_set_option_reply(instance, &msg); break; case MSG_TYPE_ECHO_REQUEST: msg_processed = 1; ret_val = qdevice_net_msg_received_echo_request(instance, &msg); break; case MSG_TYPE_ECHO_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_echo_reply(instance, &msg); break; case MSG_TYPE_NODE_LIST: msg_processed = 1; ret_val = qdevice_net_msg_received_node_list(instance, &msg); break; case MSG_TYPE_NODE_LIST_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_node_list_reply(instance, &msg); break; case MSG_TYPE_ASK_FOR_VOTE: msg_processed = 1; ret_val = qdevice_net_msg_received_ask_for_vote(instance, &msg); break; case MSG_TYPE_ASK_FOR_VOTE_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_ask_for_vote_reply(instance, &msg); break; case MSG_TYPE_VOTE_INFO: msg_processed = 1; ret_val = qdevice_net_msg_received_vote_info(instance, &msg); break; case MSG_TYPE_VOTE_INFO_REPLY: msg_processed = 1; ret_val = qdevice_net_msg_received_vote_info_reply(instance, &msg); break; /* * Default is not defined intentionally. Compiler shows warning when msg type is added */ } if (!msg_processed) { qdevice_log(LOG_ERR, "Received unsupported message %u. " "Disconnecting from server", msg.type); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; ret_val = -1; } msg_decoded_destroy(&msg); return (ret_val); } diff --git a/qdevices/qdevice-net-nss.c b/qdevices/qdevice-net-nss.c index b2e291fa..cf677ac6 100644 --- a/qdevices/qdevice-net-nss.c +++ b/qdevices/qdevice-net-nss.c @@ -1,74 +1,74 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-log.h" #include "qdevice-net-nss.h" #include "qdevice-net-instance.h" #include "qnet-config.h" SECStatus qdevice_net_nss_bad_cert_hook(void *arg, PRFileDesc *fd) { if (PR_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE || PR_GetError() == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE || PR_GetError() == SEC_ERROR_CRL_EXPIRED || PR_GetError() == SEC_ERROR_KRL_EXPIRED || PR_GetError() == SSL_ERROR_EXPIRED_CERT_ALERT) { qdevice_log(LOG_WARNING, "Server certificate is expired."); return (SECSuccess); } qdevice_log_nss(LOG_ERR, "Server certificate verification failure."); return (SECFailure); } SECStatus qdevice_net_nss_get_client_auth_data(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { struct qdevice_net_instance *instance; qdevice_log(LOG_DEBUG, "Sending client auth data."); instance = (struct qdevice_net_instance *)arg; instance->tls_client_cert_sent = 1; - return (NSS_GetClientAuthData((void *)QDEVICE_NET_NSS_CLIENT_CERT_NICKNAME, sock, caNames, - pRetCert, pRetKey)); + return (NSS_GetClientAuthData((void *)instance->advanced_settings->net_nss_client_cert_nickname, + sock, caNames, pRetCert, pRetKey)); } diff --git a/qdevices/qdevice-net-socket.c b/qdevices/qdevice-net-socket.c index 5d1b78e0..6dc0f3fe 100644 --- a/qdevices/qdevice-net-socket.c +++ b/qdevices/qdevice-net-socket.c @@ -1,213 +1,213 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "msg.h" #include "msgio.h" #include "qnet-config.h" #include "qdevice-log.h" #include "qdevice-net-msg-received.h" #include "qdevice-net-nss.h" #include "qdevice-net-send.h" #include "qdevice-net-socket.h" /* * -1 means end of connection (EOF) or some other unhandled error. 0 = success */ int qdevice_net_socket_read(struct qdevice_net_instance *instance) { int res; int ret_val; int orig_skipping_msg; orig_skipping_msg = instance->skipping_msg; res = msgio_read(instance->socket, &instance->receive_buffer, &instance->msg_already_received_bytes, &instance->skipping_msg); if (!orig_skipping_msg && instance->skipping_msg) { qdevice_log(LOG_DEBUG, "msgio_read set skipping_msg"); } ret_val = 0; switch (res) { case 0: /* * Partial read */ break; case -1: qdevice_log(LOG_DEBUG, "Server closed connection"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_CLOSED_CONNECTION; ret_val = -1; break; case -2: qdevice_log(LOG_ERR, "Unhandled error when reading from server. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_READ_MESSAGE; ret_val = -1; break; case -3: qdevice_log(LOG_ERR, "Can't store message header from server. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_READ_MESSAGE; ret_val = -1; break; case -4: qdevice_log(LOG_ERR, "Can't store message from server. " "Disconnecting from server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_READ_MESSAGE; ret_val = -1; break; case -5: qdevice_log(LOG_WARNING, "Server sent unsupported msg type %u. " "Disconnecting from server", msg_get_type(&instance->receive_buffer)); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNSUPPORTED_MSG; ret_val = -1; break; case -6: qdevice_log(LOG_WARNING, "Server wants to send too long message %u bytes. Disconnecting from server", msg_get_len(&instance->receive_buffer)); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_READ_MESSAGE; ret_val = -1; break; case 1: /* * Full message received / skipped */ if (!instance->skipping_msg) { if (qdevice_net_msg_received(instance) == -1) { ret_val = -1; } } else { qdevice_log(LOG_CRIT, "net_socket_read in skipping msg state"); exit(1); } instance->skipping_msg = 0; instance->msg_already_received_bytes = 0; dynar_clean(&instance->receive_buffer); break; default: qdevice_log(LOG_CRIT, "qdevice_net_socket_read unhandled error %d", res); exit(1); break; } return (ret_val); } static int qdevice_net_socket_write_finished(struct qdevice_net_instance *instance) { PRFileDesc *new_pr_fd; if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_STARTTLS_BEING_SENT) { /* * StartTLS sent to server. Begin with TLS handshake */ if ((new_pr_fd = nss_sock_start_ssl_as_client(instance->socket, - QDEVICE_NET_NSS_SERVER_CN, + instance->advanced_settings->net_nss_qnetd_cn, qdevice_net_nss_bad_cert_hook, qdevice_net_nss_get_client_auth_data, instance, 0, NULL)) == NULL) { qdevice_log_nss(LOG_ERR, "Can't start TLS"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_START_TLS; return (-1); } /* * And send init msg */ if (qdevice_net_send_init(instance) != 0) { instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; return (-1); } instance->socket = new_pr_fd; instance->using_tls = 1; } return (0); } int qdevice_net_socket_write(struct qdevice_net_instance *instance) { int res; struct send_buffer_list_entry *send_buffer; enum msg_type sent_msg_type; send_buffer = send_buffer_list_get_active(&instance->send_buffer_list); if (send_buffer == NULL) { qdevice_log(LOG_CRIT, "send_buffer_list_get_active returned NULL"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SEND_MESSAGE; return (-1); } res = msgio_write(instance->socket, &send_buffer->buffer, &send_buffer->msg_already_sent_bytes); if (res == 1) { sent_msg_type = msg_get_type(&send_buffer->buffer); send_buffer_list_delete(&instance->send_buffer_list, send_buffer); if (sent_msg_type != MSG_TYPE_ECHO_REQUEST) { if (qdevice_net_socket_write_finished(instance) == -1) { return (-1); } } } if (res == -1) { qdevice_log_nss(LOG_CRIT, "PR_Send returned 0"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_CLOSED_CONNECTION; return (-1); } if (res == -2) { qdevice_log_nss(LOG_ERR, "Unhandled error when sending message to server"); instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SEND_MESSAGE; return (-1); } return (0); } diff --git a/qdevices/qdevice-votequorum.c b/qdevices/qdevice-votequorum.c index 35ae3553..a25934b9 100644 --- a/qdevices/qdevice-votequorum.c +++ b/qdevices/qdevice-votequorum.c @@ -1,275 +1,275 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qdevice-config.h" #include "qdevice-log.h" #include "qdevice-votequorum.h" #include "qdevice-model.h" #include "utils.h" static void qdevice_votequorum_quorum_notify_callback(votequorum_handle_t votequorum_handle, uint64_t context, uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[]) { struct qdevice_instance *instance; uint32_t u32; if (votequorum_context_get(votequorum_handle, (void **)&instance) != CS_OK) { qdevice_log(LOG_CRIT, "Fatal error. Can't get votequorum context"); exit(1); } qdevice_log(LOG_DEBUG, "Votequorum quorum notify callback:"); qdevice_log(LOG_DEBUG, " Quorate = %u", quorate); qdevice_log(LOG_DEBUG, " Node list (size = %"PRIu32"):", node_list_entries); for (u32 = 0; u32 < node_list_entries; u32++) { qdevice_log(LOG_DEBUG, " %"PRIu32" nodeid = "UTILS_PRI_NODE_ID", state = %"PRIu32, u32, node_list[u32].nodeid, node_list[u32].state); } if (qdevice_model_votequorum_quorum_notify(instance, quorate, node_list_entries, node_list) != 0) { qdevice_log(LOG_DEBUG, "qdevice_model_votequorum_quorum_notify returned error -> exit"); exit(2); } instance->vq_quorum_quorate = quorate; instance->vq_quorum_node_list_entries = node_list_entries; free(instance->vq_quorum_node_list); instance->vq_quorum_node_list = malloc(sizeof(*node_list) * node_list_entries); if (instance->vq_quorum_node_list == NULL) { qdevice_log(LOG_CRIT, "Can't alloc votequorum node list memory"); exit(1); } memcpy(instance->vq_quorum_node_list, node_list, sizeof(*node_list) * node_list_entries); } static void qdevice_votequorum_node_list_notify_callback(votequorum_handle_t votequorum_handle, uint64_t context, votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[]) { struct qdevice_instance *instance; uint32_t u32; if (votequorum_context_get(votequorum_handle, (void **)&instance) != CS_OK) { qdevice_log(LOG_CRIT, "Fatal error. Can't get votequorum context"); exit(1); } qdevice_log(LOG_DEBUG, "Votequorum nodelist notify callback:"); qdevice_log(LOG_DEBUG, " Ring_id = ("UTILS_PRI_RING_ID")", votequorum_ring_id.nodeid, votequorum_ring_id.seq); qdevice_log(LOG_DEBUG, " Node list (size = %"PRIu32"):", node_list_entries); for (u32 = 0; u32 < node_list_entries; u32++) { qdevice_log(LOG_DEBUG, " %"PRIu32" nodeid = "UTILS_PRI_NODE_ID, u32, node_list[u32]); } if (qdevice_model_votequorum_node_list_notify(instance, votequorum_ring_id, node_list_entries, node_list) != 0) { qdevice_log(LOG_DEBUG, "qdevice_votequorum_node_list_notify_callback returned error -> exit"); exit(2); } memcpy(&instance->vq_node_list_ring_id, &votequorum_ring_id, sizeof(votequorum_ring_id)); instance->vq_node_list_entries = node_list_entries; free(instance->vq_node_list); instance->vq_node_list = malloc(sizeof(*node_list) * node_list_entries); if (instance->vq_node_list == NULL) { qdevice_log(LOG_CRIT, "Can't alloc votequorum node list memory"); exit(1); } memcpy(instance->vq_node_list, node_list, sizeof(*node_list) * node_list_entries); } static void qdevice_votequorum_expected_votes_notify_callback(votequorum_handle_t votequorum_handle, uint64_t context, uint32_t expected_votes) { struct qdevice_instance *instance; if (votequorum_context_get(votequorum_handle, (void **)&instance) != CS_OK) { qdevice_log(LOG_CRIT, "Fatal error. Can't get votequorum context"); exit(1); } qdevice_log(LOG_DEBUG, "Votequorum expected_votes notify callback:"); qdevice_log(LOG_DEBUG, " Expected_votes: "UTILS_PRI_EXPECTED_VOTES, expected_votes); if (qdevice_model_votequorum_expected_votes_notify(instance, expected_votes) != 0) { qdevice_log(LOG_DEBUG, "qdevice_votequorum_expected_votes_notify_callback returned error -> exit"); exit(2); } instance->vq_expected_votes = expected_votes; } void qdevice_votequorum_init(struct qdevice_instance *instance) { votequorum_callbacks_t votequorum_callbacks; votequorum_handle_t votequorum_handle; cs_error_t res; int no_retries; struct votequorum_info vq_info; memset(&votequorum_callbacks, 0, sizeof(votequorum_callbacks)); votequorum_callbacks.votequorum_quorum_notify_fn = qdevice_votequorum_quorum_notify_callback; votequorum_callbacks.votequorum_nodelist_notify_fn = qdevice_votequorum_node_list_notify_callback; votequorum_callbacks.votequorum_expectedvotes_notify_fn = qdevice_votequorum_expected_votes_notify_callback; no_retries = 0; while ((res = votequorum_initialize(&votequorum_handle, &votequorum_callbacks)) == CS_ERR_TRY_AGAIN && - no_retries++ < QDEVICE_MAX_CS_TRY_AGAIN) { + no_retries++ < instance->advanced_settings->max_cs_try_again) { (void)poll(NULL, 0, 1000); } if (res != CS_OK) { qdevice_log(LOG_CRIT, "Failed to initialize the votequorum API. Error %s", cs_strerror(res)); exit(1); } if ((res = votequorum_qdevice_register(votequorum_handle, - QDEVICE_VOTEQUORUM_DEVICE_NAME)) != CS_OK) { + instance->advanced_settings->votequorum_device_name)) != CS_OK) { qdevice_log(LOG_CRIT, "Can't register votequorum device. Error %s", cs_strerror(res)); exit(1); } if ((res = votequorum_context_set(votequorum_handle, (void *)instance)) != CS_OK) { qdevice_log(LOG_CRIT, "Can't set votequorum context. Error %s", cs_strerror(res)); exit(1); } if ((res = votequorum_getinfo(votequorum_handle, VOTEQUORUM_QDEVICE_NODEID, &vq_info)) != CS_OK) { qdevice_log(LOG_CRIT, "Can't get votequorum information. Error %s", cs_strerror(res)); exit(1); } instance->vq_expected_votes = vq_info.node_expected_votes; instance->votequorum_handle = votequorum_handle; votequorum_fd_get(votequorum_handle, &instance->votequorum_poll_fd); if ((res = votequorum_trackstart(instance->votequorum_handle, 0, CS_TRACK_CHANGES)) != CS_OK) { qdevice_log(LOG_CRIT, "Can't start tracking votequorum changes. Error %s", cs_strerror(res)); exit(1); } } void qdevice_votequorum_destroy(struct qdevice_instance *instance) { cs_error_t res; free(instance->vq_quorum_node_list); instance->vq_quorum_node_list = NULL; free(instance->vq_node_list); instance->vq_node_list = NULL; res = votequorum_trackstop(instance->votequorum_handle); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Can't start tracking votequorum changes. Error %s", cs_strerror(res)); } res = votequorum_qdevice_unregister(instance->votequorum_handle, - QDEVICE_VOTEQUORUM_DEVICE_NAME); + instance->advanced_settings->votequorum_device_name); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Unable to unregister votequorum device. Error %s", cs_strerror(res)); } res = votequorum_finalize(instance->votequorum_handle); if (res != CS_OK) { qdevice_log(LOG_WARNING, "Unable to finalize votequorum. Error %s", cs_strerror(res)); } } int qdevice_votequorum_dispatch(struct qdevice_instance *instance) { cs_error_t res; res = votequorum_dispatch(instance->votequorum_handle, CS_DISPATCH_ALL); if (res != CS_OK && res != CS_ERR_TRY_AGAIN) { qdevice_log(LOG_ERR, "Can't dispatch votequorum messages"); return (-1); } return (0); } int qdevice_votequorum_poll(struct qdevice_instance *instance, int cast_vote) { cs_error_t res; instance->vq_last_poll = time(NULL); instance->vq_last_poll_cast_vote = cast_vote; res = votequorum_qdevice_poll(instance->votequorum_handle, - QDEVICE_VOTEQUORUM_DEVICE_NAME, cast_vote, + instance->advanced_settings->votequorum_device_name, cast_vote, instance->vq_node_list_ring_id); if (res != CS_OK && res != CS_ERR_TRY_AGAIN) { if (res == CS_ERR_MESSAGE_ERROR) { qdevice_log(LOG_INFO, "qdevice_votequorum_poll called with old ring id"); } else { qdevice_log(LOG_CRIT, "Can't call votequorum_qdevice_poll. Error %s", cs_strerror(res)); return (-1); } } return (0); } diff --git a/qdevices/qnet-config.h b/qdevices/qnet-config.h index b388cd31..906907f5 100644 --- a/qdevices/qnet-config.h +++ b/qdevices/qnet-config.h @@ -1,129 +1,142 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 _QNET_CONFIG_H_ #define _QNET_CONFIG_H_ #include #include "tlv.h" #ifdef __cplusplus extern "C" { #endif /* * There are "hardcoded" defaults for both qnetd and qdevice-net. It's not so good * idea to change them as long as you are not 100% sure what you are doing. Also - * every single one can be changed in CLI via advanced_settings (-S). + * most of them can be changed in CLI via advanced_settings (-S). */ -#define QNETD_PROGRAM_NAME "corosync-qnetd" -#define QNETD_DEFAULT_HOST_PORT 5403 -#define QNETD_DEFAULT_LISTEN_BACKLOG 10 -#define QNETD_MIN_LISTEN_BACKLOG 1 -#define QNETD_DEFAULT_MAX_CLIENT_SEND_BUFFERS 10 -#define QNETD_MIN_CLIENT_SEND_BUFFERS 2 -#define QNETD_DEFAULT_MAX_CLIENT_SEND_SIZE (1 << 15) -#define QNETD_DEFAULT_MAX_CLIENT_RECEIVE_SIZE (1 << 15) -#define QNETD_MIN_CLIENT_RECEIVE_SEND_SIZE 16 -#define QNETD_DEFAULT_MAX_CLIENTS 0 +#define QNETD_PROGRAM_NAME "corosync-qnetd" +#define QNETD_DEFAULT_HOST_PORT 5403 +#define QNETD_DEFAULT_LISTEN_BACKLOG 10 +#define QNETD_MIN_LISTEN_BACKLOG 1 +#define QNETD_DEFAULT_MAX_CLIENT_SEND_BUFFERS 10 +#define QNETD_MIN_CLIENT_SEND_BUFFERS 2 +#define QNETD_DEFAULT_MAX_CLIENT_SEND_SIZE (1 << 15) +#define QNETD_DEFAULT_MAX_CLIENT_RECEIVE_SIZE (1 << 15) +#define QNETD_MIN_CLIENT_RECEIVE_SEND_SIZE 16 +#define QNETD_DEFAULT_MAX_CLIENTS 0 -#define QNETD_DEFAULT_NSS_DB_DIR COROSYSCONFDIR "/qdevice/net/qnetd/nssdb" -#define QNETD_DEFAULT_CERT_NICKNAME "QNetd Cert" +#define QNETD_DEFAULT_NSS_DB_DIR COROSYSCONFDIR "/qdevice/net/qnetd/nssdb" +#define QNETD_DEFAULT_CERT_NICKNAME "QNetd Cert" -#define QNETD_DEFAULT_TLS_SUPPORTED TLV_TLS_SUPPORTED -#define QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED 1 +#define QNETD_DEFAULT_TLS_SUPPORTED TLV_TLS_SUPPORTED +#define QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED 1 -#define QNETD_DEFAULT_HEARTBEAT_INTERVAL_MIN (1*1000) -#define QNETD_DEFAULT_HEARTBEAT_INTERVAL_MAX (2*60*1000) -#define QNETD_MIN_HEARTBEAT_INTERVAL 1 +#define QNETD_DEFAULT_HEARTBEAT_INTERVAL_MIN (1*1000) +#define QNETD_DEFAULT_HEARTBEAT_INTERVAL_MAX (2*60*1000) +#define QNETD_MIN_HEARTBEAT_INTERVAL 1 -#define QNETD_DEFAULT_DPD_ENABLED 1 -#define QNETD_DEFAULT_DPD_INTERVAL (10*1000) -#define QNETD_MIN_DPD_INTERVAL 1 +#define QNETD_DEFAULT_DPD_ENABLED 1 +#define QNETD_DEFAULT_DPD_INTERVAL (10*1000) +#define QNETD_MIN_DPD_INTERVAL 1 -#define QNETD_DEFAULT_LOCK_FILE LOCALSTATEDIR"/run/corosync-qnetd.pid" -#define QNETD_DEFAULT_LOCAL_SOCKET_FILE LOCALSTATEDIR"/run/corosync-qnetd.sock" -#define QNETD_DEFAULT_LOCAL_SOCKET_BACKLOG 10 -#define QNETD_MIN_LOCAL_SOCKET_BACKLOG 1 +#define QNETD_DEFAULT_LOCK_FILE LOCALSTATEDIR"/run/corosync-qnetd.pid" +#define QNETD_DEFAULT_LOCAL_SOCKET_FILE LOCALSTATEDIR"/run/corosync-qnetd.sock" +#define QNETD_DEFAULT_LOCAL_SOCKET_BACKLOG 10 +#define QNETD_MIN_LOCAL_SOCKET_BACKLOG 1 -#define QNETD_DEFAULT_IPC_MAX_CLIENTS 10 -#define QNETD_MIN_IPC_MAX_CLIENTS 0 -#define QNETD_DEFAULT_IPC_MAX_RECEIVE_SIZE (4*1024) -#define QNETD_DEFAULT_IPC_MAX_SEND_SIZE (10*1024*1024) -#define QNETD_MIN_IPC_RECEIVE_SEND_SIZE 1024 +#define QNETD_DEFAULT_IPC_MAX_CLIENTS 10 +#define QNETD_MIN_IPC_MAX_CLIENTS 0 +#define QNETD_DEFAULT_IPC_MAX_RECEIVE_SIZE (4*1024) +#define QNETD_DEFAULT_IPC_MAX_SEND_SIZE (10*1024*1024) +#define QNETD_MIN_IPC_RECEIVE_SEND_SIZE 1024 -#define QNETD_TOOL_PROGRAM_NAME "corosync-qnetd-tool" +#define QNETD_TOOL_PROGRAM_NAME "corosync-qnetd-tool" -#define QDEVICE_NET_NSS_DB_DIR COROSYSCONFDIR "/qdevice/net/node/nssdb" +#define QDEVICE_NET_DEFAULT_NSS_DB_DIR COROSYSCONFDIR "/qdevice/net/node/nssdb" -#define QDEVICE_NET_INITIAL_MSG_RECEIVE_SIZE (1 << 15) -#define QDEVICE_NET_INITIAL_MSG_SEND_SIZE (1 << 15) -#define QDEVICE_NET_MIN_MSG_SEND_SIZE QDEVICE_NET_INITIAL_MSG_SEND_SIZE -#define QDEVICE_NET_MAX_MSG_RECEIVE_SIZE (1 << 24) +#define QDEVICE_NET_DEFAULT_INITIAL_MSG_RECEIVE_SIZE (1 << 15) +#define QDEVICE_NET_DEFAULT_INITIAL_MSG_SEND_SIZE (1 << 15) +#define QDEVICE_NET_DEFAULT_MIN_MSG_SEND_SIZE QDEVICE_NET_DEFAULT_INITIAL_MSG_SEND_SIZE +#define QDEVICE_NET_DEFAULT_MAX_MSG_RECEIVE_SIZE (1 << 24) +#define QDEVICE_NET_DEFAULT_MAX_SEND_BUFFERS 10 +#define QDEVICE_NET_MIN_MAX_SEND_BUFFERS 2 +#define QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE 16 -#define QDEVICE_NET_NSS_SERVER_CN "Qnetd Server" +#define QDEVICE_NET_DEFAULT_NSS_QNETD_CN "Qnetd Server" -#define QDEVICE_NET_NSS_CLIENT_CERT_NICKNAME "Cluster Cert" +#define QDEVICE_NET_DEFAULT_NSS_CLIENT_CERT_NICKNAME "Cluster Cert" -#define QDEVICE_NET_MAX_SEND_BUFFERS 10 -#define QDEVICE_NET_DEFAULT_ALGORITHM TLV_DECISION_ALGORITHM_TYPE_TEST +#define QDEVICE_NET_DEFAULT_ALGORITHM TLV_DECISION_ALGORITHM_TYPE_TEST -#define QDEVICE_NET_DEFAULT_TLS_SUPPORTED TLV_TLS_SUPPORTED +#define QDEVICE_NET_DEFAULT_TLS_SUPPORTED TLV_TLS_SUPPORTED -#define QDEVICE_NET_DEFAULT_TIE_BREAKER_MODE TLV_TIE_BREAKER_MODE_LOWEST +#define QDEVICE_NET_DEFAULT_TIE_BREAKER_MODE TLV_TIE_BREAKER_MODE_LOWEST -#define QDEVICE_NET_HEARTBEAT_INTERVAL_MIN QNETD_DEFAULT_HEARTBEAT_INTERVAL_MIN -#define QDEVICE_NET_HEARTBEAT_INTERVAL_MAX QNETD_DEFAULT_HEARTBEAT_INTERVAL_MAX +#define QDEVICE_NET_DEFAULT_HEARTBEAT_INTERVAL_MIN QNETD_DEFAULT_HEARTBEAT_INTERVAL_MIN +#define QDEVICE_NET_DEFAULT_HEARTBEAT_INTERVAL_MAX QNETD_DEFAULT_HEARTBEAT_INTERVAL_MAX +#define QDEVICE_NET_MIN_HEARTBEAT_INTERVAL 1 -#define QDEVICE_NET_MIN_CONNECT_TIMEOUT (1*1000L) -#define QDEVICE_NET_MAX_CONNECT_TIMEOUT (2*60*1000L) +#define QDEVICE_NET_DEFAULT_MIN_CONNECT_TIMEOUT (1*1000) +#define QDEVICE_NET_DEFAULT_MAX_CONNECT_TIMEOUT (2*60*1000) +#define QDEVICE_NET_MIN_CONNECT_TIMEOUT 1 + +#ifdef DEBUG +#define QDEVICE_NET_DEFAULT_TEST_ALGORITHM_ENABLED 1 +#else +#define QDEVICE_NET_DEFAULT_TEST_ALGORITHM_ENABLED 0 +#endif + +#define QDEVICE_NET_DEFAULT_DELAY_BEFORE_RECONNECT (1000) +#define QDEVICE_NET_MIN_DELAY_BEFORE_RECONNECT 1 /* * Decision algorithms supported by qnetd */ #define QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE 4 extern enum tlv_decision_algorithm_type qnetd_static_supported_decision_algorithms[QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE]; #define QDEVICE_NET_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE #ifdef __cplusplus } #endif #endif /* _QNET_CONFIG_H_ */ diff --git a/qdevices/qnetd-advanced-settings.c b/qdevices/qnetd-advanced-settings.c index f1eff374..2a08f3f0 100644 --- a/qdevices/qnetd-advanced-settings.c +++ b/qdevices/qnetd-advanced-settings.c @@ -1,213 +1,220 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "dynar.h" #include "dynar-getopt-lex.h" #include "dynar-str.h" #include "qnet-config.h" #include "qnetd-advanced-settings.h" #include "utils.h" int qnetd_advanced_settings_init(struct qnetd_advanced_settings *settings) { memset(settings, 0, sizeof(*settings)); settings->listen_backlog = QNETD_DEFAULT_LISTEN_BACKLOG; settings->max_client_send_buffers = QNETD_DEFAULT_MAX_CLIENT_SEND_BUFFERS; settings->max_client_send_size = QNETD_DEFAULT_MAX_CLIENT_SEND_SIZE; settings->max_client_receive_size = QNETD_DEFAULT_MAX_CLIENT_RECEIVE_SIZE; if ((settings->nss_db_dir = strdup(QNETD_DEFAULT_NSS_DB_DIR)) == NULL) { return (-1); } if ((settings->cert_nickname = strdup(QNETD_DEFAULT_CERT_NICKNAME)) == NULL) { return (-1); } settings->heartbeat_interval_min = QNETD_DEFAULT_HEARTBEAT_INTERVAL_MIN; settings->heartbeat_interval_max = QNETD_DEFAULT_HEARTBEAT_INTERVAL_MAX; settings->dpd_enabled = QNETD_DEFAULT_DPD_ENABLED; settings->dpd_interval = QNETD_DEFAULT_DPD_INTERVAL; if ((settings->lock_file = strdup(QNETD_DEFAULT_LOCK_FILE)) == NULL) { return (-1); } if ((settings->local_socket_file = strdup(QNETD_DEFAULT_LOCAL_SOCKET_FILE)) == NULL) { return (-1); } settings->local_socket_backlog = QNETD_DEFAULT_LOCAL_SOCKET_BACKLOG; settings->ipc_max_clients = QNETD_DEFAULT_IPC_MAX_CLIENTS; settings->ipc_max_receive_size = QNETD_DEFAULT_IPC_MAX_RECEIVE_SIZE; settings->ipc_max_send_size = QNETD_DEFAULT_IPC_MAX_SEND_SIZE; return (0); } void qnetd_advanced_settings_destroy(struct qnetd_advanced_settings *settings) { free(settings->nss_db_dir); free(settings->cert_nickname); free(settings->lock_file); free(settings->local_socket_file); } /* * 0 - No error * -1 - Unknown option * -2 - Incorrect value */ int qnetd_advanced_settings_set(struct qnetd_advanced_settings *settings, const char *option, const char *value) { long long int tmpll; char *ep; if (strcasecmp(option, "listen_backlog") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_LISTEN_BACKLOG || errno != 0 || *ep != '\0') { return (-2); } settings->listen_backlog = (int)tmpll; } else if (strcasecmp(option, "max_client_send_buffers") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_CLIENT_SEND_BUFFERS || errno != 0 || *ep != '\0') { return (-2); } settings->max_client_send_buffers = (size_t)tmpll; } else if (strcasecmp(option, "max_client_send_size") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_CLIENT_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { return (-2); } settings->max_client_send_size = (size_t)tmpll; } else if (strcasecmp(option, "max_client_receive_size") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_CLIENT_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { return (-2); } settings->max_client_receive_size = (size_t)tmpll; } else if (strcasecmp(option, "nss_db_dir") == 0) { free(settings->nss_db_dir); if ((settings->nss_db_dir = strdup(value)) == NULL) { return (-1); } } else if (strcasecmp(option, "cert_nickname") == 0) { free(settings->cert_nickname); if ((settings->cert_nickname = strdup(value)) == NULL) { return (-1); } } else if (strcasecmp(option, "heartbeat_interval_min") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_HEARTBEAT_INTERVAL || errno != 0 || *ep != '\0') { return (-2); } settings->heartbeat_interval_min = (uint32_t)tmpll; } else if (strcasecmp(option, "heartbeat_interval_max") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_HEARTBEAT_INTERVAL || errno != 0 || *ep != '\0') { return (-2); } settings->heartbeat_interval_max = (uint32_t)tmpll; } else if (strcasecmp(option, "dpd_enabled") == 0) { if ((tmpll = utils_parse_bool_str(value)) == -1) { return (-2); } settings->dpd_enabled = (uint8_t)tmpll; } else if (strcasecmp(option, "dpd_interval") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_DPD_INTERVAL || errno != 0 || *ep != '\0') { return (-2); } settings->dpd_interval = (uint32_t)tmpll; } else if (strcasecmp(option, "lock_file") == 0) { free(settings->lock_file); if ((settings->lock_file = strdup(value)) == NULL) { return (-1); } } else if (strcasecmp(option, "local_socket_file") == 0) { free(settings->local_socket_file); if ((settings->local_socket_file = strdup(value)) == NULL) { return (-1); } } else if (strcasecmp(option, "local_socket_backlog") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_LOCAL_SOCKET_BACKLOG || errno != 0 || *ep != '\0') { return (-2); } settings->local_socket_backlog = (int)tmpll; } else if (strcasecmp(option, "ipc_max_clients") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_IPC_MAX_CLIENTS || errno != 0 || *ep != '\0') { return (-2); } settings->ipc_max_clients = (size_t)tmpll; } else if (strcasecmp(option, "ipc_max_receive_size") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { return (-2); } settings->ipc_max_receive_size = (size_t)tmpll; } else if (strcasecmp(option, "ipc_max_send_size") == 0) { tmpll = strtoll(value, &ep, 10); if (tmpll < QNETD_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { return (-2); } + settings->ipc_max_send_size = (size_t)tmpll; + } else if (strcasecmp(option, "ipc_max_send_size") == 0) { + tmpll = strtoll(value, &ep, 10); + if (tmpll < QNETD_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') { + return (-2); + } + settings->ipc_max_send_size = (size_t)tmpll; } else { return (-1); } return (0); } diff --git a/qdevices/qnetd-instance.c b/qdevices/qnetd-instance.c index 58b07a27..931b18a0 100644 --- a/qdevices/qnetd-instance.c +++ b/qdevices/qnetd-instance.c @@ -1,134 +1,134 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 "qnetd-instance.h" #include "qnetd-client.h" #include "qnetd-algorithm.h" #include "qnetd-log-debug.h" #include "qnetd-dpd-timer.h" #include "qnetd-poll-array-user-data.h" #include "qnetd-client-algo-timer.h" int qnetd_instance_init(struct qnetd_instance *instance, enum tlv_tls_supported tls_supported, int tls_client_cert_required, size_t max_clients, - struct qnetd_advanced_settings *advanced_settings) + const struct qnetd_advanced_settings *advanced_settings) { memset(instance, 0, sizeof(*instance)); instance->advanced_settings = advanced_settings; pr_poll_array_init(&instance->poll_array, sizeof(struct qnetd_poll_array_user_data)); qnetd_client_list_init(&instance->clients); qnetd_cluster_list_init(&instance->clusters); instance->tls_supported = tls_supported; instance->tls_client_cert_required = tls_client_cert_required; instance->max_clients = max_clients; timer_list_init(&instance->main_timer_list); if (qnetd_dpd_timer_init(instance) != 0) { return (0); } return (0); } int qnetd_instance_destroy(struct qnetd_instance *instance) { struct qnetd_client *client; struct qnetd_client *client_next; qnetd_dpd_timer_destroy(instance); client = TAILQ_FIRST(&instance->clients); while (client != NULL) { client_next = TAILQ_NEXT(client, entries); qnetd_instance_client_disconnect(instance, client, 1); client = client_next; } pr_poll_array_destroy(&instance->poll_array); qnetd_cluster_list_free(&instance->clusters); qnetd_client_list_free(&instance->clients); timer_list_free(&instance->main_timer_list); return (0); } void qnetd_instance_client_disconnect(struct qnetd_instance *instance, struct qnetd_client *client, int server_going_down) { qnetd_log_debug_client_disconnect(client, server_going_down); if (client->init_received) { qnetd_algorithm_client_disconnect(client, server_going_down); } PR_Close(client->socket); if (client->cluster != NULL) { qnetd_cluster_list_del_client(&instance->clusters, client->cluster, client); } qnetd_client_algo_timer_abort(client); qnetd_client_list_del(&instance->clients, client); } int qnetd_instance_init_certs(struct qnetd_instance *instance) { instance->server.cert = PK11_FindCertFromNickname( instance->advanced_settings->cert_nickname, NULL); if (instance->server.cert == NULL) { return (-1); } instance->server.private_key = PK11_FindKeyByAnyCert(instance->server.cert, NULL); if (instance->server.private_key == NULL) { return (-1); } return (0); } diff --git a/qdevices/qnetd-instance.h b/qdevices/qnetd-instance.h index a810a2e5..d2c4733e 100644 --- a/qdevices/qnetd-instance.h +++ b/qdevices/qnetd-instance.h @@ -1,92 +1,92 @@ /* * Copyright (c) 2015-2016 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@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 Red Hat, 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 _QNETD_INSTANCE_H_ #define _QNETD_INSTANCE_H_ #include #include #include #include #include "qnetd-client-list.h" #include "qnetd-cluster-list.h" #include "pr-poll-array.h" #include "qnet-config.h" #include "timer-list.h" #include "unix-socket-ipc.h" #include "qnetd-advanced-settings.h" #ifdef __cplusplus extern "C" { #endif struct qnetd_instance { struct { PRFileDesc *socket; CERTCertificate *cert; SECKEYPrivateKey *private_key; } server; size_t max_clients; struct qnetd_client_list clients; struct qnetd_cluster_list clusters; struct pr_poll_array poll_array; enum tlv_tls_supported tls_supported; int tls_client_cert_required; const char *host_addr; uint16_t host_port; struct timer_list main_timer_list; struct timer_list_entry *dpd_timer; /* Dead peer detection timer */ struct unix_socket_ipc local_ipc; PRFileDesc *ipc_socket_poll_fd; - struct qnetd_advanced_settings *advanced_settings; + const struct qnetd_advanced_settings *advanced_settings; }; extern int qnetd_instance_init(struct qnetd_instance *instance, enum tlv_tls_supported tls_supported, int tls_client_cert_required, size_t max_clients, - struct qnetd_advanced_settings *advanced_settings); + const struct qnetd_advanced_settings *advanced_settings); extern int qnetd_instance_destroy(struct qnetd_instance *instance); extern void qnetd_instance_client_disconnect(struct qnetd_instance *instance, struct qnetd_client *client, int server_going_down); extern int qnetd_instance_init_certs(struct qnetd_instance *instance); #ifdef __cplusplus } #endif #endif /* _QNETD_INSTANCE_H_ */