]> git.proxmox.com Git - mirror_corosync-qdevice.git/blame - qdevices/corosync-qnetd.c
init: Fix init scripts to work with containers
[mirror_corosync-qdevice.git] / qdevices / corosync-qnetd.c
CommitLineData
9a1955a7
JF
1/*
2 * Copyright (c) 2015-2016 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
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.
21 *
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.
33 */
34
35#include <err.h>
36#include <errno.h>
37#include <getopt.h>
3b21d758 38#include <limits.h>
9a1955a7
JF
39#include <signal.h>
40#include <unistd.h>
41
42#include "qnet-config.h"
43
44#include "dynar.h"
45#include "dynar-str.h"
46#include "dynar-getopt-lex.h"
47#include "nss-sock.h"
48#include "pr-poll-array.h"
49#include "qnetd-advanced-settings.h"
50#include "qnetd-algorithm.h"
51#include "qnetd-instance.h"
52#include "qnetd-ipc.h"
53#include "qnetd-log.h"
54#include "qnetd-client-net.h"
55#include "qnetd-client-msg-received.h"
56#include "qnetd-poll-array-user-data.h"
57#include "utils.h"
58#include "msg.h"
59
60#ifdef HAVE_LIBSYSTEMD
61#include <systemd/sd-daemon.h>
62#endif
63
64/*
65 * This is global variable used for comunication with main loop and signal (calls close)
66 */
67struct qnetd_instance *global_instance;
68
69enum tlv_decision_algorithm_type
70 qnetd_static_supported_decision_algorithms[QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE] = {
71 TLV_DECISION_ALGORITHM_TYPE_TEST,
72 TLV_DECISION_ALGORITHM_TYPE_FFSPLIT,
73 TLV_DECISION_ALGORITHM_TYPE_2NODELMS,
74 TLV_DECISION_ALGORITHM_TYPE_LMS,
75};
76
77static void
78qnetd_err_nss(void)
79{
80
81 qnetd_log_nss(LOG_CRIT, "NSS error");
82
83 exit(1);
84}
85
86static void
87qnetd_warn_nss(void)
88{
89
90 qnetd_log_nss(LOG_WARNING, "NSS warning");
91}
92
93static PRPollDesc *
94qnetd_pr_poll_array_create(struct qnetd_instance *instance)
95{
96 struct pr_poll_array *poll_array;
97 const struct qnetd_client_list *client_list;
98 struct qnetd_client *client;
99 PRPollDesc *poll_desc;
100 struct qnetd_poll_array_user_data *user_data;
101 const struct unix_socket_client_list *ipc_client_list;
102 struct unix_socket_client *ipc_client;
103
104 poll_array = &instance->poll_array;
105 client_list = &instance->clients;
106 ipc_client_list = &instance->local_ipc.clients;
107
108 pr_poll_array_clean(poll_array);
109
110 if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
111 return (NULL);
112 }
113
114 poll_desc->fd = instance->server.socket;
115 poll_desc->in_flags = PR_POLL_READ;
116
117 user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET;
118
119 if (qnetd_ipc_is_closed(instance)) {
120 qnetd_log(LOG_DEBUG, "Listening socket is closed");
121
122 return (NULL);
123 }
124
125 if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
126 return (NULL);
127 }
128
129 poll_desc->fd = instance->ipc_socket_poll_fd;
130 poll_desc->in_flags = PR_POLL_READ;
131 user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET;
132
133 TAILQ_FOREACH(client, client_list, entries) {
134 if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
135 return (NULL);
136 }
137 poll_desc->fd = client->socket;
138 poll_desc->in_flags = PR_POLL_READ;
139
140 if (!send_buffer_list_empty(&client->send_buffer_list)) {
141 poll_desc->in_flags |= PR_POLL_WRITE;
142 }
143
144 user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT;
145 user_data->client = client;
146 }
147
148 TAILQ_FOREACH(ipc_client, ipc_client_list, entries) {
149 if (!ipc_client->reading_line && !ipc_client->writing_buffer) {
150 continue;
151 }
152
153 if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
154 return (NULL);
155 }
156
157 poll_desc->fd = ((struct qnetd_ipc_user_data *)ipc_client->user_data)->nspr_poll_fd;
158 if (ipc_client->reading_line) {
159 poll_desc->in_flags |= PR_POLL_READ;
160 }
161
162 if (ipc_client->writing_buffer) {
163 poll_desc->in_flags |= PR_POLL_WRITE;
164 }
165
166 user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT;
167 user_data->ipc_client = ipc_client;
168 }
169
170 pr_poll_array_gc(poll_array);
171
172 return (poll_array->array);
173}
174
175static int
176qnetd_poll(struct qnetd_instance *instance)
177{
178 struct qnetd_client *client;
179 PRPollDesc *pfds;
180 PRInt32 poll_res;
181 ssize_t i;
182 int client_disconnect;
183 struct qnetd_poll_array_user_data *user_data;
184 struct unix_socket_client *ipc_client;
185
186 client = NULL;
187 client_disconnect = 0;
188
189 pfds = qnetd_pr_poll_array_create(instance);
190 if (pfds == NULL) {
191 return (-1);
192 }
193
194 if ((poll_res = PR_Poll(pfds, pr_poll_array_size(&instance->poll_array),
195 timer_list_time_to_expire(&instance->main_timer_list))) >= 0) {
196 timer_list_expire(&instance->main_timer_list);
197
198 /*
199 * Walk thru pfds array and process events
200 */
201 for (i = 0; i < pr_poll_array_size(&instance->poll_array); i++) {
202 user_data = pr_poll_array_get_user_data(&instance->poll_array, i);
203
204 client = NULL;
205 ipc_client = NULL;
206 client_disconnect = 0;
207
208 switch (user_data->type) {
209 case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
210 break;
211 case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
212 client = user_data->client;
213 client_disconnect = client->schedule_disconnect;
214 break;
215 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
216 break;
217 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
218 ipc_client = user_data->ipc_client;
219 client_disconnect = ipc_client->schedule_disconnect;
220 }
221
222 if (!client_disconnect && poll_res > 0 &&
223 pfds[i].out_flags & PR_POLL_READ) {
224 switch (user_data->type) {
225 case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
226 qnetd_client_net_accept(instance);
227 break;
228 case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
229 if (qnetd_client_net_read(instance, client) == -1) {
230 client_disconnect = 1;
231 }
232 break;
233 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
234 qnetd_ipc_accept(instance, &ipc_client);
235 break;
236 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
237 qnetd_ipc_io_read(instance, ipc_client);
238 break;
239 }
240 }
241
242 if (!client_disconnect && poll_res > 0 &&
243 pfds[i].out_flags & PR_POLL_WRITE) {
244 switch (user_data->type) {
245 case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
246 /*
247 * Poll write on listen socket -> fatal error
248 */
249 qnetd_log(LOG_CRIT, "POLL_WRITE on listening socket");
250
251 return (-1);
252 break;
253 case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
254 if (qnetd_client_net_write(instance, client) == -1) {
255 client_disconnect = 1;
256 }
257 break;
258 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
259 qnetd_log(LOG_CRIT, "POLL_WRITE on listening IPC socket");
260 return (-1);
261 break;
262 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
263 qnetd_ipc_io_write(instance, ipc_client);
264 break;
265 }
266 }
267
268 if (!client_disconnect && poll_res > 0 &&
269 (pfds[i].out_flags & (PR_POLL_ERR|PR_POLL_NVAL|PR_POLL_HUP|PR_POLL_EXCEPT)) &&
270 !(pfds[i].out_flags & (PR_POLL_READ|PR_POLL_WRITE))) {
271 switch (user_data->type) {
272 case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
273 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
274 if (pfds[i].out_flags != PR_POLL_NVAL) {
275 /*
276 * Poll ERR on listening socket is fatal error.
277 * POLL_NVAL is used as a signal to quit poll loop.
278 */
279 qnetd_log(LOG_CRIT, "POLL_ERR (%u) on listening "
280 "socket", pfds[i].out_flags);
281 } else {
282 qnetd_log(LOG_DEBUG, "Listening socket is closed");
283 }
284
285 return (-1);
286 break;
287 case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
288 qnetd_log(LOG_DEBUG, "POLL_ERR (%u) on client socket. "
289 "Disconnecting.", pfds[i].out_flags);
290
291 client_disconnect = 1;
292 break;
293 case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
294 qnetd_log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket."
295 " Disconnecting.", pfds[i].out_flags);
296
297 client_disconnect = 1;
298 break;
299 }
300 }
301
302 /*
303 * If client is scheduled for disconnect, disconnect it
304 */
305 if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT &&
306 client_disconnect) {
307 qnetd_instance_client_disconnect(instance, client, 0);
308 } else if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT &&
309 (client_disconnect || ipc_client->schedule_disconnect)) {
310 qnetd_ipc_client_disconnect(instance, ipc_client);
311 }
312 }
313 }
314
315
316 return (0);
317}
318
319static void
320signal_int_handler(int sig)
321{
322
323 qnetd_log(LOG_DEBUG, "SIGINT received - closing server IPC socket");
324
325 qnetd_ipc_close(global_instance);
326}
327
328static void
329signal_term_handler(int sig)
330{
331
332 qnetd_log(LOG_DEBUG, "SIGTERM received - closing server IPC socket");
333
334 qnetd_ipc_close(global_instance);
335}
336
337static void
338signal_handlers_register(void)
339{
340 struct sigaction act;
341
342 act.sa_handler = signal_int_handler;
343 sigemptyset(&act.sa_mask);
344 act.sa_flags = SA_RESTART;
345
346 sigaction(SIGINT, &act, NULL);
347
348 act.sa_handler = signal_term_handler;
349 sigemptyset(&act.sa_mask);
350 act.sa_flags = SA_RESTART;
351
352 sigaction(SIGTERM, &act, NULL);
353}
354
355static void
356usage(void)
357{
358
359 printf("usage: %s [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME);
360 printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]\n", "");
361}
362
363static void
364display_version(void)
365{
366 enum msg_type *supported_messages;
367 size_t no_supported_messages;
368 size_t zi;
369
370 msg_get_supported_messages(&supported_messages, &no_supported_messages);
371 printf("Corosync Qdevice Network Daemon, version '%s'\n\n", VERSION);
372 printf("Supported algorithms: ");
373 for (zi = 0; zi < QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE; zi++) {
374 if (zi != 0) {
375 printf(", ");
376 }
377 printf("%s (%u)",
378 tlv_decision_algorithm_type_to_str(qnetd_static_supported_decision_algorithms[zi]),
379 qnetd_static_supported_decision_algorithms[zi]);
380 }
381 printf("\n");
382 printf("Supported message types: ");
383 for (zi = 0; zi < no_supported_messages; zi++) {
384 if (zi != 0) {
385 printf(", ");
386 }
387 printf("%s (%u)", msg_type_to_str(supported_messages[zi]), supported_messages[zi]);
388 }
389 printf("\n");
390}
391
392static void
393cli_parse_long_opt(struct qnetd_advanced_settings *advanced_settings, const char *long_opt)
394{
395 struct dynar_getopt_lex lex;
396 struct dynar dynar_long_opt;
397 const char *opt;
398 const char *val;
399 int res;
400
401 dynar_init(&dynar_long_opt, strlen(long_opt) + 1);
402 if (dynar_str_cpy(&dynar_long_opt, long_opt) != 0) {
403 errx(1, "Can't alloc memory for long option");
404 }
405
406 dynar_getopt_lex_init(&lex, &dynar_long_opt);
407
408 while (dynar_getopt_lex_token_next(&lex) == 0 && strcmp(dynar_data(&lex.option), "") != 0) {
409 opt = dynar_data(&lex.option);
410 val = dynar_data(&lex.value);
411
412 res = qnetd_advanced_settings_set(advanced_settings, opt, val);
413 switch (res) {
414 case -1:
415 errx(1, "Unknown option '%s'", opt);
416 break;
417 case -2:
418 errx(1, "Invalid value '%s' for option '%s'", val, opt);
419 break;
420 }
421 }
422
423 dynar_getopt_lex_destroy(&lex);
424 dynar_destroy(&dynar_long_opt);
425}
426
427static void
428cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port, int *foreground,
429 int *debug_log, int *bump_log_priority, enum tlv_tls_supported *tls_supported,
430 int *client_cert_required, size_t *max_clients, PRIntn *address_family,
431 struct qnetd_advanced_settings *advanced_settings)
432{
433 int ch;
9a1955a7
JF
434 long long int tmpll;
435
436 *host_addr = NULL;
437 *host_port = QNETD_DEFAULT_HOST_PORT;
438 *foreground = 0;
439 *debug_log = 0;
440 *bump_log_priority = 0;
441 *tls_supported = QNETD_DEFAULT_TLS_SUPPORTED;
442 *client_cert_required = QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED;
443 *max_clients = QNETD_DEFAULT_MAX_CLIENTS;
444 *address_family = PR_AF_UNSPEC;
445
446 while ((ch = getopt(argc, argv, "46dfhvc:l:m:p:S:s:")) != -1) {
447 switch (ch) {
448 case '4':
449 *address_family = PR_AF_INET;
450 break;
451 case '6':
452 *address_family = PR_AF_INET6;
453 break;
454 case 'f':
455 *foreground = 1;
456 break;
457 case 'd':
458 if (*debug_log) {
459 *bump_log_priority = 1;
460 }
461 *debug_log = 1;
462 break;
463 case 'c':
464 if ((*client_cert_required = utils_parse_bool_str(optarg)) == -1) {
465 errx(1, "client_cert_required should be on/yes/1, off/no/0");
466 }
467 break;
468 case 'l':
469 free(*host_addr);
470 *host_addr = strdup(optarg);
471 if (*host_addr == NULL) {
472 errx(1, "Can't alloc memory for host addr string");
473 }
474 break;
475 case 'm':
3b21d758 476 if (utils_strtonum(optarg, 0, LLONG_MAX, &tmpll) == -1) {
9a1955a7
JF
477 errx(1, "max clients value %s is invalid", optarg);
478 }
3b21d758 479
9a1955a7
JF
480 *max_clients = (size_t)tmpll;
481 break;
482 case 'p':
3b21d758
JF
483 if (utils_strtonum(optarg, 1, UINT16_MAX, &tmpll) == -1) {
484 errx(1, "host port must be in range 1-%u", UINT16_MAX);
9a1955a7 485 }
3b21d758
JF
486
487 *host_port = tmpll;
9a1955a7
JF
488 break;
489 case 'S':
490 cli_parse_long_opt(advanced_settings, optarg);
491 break;
492 case 's':
493 if (strcasecmp(optarg, "on") == 0) {
494 *tls_supported = QNETD_DEFAULT_TLS_SUPPORTED;
495 } else if (strcasecmp(optarg, "off") == 0) {
496 *tls_supported = TLV_TLS_UNSUPPORTED;
497 } else if (strcasecmp(optarg, "req") == 0) {
498 *tls_supported = TLV_TLS_REQUIRED;
499 } else {
500 errx(1, "tls must be one of on, off, req");
501 }
502 break;
503 case 'v':
504 display_version();
505 exit(1);
506 break;
507 case 'h':
508 case '?':
509 usage();
510 exit(1);
511 break;
512 }
513 }
514}
515
516int
517main(int argc, char * const argv[])
518{
519 struct qnetd_instance instance;
520 struct qnetd_advanced_settings advanced_settings;
521 char *host_addr;
522 uint16_t host_port;
523 int foreground;
524 int debug_log;
525 int bump_log_priority;
526 enum tlv_tls_supported tls_supported;
527 int client_cert_required;
528 size_t max_clients;
529 PRIntn address_family;
530 int lock_file;
531 int another_instance_running;
532
533 if (qnetd_advanced_settings_init(&advanced_settings) != 0) {
534 errx(1, "Can't alloc memory for advanced settings");
535 }
536
537 cli_parse(argc, argv, &host_addr, &host_port, &foreground, &debug_log, &bump_log_priority,
538 &tls_supported, &client_cert_required, &max_clients, &address_family, &advanced_settings);
539
540 if (foreground) {
541 qnetd_log_init(QNETD_LOG_TARGET_STDERR);
542 } else {
543 qnetd_log_init(QNETD_LOG_TARGET_SYSLOG);
544 }
545
546 qnetd_log_set_debug(debug_log);
547 qnetd_log_set_priority_bump(bump_log_priority);
548
549 /*
550 * Daemonize
551 */
552 if (!foreground) {
553 utils_tty_detach();
554 }
555
556 if ((lock_file = utils_flock(advanced_settings.lock_file, getpid(),
557 &another_instance_running)) == -1) {
558 if (another_instance_running) {
559 qnetd_log(LOG_ERR, "Another instance is running");
560 } else {
561 qnetd_log_err(LOG_ERR, "Can't acquire lock");
562 }
563
564 exit(1);
565 }
566
567 qnetd_log(LOG_DEBUG, "Initializing nss");
568 if (nss_sock_init_nss((tls_supported != TLV_TLS_UNSUPPORTED ?
569 advanced_settings.nss_db_dir : NULL)) != 0) {
570 qnetd_err_nss();
571 }
572
573 if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
574 qnetd_err_nss();
575 }
576
577 if (qnetd_instance_init(&instance, tls_supported, client_cert_required,
578 max_clients, &advanced_settings) == -1) {
579 qnetd_log(LOG_ERR, "Can't initialize qnetd");
580 exit(1);
581 }
582 instance.host_addr = host_addr;
583 instance.host_port = host_port;
584
585 if (tls_supported != TLV_TLS_UNSUPPORTED && qnetd_instance_init_certs(&instance) == -1) {
586 qnetd_err_nss();
587 }
588
589 qnetd_log(LOG_DEBUG, "Initializing local socket");
590 if (qnetd_ipc_init(&instance) != 0) {
591 return (1);
592 }
593
594 qnetd_log(LOG_DEBUG, "Creating listening socket");
595 instance.server.socket = nss_sock_create_listen_socket(instance.host_addr,
596 instance.host_port, address_family);
597 if (instance.server.socket == NULL) {
598 qnetd_err_nss();
599 }
600
601 if (nss_sock_set_non_blocking(instance.server.socket) != 0) {
602 qnetd_err_nss();
603 }
604
605 if (PR_Listen(instance.server.socket, instance.advanced_settings->listen_backlog) !=
606 PR_SUCCESS) {
607 qnetd_err_nss();
608 }
609
610 global_instance = &instance;
611 signal_handlers_register();
612
613 qnetd_log(LOG_DEBUG, "Registering algorithms");
614 if (qnetd_algorithm_register_all() != 0) {
615 exit(1);
616 }
617
618 qnetd_log(LOG_DEBUG, "QNetd ready to provide service");
619
620#ifdef HAVE_LIBSYSTEMD
621 sd_notify(0, "READY=1");
622#endif
623
624 /*
625 * MAIN LOOP
626 */
627 while (qnetd_poll(&instance) == 0) {
628 }
629
630 /*
631 * Cleanup
632 */
633 qnetd_ipc_destroy(&instance);
634
635 if (PR_Close(instance.server.socket) != PR_SUCCESS) {
636 qnetd_warn_nss();
637 }
638
639 CERT_DestroyCertificate(instance.server.cert);
640 SECKEY_DestroyPrivateKey(instance.server.private_key);
641
642 SSL_ClearSessionCache();
643
644 SSL_ShutdownServerSessionIDCache();
645
646 qnetd_instance_destroy(&instance);
647
648 qnetd_advanced_settings_destroy(&advanced_settings);
649
650 if (NSS_Shutdown() != SECSuccess) {
651 qnetd_warn_nss();
652 }
653
654 if (PR_Cleanup() != PR_SUCCESS) {
655 qnetd_warn_nss();
656 }
657
658 qnetd_log_close();
659
660 return (0);
661}