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
, 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_write_cb(PRFileDesc
*prfd
, void *user_data1
, void *user_data2
)
107 * Poll write on listen socket -> fatal error
109 log(LOG_CRIT
, "POLL_WRITE on listening socket");
115 server_socket_poll_loop_err_cb(PRFileDesc
*prfd
, short revents
, void *user_data1
, void *user_data2
)
118 if (revents
!= POLLNVAL
) {
120 * Poll ERR on listening socket is fatal error.
121 * POLL_NVAL is used as a signal to quit poll loop.
123 log(LOG_CRIT
, "POLL_ERR (%u) on listening socket", revents
);
125 log(LOG_DEBUG
, "Listening socket is closed");
132 signal_int_handler(int sig
)
135 log(LOG_DEBUG
, "SIGINT received - closing server IPC socket");
137 qnetd_ipc_close(global_instance
);
141 signal_term_handler(int sig
)
144 log(LOG_DEBUG
, "SIGTERM received - closing server IPC socket");
146 qnetd_ipc_close(global_instance
);
150 signal_handlers_register(void)
152 struct sigaction act
;
154 act
.sa_handler
= signal_int_handler
;
155 sigemptyset(&act
.sa_mask
);
156 act
.sa_flags
= SA_RESTART
;
158 sigaction(SIGINT
, &act
, NULL
);
160 act
.sa_handler
= signal_term_handler
;
161 sigemptyset(&act
.sa_mask
);
162 act
.sa_flags
= SA_RESTART
;
164 sigaction(SIGTERM
, &act
, NULL
);
171 printf("usage: %s [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME
);
172 printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]\n", "");
176 display_version(void)
178 enum msg_type
*supported_messages
;
179 size_t no_supported_messages
;
182 msg_get_supported_messages(&supported_messages
, &no_supported_messages
);
183 printf("Corosync Qdevice Network Daemon, version '%s'\n\n", VERSION
);
184 printf("Supported algorithms: ");
185 for (zi
= 0; zi
< QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE
; zi
++) {
190 tlv_decision_algorithm_type_to_str(qnetd_static_supported_decision_algorithms
[zi
]),
191 qnetd_static_supported_decision_algorithms
[zi
]);
194 printf("Supported message types: ");
195 for (zi
= 0; zi
< no_supported_messages
; zi
++) {
199 printf("%s (%u)", msg_type_to_str(supported_messages
[zi
]), supported_messages
[zi
]);
205 cli_parse_long_opt(struct qnetd_advanced_settings
*advanced_settings
, const char *long_opt
)
207 struct dynar_getopt_lex lex
;
208 struct dynar dynar_long_opt
;
213 dynar_init(&dynar_long_opt
, strlen(long_opt
) + 1);
214 if (dynar_str_cpy(&dynar_long_opt
, long_opt
) != 0) {
215 errx(1, "Can't alloc memory for long option");
218 dynar_getopt_lex_init(&lex
, &dynar_long_opt
);
220 while (dynar_getopt_lex_token_next(&lex
) == 0 && strcmp(dynar_data(&lex
.option
), "") != 0) {
221 opt
= dynar_data(&lex
.option
);
222 val
= dynar_data(&lex
.value
);
224 res
= qnetd_advanced_settings_set(advanced_settings
, opt
, val
);
227 errx(1, "Unknown option '%s'", opt
);
230 errx(1, "Invalid value '%s' for option '%s'", val
, opt
);
235 dynar_getopt_lex_destroy(&lex
);
236 dynar_destroy(&dynar_long_opt
);
240 cli_parse(int argc
, char * const argv
[], char **host_addr
, uint16_t *host_port
, int *foreground
,
241 int *debug_log
, int *bump_log_priority
, enum tlv_tls_supported
*tls_supported
,
242 int *client_cert_required
, size_t *max_clients
, PRIntn
*address_family
,
243 struct qnetd_advanced_settings
*advanced_settings
)
249 *host_port
= QNETD_DEFAULT_HOST_PORT
;
252 *bump_log_priority
= 0;
253 *tls_supported
= QNETD_DEFAULT_TLS_SUPPORTED
;
254 *client_cert_required
= QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED
;
255 *max_clients
= QNETD_DEFAULT_MAX_CLIENTS
;
256 *address_family
= PR_AF_UNSPEC
;
258 while ((ch
= getopt(argc
, argv
, "46dfhvc:l:m:p:S:s:")) != -1) {
261 *address_family
= PR_AF_INET
;
264 *address_family
= PR_AF_INET6
;
271 *bump_log_priority
= 1;
276 if ((*client_cert_required
= utils_parse_bool_str(optarg
)) == -1) {
277 errx(1, "client_cert_required should be on/yes/1, off/no/0");
282 *host_addr
= strdup(optarg
);
283 if (*host_addr
== NULL
) {
284 errx(1, "Can't alloc memory for host addr string");
288 if (utils_strtonum(optarg
, 0, LLONG_MAX
, &tmpll
) == -1) {
289 errx(1, "max clients value %s is invalid", optarg
);
292 *max_clients
= (size_t)tmpll
;
295 if (utils_strtonum(optarg
, 1, UINT16_MAX
, &tmpll
) == -1) {
296 errx(1, "host port must be in range 1-%u", UINT16_MAX
);
302 cli_parse_long_opt(advanced_settings
, optarg
);
305 if (strcasecmp(optarg
, "on") == 0) {
306 *tls_supported
= QNETD_DEFAULT_TLS_SUPPORTED
;
307 } else if (strcasecmp(optarg
, "off") == 0) {
308 *tls_supported
= TLV_TLS_UNSUPPORTED
;
309 } else if (strcasecmp(optarg
, "req") == 0) {
310 *tls_supported
= TLV_TLS_REQUIRED
;
312 errx(1, "tls must be one of on, off, req");
329 main(int argc
, char * const argv
[])
331 struct qnetd_instance instance
;
332 struct qnetd_advanced_settings advanced_settings
;
337 int bump_log_priority
;
338 enum tlv_tls_supported tls_supported
;
339 int client_cert_required
;
341 PRIntn address_family
;
343 int another_instance_running
;
347 if (qnetd_advanced_settings_init(&advanced_settings
) != 0) {
348 errx(1, "Can't alloc memory for advanced settings");
351 cli_parse(argc
, argv
, &host_addr
, &host_port
, &foreground
, &debug_log
, &bump_log_priority
,
352 &tls_supported
, &client_cert_required
, &max_clients
, &address_family
, &advanced_settings
);
354 log_target
= LOG_TARGET_SYSLOG
;
356 log_target
|= LOG_TARGET_STDERR
;
359 if (log_init(QNETD_PROGRAM_NAME
, log_target
, LOG_DAEMON
) == -1) {
360 errx(1, "Can't initialize logging");
363 log_set_debug(debug_log
);
364 log_set_priority_bump(bump_log_priority
);
367 * Check that it's possible to open NSS dir if needed
369 if (nss_sock_check_db_dir((tls_supported
!= TLV_TLS_UNSUPPORTED
?
370 advanced_settings
.nss_db_dir
: NULL
)) != 0) {
371 log_err(LOG_ERR
, "Can't open NSS DB directory");
383 if ((lock_file
= utils_flock(advanced_settings
.lock_file
, getpid(),
384 &another_instance_running
)) == -1) {
385 if (another_instance_running
) {
386 log(LOG_ERR
, "Another instance is running");
388 log_err(LOG_ERR
, "Can't acquire lock");
394 log(LOG_DEBUG
, "Initializing nss");
395 if (nss_sock_init_nss((tls_supported
!= TLV_TLS_UNSUPPORTED
?
396 advanced_settings
.nss_db_dir
: NULL
)) != 0) {
400 if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL
) != SECSuccess
) {
404 if (qnetd_instance_init(&instance
, tls_supported
, client_cert_required
,
405 max_clients
, &advanced_settings
) == -1) {
406 log(LOG_ERR
, "Can't initialize qnetd");
409 instance
.host_addr
= host_addr
;
410 instance
.host_port
= host_port
;
412 if (tls_supported
!= TLV_TLS_UNSUPPORTED
&& qnetd_instance_init_certs(&instance
) == -1) {
416 log(LOG_DEBUG
, "Initializing local socket");
417 if (qnetd_ipc_init(&instance
) != 0) {
421 log(LOG_DEBUG
, "Creating listening socket");
422 instance
.server
.socket
= nss_sock_create_listen_socket(instance
.host_addr
,
423 instance
.host_port
, address_family
);
424 if (instance
.server
.socket
== NULL
) {
428 if (nss_sock_set_non_blocking(instance
.server
.socket
) != 0) {
432 if (PR_Listen(instance
.server
.socket
, instance
.advanced_settings
->listen_backlog
) !=
437 if (pr_poll_loop_add_prfd(&instance
.main_poll_loop
, instance
.server
.socket
, POLLIN
,
439 server_socket_poll_loop_read_cb
,
440 server_socket_poll_loop_write_cb
,
441 server_socket_poll_loop_err_cb
,
442 &instance
, NULL
) != 0) {
443 log(LOG_ERR
, "Can't add server socket to main poll loop");
448 global_instance
= &instance
;
449 signal_handlers_register();
451 log(LOG_DEBUG
, "Registering algorithms");
452 if (qnetd_algorithm_register_all() != 0) {
456 log(LOG_DEBUG
, "QNetd ready to provide service");
458 #ifdef HAVE_LIBSYSTEMD
459 sd_notify(0, "READY=1");
465 while ((poll_res
= pr_poll_loop_exec(&instance
.main_poll_loop
)) == 0) {
468 if (poll_res
== -2) {
469 log(LOG_CRIT
, "pr_poll_loop_exec returned -2 - internal error");
476 log(LOG_DEBUG
, "Destroying qnetd ipc");
477 qnetd_ipc_destroy(&instance
);
479 log(LOG_DEBUG
, "Closing server socket");
480 if (PR_Close(instance
.server
.socket
) != PR_SUCCESS
) {
484 CERT_DestroyCertificate(instance
.server
.cert
);
485 SECKEY_DestroyPrivateKey(instance
.server
.private_key
);
487 SSL_ClearSessionCache();
489 SSL_ShutdownServerSessionIDCache();
491 qnetd_instance_destroy(&instance
);
493 qnetd_advanced_settings_destroy(&advanced_settings
);
495 if (NSS_Shutdown() != SECSuccess
) {
499 if (PR_Cleanup() != PR_SUCCESS
) {
503 log(LOG_DEBUG
, "Closing log");