2 * Copyright (c) 2015-2020 Red Hat, Inc.
6 * Author: Jan Friesse (jfriesse@redhat.com)
8 * This software licensed under BSD license, the text of which follows:
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
42 #include "qnet-config.h"
45 #include "dynar-str.h"
46 #include "dynar-getopt-lex.h"
49 #include "pr-poll-array.h"
50 #include "qnetd-advanced-settings.h"
51 #include "qnetd-algorithm.h"
52 #include "qnetd-instance.h"
53 #include "qnetd-ipc.h"
54 #include "qnetd-client-net.h"
55 #include "qnetd-client-msg-received.h"
59 #ifdef HAVE_LIBSYSTEMD
60 #include <systemd/sd-daemon.h>
64 * This is global variable used for comunication with main loop and signal (calls close)
66 struct qnetd_instance
*global_instance
;
68 enum tlv_decision_algorithm_type
69 qnetd_static_supported_decision_algorithms
[QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE
] = {
70 TLV_DECISION_ALGORITHM_TYPE_TEST
,
71 TLV_DECISION_ALGORITHM_TYPE_FFSPLIT
,
72 TLV_DECISION_ALGORITHM_TYPE_2NODELMS
,
73 TLV_DECISION_ALGORITHM_TYPE_LMS
,
80 log_nss(LOG_CRIT
, "NSS error");
89 log_nss(LOG_WARNING
, "NSS warning");
93 server_socket_poll_loop_read_cb(PRFileDesc
*prfd
, const PRPollDesc
*pd
, void *user_data1
, void *user_data2
)
95 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
97 qnetd_client_net_accept(instance
);
103 server_socket_poll_loop_err_cb(PRFileDesc
*prfd
, short revents
, const PRPollDesc
*pd
,
104 void *user_data1
, void *user_data2
)
107 if (revents
!= POLLNVAL
) {
109 * Poll ERR on listening socket is fatal error.
110 * POLL_NVAL is used as a signal to quit poll loop.
112 log(LOG_CRIT
, "POLL_ERR (%u) on listening socket", revents
);
114 log(LOG_DEBUG
, "Listening socket is closed");
121 signal_int_handler(int sig
)
124 log(LOG_DEBUG
, "SIGINT received - closing server IPC socket");
126 qnetd_ipc_close(global_instance
);
130 signal_term_handler(int sig
)
133 log(LOG_DEBUG
, "SIGTERM received - closing server IPC socket");
135 qnetd_ipc_close(global_instance
);
139 signal_handlers_register(void)
141 struct sigaction act
;
143 act
.sa_handler
= signal_int_handler
;
144 sigemptyset(&act
.sa_mask
);
145 act
.sa_flags
= SA_RESTART
;
147 sigaction(SIGINT
, &act
, NULL
);
149 act
.sa_handler
= signal_term_handler
;
150 sigemptyset(&act
.sa_mask
);
151 act
.sa_flags
= SA_RESTART
;
153 sigaction(SIGTERM
, &act
, NULL
);
157 qnetd_run_main_loop(struct qnetd_instance
*instance
)
161 while ((poll_res
= pr_poll_loop_exec(&instance
->main_poll_loop
)) == 0) {
164 if (poll_res
== -2) {
165 log(LOG_CRIT
, "pr_poll_loop_exec returned -2 - internal error");
167 } else if (poll_res
== -3) {
168 log_nss(LOG_CRIT
, "pr_poll_loop_exec returned -3 - PR_Poll error");
172 return (qnetd_ipc_is_closed(instance
) ? 0 : -1);
179 printf("usage: %s [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME
);
180 printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]\n", "");
184 display_version(void)
186 enum msg_type
*supported_messages
;
187 size_t no_supported_messages
;
190 msg_get_supported_messages(&supported_messages
, &no_supported_messages
);
191 printf("Corosync Qdevice Network Daemon, version '%s'\n\n", VERSION
);
192 printf("Supported algorithms: ");
193 for (zi
= 0; zi
< QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE
; zi
++) {
198 tlv_decision_algorithm_type_to_str(qnetd_static_supported_decision_algorithms
[zi
]),
199 qnetd_static_supported_decision_algorithms
[zi
]);
202 printf("Supported message types: ");
203 for (zi
= 0; zi
< no_supported_messages
; zi
++) {
207 printf("%s (%u)", msg_type_to_str(supported_messages
[zi
]), supported_messages
[zi
]);
213 cli_parse_long_opt(struct qnetd_advanced_settings
*advanced_settings
, const char *long_opt
)
215 struct dynar_getopt_lex lex
;
216 struct dynar dynar_long_opt
;
221 dynar_init(&dynar_long_opt
, strlen(long_opt
) + 1);
222 if (dynar_str_cpy(&dynar_long_opt
, long_opt
) != 0) {
223 errx(EXIT_FAILURE
, "Can't alloc memory for long option");
226 dynar_getopt_lex_init(&lex
, &dynar_long_opt
);
228 while (dynar_getopt_lex_token_next(&lex
) == 0 && strcmp(dynar_data(&lex
.option
), "") != 0) {
229 opt
= dynar_data(&lex
.option
);
230 val
= dynar_data(&lex
.value
);
232 res
= qnetd_advanced_settings_set(advanced_settings
, opt
, val
);
235 errx(EXIT_FAILURE
, "Unknown option '%s'", opt
);
238 errx(EXIT_FAILURE
, "Invalid value '%s' for option '%s'", val
, opt
);
241 warnx("Option '%s' is deprecated and has no effect anymore", opt
);
246 dynar_getopt_lex_destroy(&lex
);
247 dynar_destroy(&dynar_long_opt
);
251 cli_parse(int argc
, char * const argv
[], char **host_addr
, uint16_t *host_port
, int *foreground
,
252 int *debug_log
, int *bump_log_priority
, enum tlv_tls_supported
*tls_supported
,
253 int *client_cert_required
, size_t *max_clients
, PRIntn
*address_family
,
254 struct qnetd_advanced_settings
*advanced_settings
)
260 *host_port
= QNETD_DEFAULT_HOST_PORT
;
263 *bump_log_priority
= 0;
264 *tls_supported
= QNETD_DEFAULT_TLS_SUPPORTED
;
265 *client_cert_required
= QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED
;
266 *max_clients
= QNETD_DEFAULT_MAX_CLIENTS
;
267 *address_family
= PR_AF_UNSPEC
;
269 while ((ch
= getopt(argc
, argv
, "46dfhvc:l:m:p:S:s:")) != -1) {
272 *address_family
= PR_AF_INET
;
275 *address_family
= PR_AF_INET6
;
282 *bump_log_priority
= 1;
287 if ((*client_cert_required
= utils_parse_bool_str(optarg
)) == -1) {
288 errx(EXIT_FAILURE
, "client_cert_required should be on/yes/1, off/no/0");
295 if (utils_strtonum(optarg
, 0, LLONG_MAX
, &tmpll
) == -1) {
296 errx(EXIT_FAILURE
, "max clients value %s is invalid", optarg
);
299 *max_clients
= (size_t)tmpll
;
302 if (utils_strtonum(optarg
, 1, UINT16_MAX
, &tmpll
) == -1) {
303 errx(EXIT_FAILURE
, "host port must be in range 1-%u", UINT16_MAX
);
309 cli_parse_long_opt(advanced_settings
, optarg
);
312 if (strcasecmp(optarg
, "on") == 0) {
313 *tls_supported
= QNETD_DEFAULT_TLS_SUPPORTED
;
314 } else if (strcasecmp(optarg
, "off") == 0) {
315 *tls_supported
= TLV_TLS_UNSUPPORTED
;
316 } else if (strcasecmp(optarg
, "req") == 0) {
317 *tls_supported
= TLV_TLS_REQUIRED
;
319 errx(EXIT_FAILURE
, "tls must be one of on, off, req");
336 main(int argc
, char * const argv
[])
338 struct qnetd_instance instance
;
339 struct qnetd_advanced_settings advanced_settings
;
344 int bump_log_priority
;
345 enum tlv_tls_supported tls_supported
;
346 int client_cert_required
;
348 PRIntn address_family
;
350 int another_instance_running
;
354 if (qnetd_advanced_settings_init(&advanced_settings
) != 0) {
355 errx(EXIT_FAILURE
, "Can't alloc memory for advanced settings");
358 cli_parse(argc
, argv
, &host_addr
, &host_port
, &foreground
, &debug_log
, &bump_log_priority
,
359 &tls_supported
, &client_cert_required
, &max_clients
, &address_family
, &advanced_settings
);
361 log_target
= LOG_TARGET_SYSLOG
;
363 log_target
|= LOG_TARGET_STDERR
;
366 if (log_init(QNETD_PROGRAM_NAME
, log_target
, LOG_DAEMON
) == -1) {
367 errx(EXIT_FAILURE
, "Can't initialize logging");
370 log_set_debug(debug_log
);
371 log_set_priority_bump(bump_log_priority
);
374 * Check that it's possible to open NSS dir if needed
376 if (nss_sock_check_db_dir((tls_supported
!= TLV_TLS_UNSUPPORTED
?
377 advanced_settings
.nss_db_dir
: NULL
)) != 0) {
378 log_err(LOG_ERR
, "Can't open NSS DB directory");
380 return (EXIT_FAILURE
);
390 if ((lock_file
= utils_flock(advanced_settings
.lock_file
, getpid(),
391 &another_instance_running
)) == -1) {
392 if (another_instance_running
) {
393 log(LOG_ERR
, "Another instance is running");
395 log_err(LOG_ERR
, "Can't acquire lock");
398 return (EXIT_FAILURE
);
401 log(LOG_DEBUG
, "Initializing nss");
402 if (nss_sock_init_nss((tls_supported
!= TLV_TLS_UNSUPPORTED
?
403 advanced_settings
.nss_db_dir
: NULL
)) != 0) {
407 if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL
) != SECSuccess
) {
411 if (qnetd_instance_init(&instance
, tls_supported
, client_cert_required
,
412 max_clients
, &advanced_settings
) == -1) {
413 log(LOG_ERR
, "Can't initialize qnetd");
414 return (EXIT_FAILURE
);
416 instance
.host_addr
= host_addr
;
417 instance
.host_port
= host_port
;
419 if (tls_supported
!= TLV_TLS_UNSUPPORTED
&& qnetd_instance_init_certs(&instance
) == -1) {
423 log(LOG_DEBUG
, "Initializing local socket");
424 if (qnetd_ipc_init(&instance
) != 0) {
425 return (EXIT_FAILURE
);
428 log(LOG_DEBUG
, "Creating listening socket");
429 instance
.server
.socket
= nss_sock_create_listen_socket(instance
.host_addr
,
430 instance
.host_port
, address_family
);
431 if (instance
.server
.socket
== NULL
) {
435 if (nss_sock_set_non_blocking(instance
.server
.socket
) != 0) {
439 if (PR_Listen(instance
.server
.socket
, instance
.advanced_settings
->listen_backlog
) !=
444 if (pr_poll_loop_add_prfd(&instance
.main_poll_loop
, instance
.server
.socket
, POLLIN
,
446 server_socket_poll_loop_read_cb
,
448 server_socket_poll_loop_err_cb
,
449 &instance
, NULL
) != 0) {
450 log(LOG_ERR
, "Can't add server socket to main poll loop");
452 return (EXIT_FAILURE
);
455 global_instance
= &instance
;
456 signal_handlers_register();
458 log(LOG_DEBUG
, "Registering algorithms");
459 if (qnetd_algorithm_register_all() != 0) {
460 return (EXIT_FAILURE
);
463 log(LOG_DEBUG
, "QNetd ready to provide service");
465 #ifdef HAVE_LIBSYSTEMD
466 sd_notify(0, "READY=1");
469 log(LOG_DEBUG
, "Running QNetd main loop");
470 main_loop_res
= qnetd_run_main_loop(&instance
);
475 log(LOG_DEBUG
, "Destroying qnetd ipc");
476 qnetd_ipc_destroy(&instance
);
478 log(LOG_DEBUG
, "Closing server socket");
479 if (PR_Close(instance
.server
.socket
) != PR_SUCCESS
) {
483 CERT_DestroyCertificate(instance
.server
.cert
);
484 SECKEY_DestroyPrivateKey(instance
.server
.private_key
);
486 SSL_ClearSessionCache();
488 SSL_ShutdownServerSessionIDCache();
490 qnetd_instance_destroy(&instance
);
492 qnetd_advanced_settings_destroy(&advanced_settings
);
494 if (NSS_Shutdown() != SECSuccess
) {
498 if (PR_Cleanup() != PR_SUCCESS
) {
502 log(LOG_DEBUG
, "Closing log");
505 return (main_loop_res
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);