]>
Commit | Line | Data |
---|---|---|
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 | */ | |
67 | struct qnetd_instance *global_instance; | |
68 | ||
69 | enum 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 | ||
77 | static void | |
78 | qnetd_err_nss(void) | |
79 | { | |
80 | ||
81 | qnetd_log_nss(LOG_CRIT, "NSS error"); | |
82 | ||
83 | exit(1); | |
84 | } | |
85 | ||
86 | static void | |
87 | qnetd_warn_nss(void) | |
88 | { | |
89 | ||
90 | qnetd_log_nss(LOG_WARNING, "NSS warning"); | |
91 | } | |
92 | ||
93 | static PRPollDesc * | |
94 | qnetd_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 | ||
175 | static int | |
176 | qnetd_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 | ||
319 | static void | |
320 | signal_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 | ||
328 | static void | |
329 | signal_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 | ||
337 | static void | |
338 | signal_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 | ||
355 | static void | |
356 | usage(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 | ||
363 | static void | |
364 | display_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 | ||
392 | static void | |
393 | cli_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 | ||
427 | static void | |
428 | cli_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 | ||
516 | int | |
517 | main(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 | } |