Selaa lähdekoodia

Qnetd: Add advanced settings

All previously defined defaults are now configurable via -S option.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 9 vuotta sitten
vanhempi
commit
79a1b9ea59

+ 7 - 3
qdevices/Makefile.am

@@ -65,7 +65,8 @@ corosync_qnetd_SOURCES	= corosync-qnetd.c \
                           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
+                          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 \
@@ -125,8 +126,10 @@ corosync-qdevice-net-certutil: corosync-qdevice-net-certutil.sh
 	    -e 's#@''COROSYSCONFDIR@#${COROSYSCONFDIR}#g' \
 	    $< > $@
 
-TESTS				= qnetd-cluster-list.test dynar.test dynar-simple-lex.test
-check_PROGRAMS			= qnetd-cluster-list.test dynar.test dynar-simple-lex.test
+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 \
@@ -136,5 +139,6 @@ 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

+ 2 - 2
qdevices/corosync-qnetd-tool.c

@@ -80,7 +80,7 @@ cli_parse(int argc, char * const argv[], enum qnetd_tool_operation *operation,
 	*operation = QNETD_TOOL_OPERATION_NONE;
 	*verbose = 0;
 	*cluster_name = NULL;
-	*socket_path = strdup(QNETD_LOCAL_SOCKET_FILE);
+	*socket_path = strdup(QNETD_DEFAULT_LOCAL_SOCKET_FILE);
 
 	if (*socket_path == NULL) {
 		errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
@@ -260,7 +260,7 @@ main(int argc, char * const argv[])
 
 	cli_parse(argc, argv, &operation, &verbose, &cluster_name, &socket_path);
 
-	dynar_init(&send_str, QNETD_IPC_MAX_RECEIVE_SIZE);
+	dynar_init(&send_str, QNETD_DEFAULT_IPC_MAX_RECEIVE_SIZE);
 
 	sock_fd = unix_socket_client_create(socket_path, 0);
 	if (sock_fd == -1) {

+ 96 - 11
qdevices/corosync-qnetd.c

@@ -40,8 +40,12 @@
 
 #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"
@@ -50,6 +54,7 @@
 #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)
@@ -346,14 +351,79 @@ static void
 usage(void)
 {
 
-	printf("usage: %s [-46dfh] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME);
-	printf("%14s[-c client_cert_required] [-m max_clients]\n", "");
+	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", "");
+}
+
+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)
+    int *client_cert_required, size_t *max_clients, PRIntn *address_family,
+    struct qnetd_advanced_settings *advanced_settings)
 {
 	int ch;
 	char *ep;
@@ -369,7 +439,7 @@ cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port,
 	*max_clients = QNETD_DEFAULT_MAX_CLIENTS;
 	*address_family = PR_AF_UNSPEC;
 
-	while ((ch = getopt(argc, argv, "46dfhc:l:m:p:s:")) != -1) {
+	while ((ch = getopt(argc, argv, "46dfhvc:l:m:p:S:s:")) != -1) {
 		switch (ch) {
 		case '4':
 			*address_family = PR_AF_INET;
@@ -413,6 +483,9 @@ cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port,
 				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;
@@ -424,6 +497,10 @@ cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port,
 				errx(1, "tls must be one of on, off, req");
 			}
 			break;
+		case 'v':
+			display_version();
+			exit(1);
+			break;
 		case 'h':
 		case '?':
 			usage();
@@ -437,6 +514,7 @@ 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;
@@ -449,8 +527,12 @@ main(int argc, char * const argv[])
 	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);
+	    &tls_supported, &client_cert_required, &max_clients, &address_family, &advanced_settings);
 
 	if (foreground) {
 		qnetd_log_init(QNETD_LOG_TARGET_STDERR);
@@ -468,7 +550,8 @@ main(int argc, char * const argv[])
 		utils_tty_detach();
 	}
 
-	if ((lock_file = utils_flock(QNETD_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) {
 			qnetd_log(LOG_ERR, "Another instance is running");
 		} else {
@@ -480,7 +563,7 @@ main(int argc, char * const argv[])
 
 	qnetd_log(LOG_DEBUG, "Initializing nss");
 	if (nss_sock_init_nss((tls_supported != TLV_TLS_UNSUPPORTED ?
-	    (char *)QNETD_NSS_DB_DIR : NULL)) != 0) {
+	    advanced_settings.nss_db_dir : NULL)) != 0) {
 		qnetd_err_nss();
 	}
 
@@ -488,9 +571,8 @@ main(int argc, char * const argv[])
 		qnetd_err_nss();
 	}
 
-	if (qnetd_instance_init(&instance, QNETD_MAX_CLIENT_RECEIVE_SIZE,
-	    QNETD_MAX_CLIENT_SEND_BUFFERS, QNETD_MAX_CLIENT_SEND_SIZE,
-	    tls_supported, client_cert_required, max_clients) == -1) {
+	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);
 	}
@@ -517,7 +599,8 @@ main(int argc, char * const argv[])
 		qnetd_err_nss();
 	}
 
-	if (PR_Listen(instance.server.socket, QNETD_LISTEN_BACKLOG) != PR_SUCCESS) {
+	if (PR_Listen(instance.server.socket, instance.advanced_settings->listen_backlog) !=
+	    PR_SUCCESS) {
 		qnetd_err_nss();
 	}
 
@@ -554,6 +637,8 @@ main(int argc, char * const argv[])
 
 	qnetd_instance_destroy(&instance);
 
+	qnetd_advanced_settings_destroy(&advanced_settings);
+
 	if (NSS_Shutdown() != SECSuccess) {
 		qnetd_warn_nss();
 	}

+ 131 - 0
qdevices/dynar-getopt-lex.c

@@ -0,0 +1,131 @@
+/*
+ * 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 <string.h>
+
+#include "dynar-getopt-lex.h"
+
+void
+dynar_getopt_lex_init(struct dynar_getopt_lex *lex, struct dynar *input)
+{
+
+	memset(lex, 0, sizeof(*lex));
+	lex->input = input;
+	dynar_init(&lex->option, dynar_max_size(input));
+	dynar_init(&lex->value, dynar_max_size(input));
+}
+
+void
+dynar_getopt_lex_destroy(struct dynar_getopt_lex *lex)
+{
+
+	dynar_destroy(&lex->option);
+	dynar_destroy(&lex->value);
+	memset(lex, 0, sizeof(*lex));
+}
+
+/*
+ * 0 - no error
+ * -1 - Can't add character
+ */
+int
+dynar_getopt_lex_token_next(struct dynar_getopt_lex *lex)
+{
+	size_t pos;
+	size_t size;
+	char *str;
+	char ch;
+	int state;
+	int res;
+
+	dynar_clean(&lex->option);
+	dynar_clean(&lex->value);
+
+	size = dynar_size(lex->input);
+	str = dynar_data(lex->input);
+
+	state = 1;
+	pos = lex->pos;
+	res = 0;
+
+	while (state != 0 && pos < size) {
+		ch = str[pos];
+
+		switch (state) {
+		case 1:
+			/*
+			 * Read option name, wait for = or ,
+			 */
+			if (ch == '=') {
+				pos++;
+				state = 2;
+			} else if (ch == ',') {
+				pos++;
+				state = 0;
+			} else {
+				pos++;
+				if (dynar_cat(&lex->option, &ch, sizeof(ch)) != 0) {
+					return (-1);
+				}
+			}
+			break;
+		case 2:
+			/*
+			 * Wait for end of str or ,
+			 */
+			if (ch == ',') {
+				pos++;
+				state = 0;
+			} else {
+				pos++;
+				if (dynar_cat(&lex->value, &ch, sizeof(ch)) != 0) {
+					return (-1);
+				}
+			}
+			break;
+		}
+	}
+
+	ch = '\0';
+	if (dynar_cat(&lex->option, &ch, sizeof(ch)) != 0) {
+		return (-1);
+	}
+	if (dynar_cat(&lex->value, &ch, sizeof(ch)) != 0) {
+		return (-1);
+	}
+
+	lex->pos = pos;
+
+	return (0);
+}

+ 61 - 0
qdevices/dynar-getopt-lex.h

@@ -0,0 +1,61 @@
+/*
+ * 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 _DYNAR_GETOPT_LEX_H_
+#define _DYNAR_GETOPT_LEX_H_
+
+#include "dynar.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dynar_getopt_lex {
+	struct dynar option;
+	struct dynar value;
+	struct dynar *input;
+	size_t pos;
+};
+
+extern void	 	dynar_getopt_lex_init(struct dynar_getopt_lex *lex, struct dynar *input);
+
+extern void	 	dynar_getopt_lex_destroy(struct dynar_getopt_lex *lex);
+
+extern int		dynar_getopt_lex_token_next(struct dynar_getopt_lex *lex);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DYNAR_GETOPT_LEX_H_ */

+ 3 - 1
qdevices/dynar-simple-lex.c

@@ -193,7 +193,9 @@ dynar_simple_lex_token_next(struct dynar_simple_lex *lex)
 	}
 
 	ch = '\0';
-	dynar_cat(&lex->token, &ch, sizeof(ch));
+	if (dynar_cat(&lex->token, &ch, sizeof(ch)) != 0) {
+		return (NULL);
+	}
 
 	lex->pos = pos;
 

+ 26 - 0
qdevices/msg.c

@@ -977,3 +977,29 @@ msg_get_supported_messages(enum msg_type **supported_messages, size_t *no_suppor
 	*supported_messages = msg_static_supported_messages;
 	*no_supported_messages = MSG_STATIC_SUPPORTED_MESSAGES_SIZE;
 }
+
+const char *
+msg_type_to_str(enum msg_type type)
+{
+
+	switch (type) {
+	case MSG_TYPE_PREINIT: return ("Preinit"); break;
+	case MSG_TYPE_PREINIT_REPLY: return ("Preinit reply"); break;
+	case MSG_TYPE_STARTTLS: return ("StartTLS"); break;
+	case MSG_TYPE_INIT: return ("Init"); break;
+	case MSG_TYPE_INIT_REPLY: return ("Init reply"); break;
+	case MSG_TYPE_SERVER_ERROR: return ("Server error"); break;
+	case MSG_TYPE_SET_OPTION: return ("Set option"); break;
+	case MSG_TYPE_SET_OPTION_REPLY: return ("Set option reply"); break;
+	case MSG_TYPE_ECHO_REQUEST: return ("Echo request"); break;
+	case MSG_TYPE_ECHO_REPLY: return ("Echo reply"); break;
+	case MSG_TYPE_NODE_LIST: return ("Node list"); break;
+	case MSG_TYPE_NODE_LIST_REPLY: return ("Node list reply"); break;
+	case MSG_TYPE_ASK_FOR_VOTE: return ("Ask for vote"); break;
+	case MSG_TYPE_ASK_FOR_VOTE_REPLY: return ("Ask for vote reply"); break;
+	case MSG_TYPE_VOTE_INFO: return ("Vote info"); break;
+	case MSG_TYPE_VOTE_INFO_REPLY: return ("Vote info reply"); break;
+	}
+
+	return ("Unknown message type");
+}

+ 2 - 0
qdevices/msg.h

@@ -191,6 +191,8 @@ extern int		msg_decode(const struct dynar *msg, struct msg_decoded *decoded_msg)
 extern void		msg_get_supported_messages(enum msg_type **supported_messages,
     size_t *no_supported_messages);
 
+extern const char *	msg_type_to_str(enum msg_type type);
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 3
qdevices/qdevice-config.h

@@ -66,9 +66,7 @@ extern "C" {
 #define QDEVICE_LOG_DEFAULT_TIMESTAMP		0
 #define QDEVICE_LOG_DEFAULT_FUNCTION_NAME	0
 
-#define QDEVICE_VOTEQUORUM_DEVICE_NAME      "Qdevice"
-
-#define QDEVICE_ENABLE_NSS			1
+#define QDEVICE_VOTEQUORUM_DEVICE_NAME		"Qdevice"
 
 #define QDEVICE_IPC_MAX_CLIENTS			10
 #define QDEVICE_IPC_MAX_RECEIVE_SIZE		(4*1024)

+ 6 - 6
qdevices/qdevice-net-instance.c

@@ -266,15 +266,15 @@ qdevice_net_instance_init_from_cmap(struct qdevice_instance *instance)
 	 */
 	cast_vote_timer_interval = instance->heartbeat_interval * 0.5;
 	heartbeat_interval = instance->heartbeat_interval * 0.8;
-	if (heartbeat_interval < QDEVICE_HEARTBEAT_INTERVAL_MIN) {
+	if (heartbeat_interval < QDEVICE_NET_HEARTBEAT_INTERVAL_MIN) {
 		qdevice_log(LOG_WARNING, "Heartbeat interval too small %"PRIu32". Adjusting to %"PRIu32".",
-		    heartbeat_interval, QNETD_HEARTBEAT_INTERVAL_MIN);
-		heartbeat_interval = QNETD_HEARTBEAT_INTERVAL_MIN;
+		    heartbeat_interval, QDEVICE_NET_HEARTBEAT_INTERVAL_MIN);
+		heartbeat_interval = QDEVICE_NET_HEARTBEAT_INTERVAL_MIN;
 	}
-	if (heartbeat_interval > QDEVICE_HEARTBEAT_INTERVAL_MAX) {
+	if (heartbeat_interval > QDEVICE_NET_HEARTBEAT_INTERVAL_MAX) {
 		qdevice_log(LOG_WARNING, "Heartbeat interval too big %"PRIu32". Adjusting to %"PRIu32".",
-		    heartbeat_interval, QNETD_HEARTBEAT_INTERVAL_MAX);
-		heartbeat_interval = QNETD_HEARTBEAT_INTERVAL_MAX;
+		    heartbeat_interval, QDEVICE_NET_HEARTBEAT_INTERVAL_MAX);
+		heartbeat_interval = QDEVICE_NET_HEARTBEAT_INTERVAL_MAX;
 	}
 	sync_heartbeat_interval = instance->sync_heartbeat_interval * 0.8;
 

+ 2 - 1
qdevices/qdevice-net-socket.c

@@ -139,7 +139,8 @@ qdevice_net_socket_write_finished(struct qdevice_net_instance *instance)
 		/*
 		 * StartTLS sent to server. Begin with TLS handshake
 		 */
-		if ((new_pr_fd = nss_sock_start_ssl_as_client(instance->socket, QNETD_NSS_SERVER_CN,
+		if ((new_pr_fd = nss_sock_start_ssl_as_client(instance->socket,
+		    QDEVICE_NET_NSS_SERVER_CN,
 		    qdevice_net_nss_bad_cert_hook,
 		    qdevice_net_nss_get_client_auth_data,
 		    instance, 0, NULL)) == NULL) {

+ 32 - 23
qdevices/qnet-config.h

@@ -44,37 +44,48 @@ extern "C" {
 #endif
 
 /*
- * There are "hardcoded" defines 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.
+ * 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).
  */
 
 #define QNETD_PROGRAM_NAME			"corosync-qnetd"
 #define QNETD_DEFAULT_HOST_PORT			5403
-#define QNETD_LISTEN_BACKLOG			10
-#define QNETD_MAX_CLIENT_SEND_BUFFERS		10
-#define QNETD_MAX_CLIENT_SEND_SIZE		(1 << 15)
-#define QNETD_MAX_CLIENT_RECEIVE_SIZE		(1 << 15)
+#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_NSS_DB_DIR			COROSYSCONFDIR "/qdevice/net/qnetd/nssdb"
-#define QNETD_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_HEARTBEAT_INTERVAL_MIN		(1*1000)
-#define QNETD_HEARTBEAT_INTERVAL_MAX		(2*60*1000)
+#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_DPD_ENABLED			1
-#define QNETD_DPD_INTERVAL			(10*1000)
+#define QNETD_DEFAULT_DPD_ENABLED		1
+#define QNETD_DEFAULT_DPD_INTERVAL		(10*1000)
+#define QNETD_MIN_DPD_INTERVAL			1
 
-#define QNETD_LOCK_FILE				LOCALSTATEDIR"/run/corosync-qnetd.pid"
-#define QNETD_LOCAL_SOCKET_FILE			LOCALSTATEDIR"/run/corosync-qnetd.sock"
-#define QNETD_LOCAL_SOCKET_BACKLOG		10
+#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_IPC_MAX_CLIENTS			10
-#define QNETD_IPC_MAX_RECEIVE_SIZE		(4*1024)
-#define QNETD_IPC_MAX_SEND_SIZE			(10*1024*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 QDEVICE_NET_NSS_DB_DIR			COROSYSCONFDIR "/qdevice/net/node/nssdb"
 
@@ -83,9 +94,7 @@ extern "C" {
 #define QDEVICE_NET_MIN_MSG_SEND_SIZE		QDEVICE_NET_INITIAL_MSG_SEND_SIZE
 #define QDEVICE_NET_MAX_MSG_RECEIVE_SIZE	(1 << 24)
 
-#define QNETD_NSS_SERVER_CN			"Qnetd Server"
-
-#define QNETD_TOOL_PROGRAM_NAME			"corosync-qnetd-tool"
+#define QDEVICE_NET_NSS_SERVER_CN		"Qnetd Server"
 
 #define QDEVICE_NET_NSS_CLIENT_CERT_NICKNAME	"Cluster Cert"
 
@@ -97,8 +106,8 @@ extern "C" {
 
 #define QDEVICE_NET_DEFAULT_TIE_BREAKER_MODE	TLV_TIE_BREAKER_MODE_LOWEST
 
-#define QDEVICE_HEARTBEAT_INTERVAL_MIN		QNETD_HEARTBEAT_INTERVAL_MIN
-#define QDEVICE_HEARTBEAT_INTERVAL_MAX		QNETD_HEARTBEAT_INTERVAL_MAX
+#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_MIN_CONNECT_TIMEOUT		(1*1000L)
 #define QDEVICE_NET_MAX_CONNECT_TIMEOUT		(2*60*1000L)

+ 213 - 0
qdevices/qnetd-advanced-settings.c

@@ -0,0 +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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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 {
+		return (-1);
+	}
+
+	return (0);
+}

+ 72 - 0
qdevices/qnetd-advanced-settings.h

@@ -0,0 +1,72 @@
+/*
+ * 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_ADVANCED_SETTINGS_H_
+#define _QNETD_ADVANCED_SETTINGS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct qnetd_advanced_settings {
+	int listen_backlog;
+	size_t max_client_send_buffers;
+	size_t max_client_send_size;
+	size_t max_client_receive_size;
+	char *nss_db_dir;
+	char *cert_nickname;
+	uint32_t heartbeat_interval_min;
+	uint32_t heartbeat_interval_max;
+	uint8_t dpd_enabled;
+	uint32_t dpd_interval;
+	char *lock_file;
+	char *local_socket_file;
+	int local_socket_backlog;
+	size_t ipc_max_clients;
+	size_t ipc_max_send_size;
+	size_t ipc_max_receive_size;
+};
+
+extern int		qnetd_advanced_settings_init(struct qnetd_advanced_settings *settings);
+
+extern int		qnetd_advanced_settings_set(struct qnetd_advanced_settings *settings,
+    const char *option, const char *value);
+
+extern void		qnetd_advanced_settings_destroy(struct qnetd_advanced_settings *settings);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _QNETD_ADVANCED_SETTINGS_H_ */

+ 6 - 5
qdevices/qnetd-client-msg-received.c

@@ -350,8 +350,8 @@ qnetd_client_msg_received_init(struct qnetd_instance *instance, struct qnetd_cli
 
 		reply_error_code = TLV_REPLY_ERROR_CODE_DOESNT_CONTAIN_REQUIRED_OPTION;
 	} else {
-		if (msg->heartbeat_interval < QNETD_HEARTBEAT_INTERVAL_MIN ||
-		    msg->heartbeat_interval > QNETD_HEARTBEAT_INTERVAL_MAX) {
+		if (msg->heartbeat_interval < instance->advanced_settings->heartbeat_interval_min ||
+		    msg->heartbeat_interval > instance->advanced_settings->heartbeat_interval_max) {
 			qnetd_log(LOG_ERR, "Client requested invalid heartbeat interval %u. "
 			    "Sending error reply.", msg->heartbeat_interval);
 
@@ -478,7 +478,8 @@ qnetd_client_msg_received_init(struct qnetd_instance *instance, struct qnetd_cli
 	if (msg_create_init_reply(&send_buffer->buffer, msg->seq_number_set, msg->seq_number,
 	    reply_error_code,
 	    supported_msgs, no_supported_msgs, supported_opts, no_supported_opts,
-	    instance->max_client_receive_size, instance->max_client_send_size,
+	    instance->advanced_settings->max_client_receive_size,
+	    instance->advanced_settings->max_client_send_size,
 	    qnetd_static_supported_decision_algorithms,
 	    QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE) == -1) {
 		qnetd_log(LOG_ERR, "Can't alloc init reply msg. Disconnecting client connection.");
@@ -536,8 +537,8 @@ qnetd_client_msg_received_set_option(struct qnetd_instance *instance, struct qne
 		/*
 		 * Check if heartbeat interval is valid
 		 */
-		if (msg->heartbeat_interval < QNETD_HEARTBEAT_INTERVAL_MIN ||
-		    msg->heartbeat_interval > QNETD_HEARTBEAT_INTERVAL_MAX) {
+		if (msg->heartbeat_interval < instance->advanced_settings->heartbeat_interval_min ||
+		    msg->heartbeat_interval > instance->advanced_settings->heartbeat_interval_max) {
 			qnetd_log(LOG_ERR, "Client requested invalid heartbeat interval %u. "
 			    "Sending error reply.", msg->heartbeat_interval);
 

+ 3 - 2
qdevices/qnetd-client-net.c

@@ -229,8 +229,9 @@ qnetd_client_net_accept(struct qnetd_instance *instance)
 
 	client = qnetd_client_list_add(&instance->clients, client_socket, &client_addr,
 	    client_addr_str,
-	    instance->max_client_receive_size, instance->max_client_send_buffers,
-	    instance->max_client_send_size, &instance->main_timer_list);
+	    instance->advanced_settings->max_client_receive_size,
+	    instance->advanced_settings->max_client_send_buffers,
+	    instance->advanced_settings->max_client_send_size, &instance->main_timer_list);
 	if (client == NULL) {
 		qnetd_log(LOG_ERR, "Can't add client to list");
 		res_err = -2;

+ 4 - 3
qdevices/qnetd-dpd-timer.c

@@ -48,7 +48,7 @@ qnetd_dpd_timer_cb(void *data1, void *data2)
 			continue;
 		}
 
-		client->dpd_time_since_last_check += QNETD_DPD_INTERVAL;
+		client->dpd_time_since_last_check += instance->advanced_settings->dpd_interval;
 
 		if (client->dpd_time_since_last_check > (client->heartbeat_interval * 2)) {
 			if (!client->dpd_msg_received_since_last_check) {
@@ -71,11 +71,12 @@ int
 qnetd_dpd_timer_init(struct qnetd_instance *instance)
 {
 
-	if (!QNETD_DPD_ENABLED) {
+	if (!instance->advanced_settings->dpd_enabled) {
 		return (0);
 	}
 
-	instance->dpd_timer = timer_list_add(&instance->main_timer_list, QNETD_DPD_INTERVAL,
+	instance->dpd_timer = timer_list_add(&instance->main_timer_list,
+	    instance->advanced_settings->dpd_interval,
 	    qnetd_dpd_timer_cb, (void *)instance, NULL);
 	if (instance->dpd_timer == NULL) {
 		qnetd_log(LOG_ERR, "Can't initialize dpd timer");

+ 7 - 8
qdevices/qnetd-instance.c

@@ -44,21 +44,19 @@
 #include "qnetd-client-algo-timer.h"
 
 int
-qnetd_instance_init(struct qnetd_instance *instance, size_t max_client_receive_size,
-    size_t max_client_send_buffers, size_t max_client_send_size,
-    enum tlv_tls_supported tls_supported, int tls_client_cert_required, size_t max_clients)
+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)
 {
 
 	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->max_client_receive_size = max_client_receive_size;
-	instance->max_client_send_buffers = max_client_send_buffers;
-	instance->max_client_send_size = max_client_send_size;
-
 	instance->tls_supported = tls_supported;
 	instance->tls_client_cert_required = tls_client_cert_required;
 
@@ -121,7 +119,8 @@ int
 qnetd_instance_init_certs(struct qnetd_instance *instance)
 {
 
-	instance->server.cert = PK11_FindCertFromNickname(QNETD_CERT_NICKNAME, NULL);
+	instance->server.cert = PK11_FindCertFromNickname(
+	    instance->advanced_settings->cert_nickname, NULL);
 	if (instance->server.cert == NULL) {
 		return (-1);
 	}

+ 4 - 5
qdevices/qnetd-instance.h

@@ -47,6 +47,7 @@
 #include "qnet-config.h"
 #include "timer-list.h"
 #include "unix-socket-ipc.h"
+#include "qnetd-advanced-settings.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -58,9 +59,6 @@ struct qnetd_instance {
 		CERTCertificate *cert;
 		SECKEYPrivateKey *private_key;
 	} server;
-	size_t max_client_receive_size;
-	size_t max_client_send_buffers;
-	size_t max_client_send_size;
 	size_t max_clients;
 	struct qnetd_client_list clients;
 	struct qnetd_cluster_list clusters;
@@ -73,11 +71,12 @@ struct qnetd_instance {
 	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;
 };
 
 extern int		qnetd_instance_init(struct qnetd_instance *instance,
-    size_t max_client_receive_size, size_t max_client_send_buffers, size_t max_client_send_size,
-    enum tlv_tls_supported tls_supported, int tls_client_cert_required, size_t max_clients);
+    enum tlv_tls_supported tls_supported, int tls_client_cert_required, size_t max_clients,
+    struct qnetd_advanced_settings *advanced_settings);
 
 extern int		qnetd_instance_destroy(struct qnetd_instance *instance);
 

+ 2 - 1
qdevices/qnetd-ipc-cmd.c

@@ -75,7 +75,8 @@ qnetd_ipc_cmd_status(struct qnetd_instance *instance, struct dynar *outbuf, int
 	}
 
 	if (dynar_str_catf(outbuf, "Maximum send/receive size:\t%zu/%zu bytes\n",
-	    instance->max_client_send_size, instance->max_client_receive_size) == -1) {
+	    instance->advanced_settings->max_client_send_size,
+	    instance->advanced_settings->max_client_receive_size) == -1) {
 		return (-1);
 	}
 

+ 6 - 3
qdevices/qnetd-ipc.c

@@ -49,9 +49,12 @@ int
 qnetd_ipc_init(struct qnetd_instance *instance)
 {
 
-	if (unix_socket_ipc_init(&instance->local_ipc, QNETD_LOCAL_SOCKET_FILE,
-	    QNETD_LOCAL_SOCKET_BACKLOG, QNETD_IPC_MAX_CLIENTS, QNETD_IPC_MAX_RECEIVE_SIZE,
-	    QNETD_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) {
 		qnetd_log_err(LOG_ERR, "Can't create unix socket");
 
 		return (-1);

+ 109 - 0
qdevices/test-dynar-getopt-lex.c

@@ -0,0 +1,109 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "dynar.h"
+#include "dynar-str.h"
+#include "dynar-getopt-lex.h"
+
+int
+main(void)
+{
+	struct dynar input_str;
+	struct dynar_getopt_lex lex;
+
+	dynar_init(&input_str, 128);
+
+	assert(dynar_str_catf(&input_str, "option=value") != -1);
+	dynar_getopt_lex_init(&lex, &input_str);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "") == 0);
+	assert(strcmp(dynar_data(&lex.value), "") == 0);
+	dynar_getopt_lex_destroy(&lex);
+
+	assert(dynar_str_cpy(&input_str, "") == 0);
+	assert(dynar_str_catf(&input_str, "option1=value1,option2=value2") != -1);
+	dynar_getopt_lex_init(&lex, &input_str);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option1") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value1") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option2") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value2") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "") == 0);
+	assert(strcmp(dynar_data(&lex.value), "") == 0);
+	dynar_getopt_lex_destroy(&lex);
+
+	assert(dynar_str_cpy(&input_str, "") == 0);
+	assert(dynar_str_catf(&input_str, "option1=value1,option2=value2,option3=value3") != -1);
+	dynar_getopt_lex_init(&lex, &input_str);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option1") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value1") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option2") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value2") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option3") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value3") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "") == 0);
+	assert(strcmp(dynar_data(&lex.value), "") == 0);
+	dynar_getopt_lex_destroy(&lex);
+
+	assert(dynar_str_cpy(&input_str, "") == 0);
+	assert(dynar_str_catf(&input_str, "option1,option2=value2") != -1);
+	dynar_getopt_lex_init(&lex, &input_str);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option1") == 0);
+	assert(strcmp(dynar_data(&lex.value), "") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "option2") == 0);
+	assert(strcmp(dynar_data(&lex.value), "value2") == 0);
+	assert(dynar_getopt_lex_token_next(&lex) == 0);
+	assert(strcmp(dynar_data(&lex.option), "") == 0);
+	assert(strcmp(dynar_data(&lex.value), "") == 0);
+	dynar_getopt_lex_destroy(&lex);
+
+	dynar_destroy(&input_str);
+
+	return (0);
+}