Change initialization order for logsys logging to files to work properly.
[openais.git] / exec / totemconfig.c
blob2da7eaeb79747e6a5bb5afb8e144d5797a375f63
1 /*
2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006 RedHat, Inc.
5 * All rights reserved.
7 * Author: Steven Dake (sdake@mvista.com)
9 * This software licensed under BSD license, the text of which follows:
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
14 * - Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * - Neither the name of the MontaVista Software, Inc. nor the names of its
20 * contributors may be used to endorse or promote products derived from this
21 * software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <assert.h>
40 #include <unistd.h>
41 #include <sys/socket.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <sys/param.h>
49 #include "swab.h"
50 #include "list.h"
51 #include "util.h"
52 #include "totem.h"
53 #include "totemconfig.h"
54 #include "logsys.h"
55 #include "objdb.h"
56 #include "tlist.h" /* for HZ */
58 #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4
59 #define TOKEN_TIMEOUT 1000
60 #define TOKEN_RETRANSMIT_TIMEOUT (int)(TOKEN_TIMEOUT / (TOKEN_RETRANSMITS_BEFORE_LOSS_CONST + 0.2))
61 #define TOKEN_HOLD_TIMEOUT (int)(TOKEN_RETRANSMIT_TIMEOUT * 0.8 - (1000/(int)HZ))
62 #define JOIN_TIMEOUT 50
63 #define CONSENSUS_TIMEOUT 800
64 #define MERGE_TIMEOUT 200
65 #define DOWNCHECK_TIMEOUT 1000
66 #define FAIL_TO_RECV_CONST 50
67 #define SEQNO_UNCHANGED_CONST 30
68 #define MINIMUM_TIMEOUT (int)(1000/HZ)*3
69 #define MAX_NETWORK_DELAY 50
70 #define WINDOW_SIZE 50
71 #define MAX_MESSAGES 17
72 #define RRP_PROBLEM_COUNT_TIMEOUT 2000
73 #define RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT 10
74 #define RRP_PROBLEM_COUNT_THRESHOLD_MIN 5
76 static char error_string_response[512];
78 /* These just makes the code below a little neater */
79 static inline int objdb_get_string (
80 struct objdb_iface_ver0 *objdb, unsigned int object_service_handle,
81 char *key, char **value)
83 int res;
85 *value = NULL;
86 if ( !(res = objdb->object_key_get (object_service_handle,
87 key,
88 strlen (key),
89 (void *)value,
90 NULL))) {
91 if (*value)
92 return 0;
94 return -1;
97 static inline void objdb_get_int (
98 struct objdb_iface_ver0 *objdb, unsigned int object_service_handle,
99 char *key, unsigned int *intvalue)
101 char *value = NULL;
103 if (!objdb->object_key_get (object_service_handle,
104 key,
105 strlen (key),
106 (void *)&value,
107 NULL)) {
108 if (value) {
109 *intvalue = atoi(value);
115 extern int totem_config_read (
116 struct objdb_iface_ver0 *objdb,
117 struct totem_config *totem_config,
118 char **error_string)
120 int res = 0;
121 unsigned int object_totem_handle;
122 unsigned int object_interface_handle;
123 char *str;
124 unsigned int ringnumber = 0;
126 memset (totem_config, 0, sizeof (struct totem_config));
127 totem_config->interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
128 if (totem_config->interfaces == 0) {
129 *error_string = "Out of memory trying to allocate ethernet interface storage area";
130 return -1;
133 memset (totem_config->interfaces, 0,
134 sizeof (struct totem_interface) * INTERFACE_MAX);
136 totem_config->secauth = 1;
138 strcpy (totem_config->rrp_mode, "none");
140 objdb->object_find_reset (OBJECT_PARENT_HANDLE);
142 if (objdb->object_find (
143 OBJECT_PARENT_HANDLE,
144 "network",
145 strlen ("network"),
146 &object_totem_handle) == 0 ||
147 objdb->object_find (
148 OBJECT_PARENT_HANDLE,
149 "totem",
150 strlen ("totem"),
151 &object_totem_handle) == 0) {
153 if (!objdb_get_string (objdb,object_totem_handle, "version", &str)) {
154 if (strcmp (str, "2") == 0) {
155 totem_config->version = 2;
158 if (!objdb_get_string (objdb,object_totem_handle, "secauth", &str)) {
159 if (strcmp (str, "on") == 0) {
160 totem_config->secauth = 1;
162 if (strcmp (str, "off") == 0) {
163 totem_config->secauth = 0;
166 if (!objdb_get_string (objdb, object_totem_handle, "rrp_mode", &str)) {
167 strcpy (totem_config->rrp_mode, str);
171 * Get interface node id
173 objdb_get_int (objdb, object_totem_handle, "nodeid", &totem_config->node_id);
175 objdb_get_int (objdb,object_totem_handle, "threads", &totem_config->threads);
178 objdb_get_int (objdb,object_totem_handle, "netmtu", &totem_config->net_mtu);
180 objdb_get_int (objdb,object_totem_handle, "token", &totem_config->token_timeout);
182 objdb_get_int (objdb,object_totem_handle, "token_retransmit", &totem_config->token_retransmit_timeout);
184 objdb_get_int (objdb,object_totem_handle, "hold", &totem_config->token_hold_timeout);
186 objdb_get_int (objdb,object_totem_handle, "token_retransmits_before_loss_const", &totem_config->token_retransmits_before_loss_const);
188 objdb_get_int (objdb,object_totem_handle, "join", &totem_config->join_timeout);
189 objdb_get_int (objdb,object_totem_handle, "send_join", &totem_config->send_join_timeout);
191 objdb_get_int (objdb,object_totem_handle, "consensus", &totem_config->consensus_timeout);
193 objdb_get_int (objdb,object_totem_handle, "merge", &totem_config->merge_timeout);
195 objdb_get_int (objdb,object_totem_handle, "downcheck", &totem_config->downcheck_timeout);
197 objdb_get_int (objdb,object_totem_handle, "fail_recv_const", &totem_config->fail_to_recv_const);
199 objdb_get_int (objdb,object_totem_handle, "seqno_unchanged_const", &totem_config->seqno_unchanged_const);
201 objdb_get_int (objdb,object_totem_handle, "rrp_token_expired_timeout", &totem_config->rrp_token_expired_timeout);
203 objdb_get_int (objdb,object_totem_handle, "rrp_problem_count_timeout", &totem_config->rrp_problem_count_timeout);
205 objdb_get_int (objdb,object_totem_handle, "rrp_problem_count_threshold", &totem_config->rrp_problem_count_threshold);
207 objdb_get_int (objdb,object_totem_handle, "heartbeat_failures_allowed", &totem_config->heartbeat_failures_allowed);
209 objdb_get_int (objdb,object_totem_handle, "max_network_delay", &totem_config->max_network_delay);
211 objdb_get_int (objdb,object_totem_handle, "window_size", &totem_config->window_size);
212 objdb_get_string (objdb, object_totem_handle, "vsftype", &totem_config->vsf_type);
214 objdb_get_int (objdb,object_totem_handle, "max_messages", &totem_config->max_messages);
216 while (objdb->object_find (
217 object_totem_handle,
218 "interface",
219 strlen ("interface"),
220 &object_interface_handle) == 0) {
222 objdb_get_int (objdb, object_interface_handle, "ringnumber", &ringnumber);
225 * Get interface multicast address
227 if (!objdb_get_string (objdb, object_interface_handle, "mcastaddr", &str)) {
228 res = totemip_parse (&totem_config->interfaces[ringnumber].mcast_addr, str, 0);
232 * Get mcast port
234 if (!objdb_get_string (objdb, object_interface_handle, "mcastport", &str)) {
235 totem_config->interfaces[ringnumber].ip_port = atoi (str);
239 * Get the bind net address
241 if (!objdb_get_string (objdb, object_interface_handle, "bindnetaddr", &str)) {
243 res = totemip_parse (&totem_config->interfaces[ringnumber].bindnet, str,
244 totem_config->interfaces[ringnumber].mcast_addr.family);
246 totem_config->interface_count++;
249 return 0;
251 return (-1);
254 int totem_config_validate (
255 struct totem_config *totem_config,
256 char **error_string)
258 static char local_error_reason[512];
259 char parse_error[512];
260 char *error_reason = local_error_reason;
261 int i;
262 unsigned int interface_max = INTERFACE_MAX;
264 if (totem_config->interface_count == 0) {
265 error_reason = "No interfaces defined";
266 goto parse_error;
269 for (i = 0; i < totem_config->interface_count; i++) {
271 * Some error checking of parsed data to make sure its valid
273 if ((int *)&totem_config->interfaces[i].mcast_addr.addr == 0) {
274 error_reason = "No multicast address specified";
275 goto parse_error;
278 if (totem_config->interfaces[i].ip_port == 0) {
279 error_reason = "No multicast port specified";
280 goto parse_error;
283 if (totem_config->interfaces[i].mcast_addr.family == AF_INET6 &&
284 totem_config->node_id == 0) {
286 error_reason = "An IPV6 network requires that a node ID be specified.";
287 goto parse_error;
290 if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) {
291 error_reason = "Multicast address family does not match bind address family";
292 goto parse_error;
295 if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) {
296 error_reason = "Not all bind address belong to the same IP family";
297 goto parse_error;
301 if (totem_config->version != 2) {
302 error_reason = "This totem parser can only parse version 2 configurations.";
303 goto parse_error;
307 if (totem_config->token_retransmits_before_loss_const == 0) {
308 totem_config->token_retransmits_before_loss_const =
309 TOKEN_RETRANSMITS_BEFORE_LOSS_CONST;
313 * Setup timeout values that are not setup by user
315 if (totem_config->token_timeout == 0) {
316 totem_config->token_timeout = TOKEN_TIMEOUT;
317 if (totem_config->token_retransmits_before_loss_const == 0) {
318 totem_config->token_retransmits_before_loss_const = TOKEN_RETRANSMITS_BEFORE_LOSS_CONST;
321 if (totem_config->token_retransmit_timeout == 0) {
322 totem_config->token_retransmit_timeout =
323 (int)(totem_config->token_timeout /
324 (totem_config->token_retransmits_before_loss_const + 0.2));
326 if (totem_config->token_hold_timeout == 0) {
327 totem_config->token_hold_timeout =
328 (int)(totem_config->token_retransmit_timeout * 0.8 -
329 (1000/HZ));
333 if (totem_config->max_network_delay == 0) {
334 totem_config->max_network_delay = MAX_NETWORK_DELAY;
337 if (totem_config->max_network_delay < MINIMUM_TIMEOUT) {
338 sprintf (local_error_reason, "The max_network_delay parameter (%d ms) may not be less then (%d ms).",
339 totem_config->max_network_delay, MINIMUM_TIMEOUT);
340 goto parse_error;
343 if (totem_config->window_size == 0) {
344 totem_config->window_size = WINDOW_SIZE;
347 if (totem_config->max_messages == 0) {
348 totem_config->max_messages = MAX_MESSAGES;
351 if (totem_config->token_timeout < MINIMUM_TIMEOUT) {
352 sprintf (local_error_reason, "The token timeout parameter (%d ms) may not be less then (%d ms).",
353 totem_config->token_timeout, MINIMUM_TIMEOUT);
354 goto parse_error;
357 if (totem_config->token_retransmit_timeout == 0) {
358 totem_config->token_retransmit_timeout =
359 (int)(totem_config->token_timeout /
360 (totem_config->token_retransmits_before_loss_const + 0.2));
362 if (totem_config->token_hold_timeout == 0) {
363 totem_config->token_hold_timeout =
364 (int)(totem_config->token_retransmit_timeout * 0.8 -
365 (1000/HZ));
367 if (totem_config->token_retransmit_timeout < MINIMUM_TIMEOUT) {
368 sprintf (local_error_reason, "The token retransmit timeout parameter (%d ms) may not be less then (%d ms).",
369 totem_config->token_retransmit_timeout, MINIMUM_TIMEOUT);
370 goto parse_error;
373 if (totem_config->token_hold_timeout == 0) {
374 totem_config->token_hold_timeout = TOKEN_HOLD_TIMEOUT;
377 if (totem_config->token_hold_timeout < MINIMUM_TIMEOUT) {
378 sprintf (local_error_reason, "The token hold timeout parameter (%d ms) may not be less then (%d ms).",
379 totem_config->token_hold_timeout, MINIMUM_TIMEOUT);
380 goto parse_error;
383 if (totem_config->join_timeout == 0) {
384 totem_config->join_timeout = JOIN_TIMEOUT;
387 if (totem_config->join_timeout < MINIMUM_TIMEOUT) {
388 sprintf (local_error_reason, "The join timeout parameter (%d ms) may not be less then (%d ms).",
389 totem_config->join_timeout, MINIMUM_TIMEOUT);
390 goto parse_error;
393 if (totem_config->consensus_timeout == 0) {
394 totem_config->consensus_timeout = CONSENSUS_TIMEOUT;
397 if (totem_config->consensus_timeout < MINIMUM_TIMEOUT) {
398 sprintf (local_error_reason, "The consensus timeout parameter (%d ms) may not be less then (%d ms).",
399 totem_config->consensus_timeout, MINIMUM_TIMEOUT);
400 goto parse_error;
403 if (totem_config->merge_timeout == 0) {
404 totem_config->merge_timeout = MERGE_TIMEOUT;
407 if (totem_config->merge_timeout < MINIMUM_TIMEOUT) {
408 sprintf (local_error_reason, "The merge timeout parameter (%d ms) may not be less then (%d ms).",
409 totem_config->merge_timeout, MINIMUM_TIMEOUT);
410 goto parse_error;
413 if (totem_config->downcheck_timeout == 0) {
414 totem_config->downcheck_timeout = DOWNCHECK_TIMEOUT;
417 if (totem_config->downcheck_timeout < MINIMUM_TIMEOUT) {
418 sprintf (local_error_reason, "The downcheck timeout parameter (%d ms) may not be less then (%d ms).",
419 totem_config->downcheck_timeout, MINIMUM_TIMEOUT);
420 goto parse_error;
424 * RRP values validation
426 if (strcmp (totem_config->rrp_mode, "none") &&
427 strcmp (totem_config->rrp_mode, "active") &&
428 strcmp (totem_config->rrp_mode, "passive")) {
429 sprintf (local_error_reason, "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config->rrp_mode);
430 goto parse_error;
432 if (totem_config->rrp_problem_count_timeout == 0) {
433 totem_config->rrp_problem_count_timeout = RRP_PROBLEM_COUNT_TIMEOUT;
435 if (totem_config->rrp_problem_count_timeout < MINIMUM_TIMEOUT) {
436 sprintf (local_error_reason, "The RRP problem count timeout parameter (%d ms) may not be less then (%d ms).",
437 totem_config->rrp_problem_count_timeout, MINIMUM_TIMEOUT);
438 goto parse_error;
440 if (totem_config->rrp_problem_count_threshold == 0) {
441 totem_config->rrp_problem_count_threshold = RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT;
443 if (totem_config->rrp_problem_count_threshold < RRP_PROBLEM_COUNT_THRESHOLD_MIN) {
444 sprintf (local_error_reason, "The RRP problem count threshold (%d problem count) may not be less then (%d problem count).",
445 totem_config->rrp_problem_count_threshold, RRP_PROBLEM_COUNT_THRESHOLD_MIN);
446 goto parse_error;
448 if (totem_config->rrp_token_expired_timeout == 0) {
449 totem_config->rrp_token_expired_timeout =
450 totem_config->token_retransmit_timeout;
453 if (totem_config->rrp_token_expired_timeout < MINIMUM_TIMEOUT) {
454 sprintf (local_error_reason, "The RRP token expired timeout parameter (%d ms) may not be less then (%d ms).",
455 totem_config->rrp_token_expired_timeout, MINIMUM_TIMEOUT);
456 goto parse_error;
459 if (strcmp (totem_config->rrp_mode, "none") == 0) {
460 interface_max = 1;
462 if (interface_max < totem_config->interface_count) {
463 sprintf (parse_error,
464 "%d is too many configured interfaces for the rrp_mode setting %s.",
465 totem_config->interface_count,
466 totem_config->rrp_mode);
467 error_reason = parse_error;
468 goto parse_error;
472 if (totem_config->fail_to_recv_const == 0) {
473 totem_config->fail_to_recv_const = FAIL_TO_RECV_CONST;
475 if (totem_config->seqno_unchanged_const == 0) {
476 totem_config->seqno_unchanged_const = SEQNO_UNCHANGED_CONST;
478 if (totem_config->net_mtu == 0) {
479 totem_config->net_mtu = 1500;
482 if ((MESSAGE_SIZE_MAX / totem_config->net_mtu) < totem_config->max_messages) {
483 sprintf (local_error_reason, "The max_messages parameter (%d messages) may not be greater then (%d messages).",
484 totem_config->max_messages, MESSAGE_SIZE_MAX / totem_config->net_mtu);
485 goto parse_error;
488 if (totem_config->threads > SEND_THREADS_MAX) {
489 totem_config->threads = SEND_THREADS_MAX;
491 if (totem_config->secauth == 0) {
492 totem_config->threads = 0;
494 if (totem_config->net_mtu > FRAME_SIZE_MAX) {
495 error_reason = "This net_mtu parameter is greater then the maximum frame size";
496 goto parse_error;
498 if (totem_config->vsf_type == NULL) {
499 totem_config->vsf_type = "none";
502 return (0);
504 parse_error:
505 sprintf (error_string_response,
506 "parse error in config: %s\n", error_reason);
507 *error_string = error_string_response;
508 return (-1);
511 static int read_keyfile (
512 char *key_location,
513 struct totem_config *totem_config,
514 char **error_string)
516 int fd;
517 int res;
519 fd = open (key_location, O_RDONLY);
520 if (fd == -1) {
521 sprintf (error_string_response, "Could not open %s: %s\n",
522 key_location, strerror (errno));
523 goto parse_error;
526 res = read (fd, totem_config->private_key, 128);
527 if (res == -1) {
528 close (fd);
529 sprintf (error_string_response, "Could not read %s: %s\n",
530 key_location, strerror (errno));
531 goto parse_error;
534 totem_config->private_key_len = 128;
536 if (res != 128) {
537 close (fd);
538 sprintf (error_string_response, "Could only read %d bits of 1024 bits from %s.\n",
539 res * 8, key_location);
540 goto parse_error;
542 return 0;
544 parse_error:
545 *error_string = error_string_response;
546 return (-1);
549 int totem_config_keyread (
550 struct objdb_iface_ver0 *objdb,
551 struct totem_config *totem_config,
552 char **error_string)
554 int got_key = 0;
555 char *key_location = NULL;
556 unsigned int object_service_handle;
557 int res;
559 memset (totem_config->private_key, 0, 128);
560 totem_config->private_key_len = 128;
562 if (totem_config->secauth == 0) {
563 return (0);
566 if (objdb->object_find (
567 OBJECT_PARENT_HANDLE,
568 "network",
569 strlen ("network"),
570 &object_service_handle) == 0 ||
571 objdb->object_find (
572 OBJECT_PARENT_HANDLE,
573 "totem",
574 strlen ("totem"),
575 &object_service_handle) == 0) {
577 /* objdb may store the location of the key file */
578 if (!objdb_get_string (objdb,object_service_handle, "keyfile", &key_location)
579 && key_location) {
580 res = read_keyfile(key_location, totem_config, error_string);
581 if (res)
582 goto key_error;
583 got_key = 1;
585 else { /* Or the key itself may be in the objdb */
586 char *key = NULL;
587 int key_len;
588 res = objdb->object_key_get (object_service_handle,
589 "key",
590 strlen ("key"),
591 (void *)&key,
592 &key_len);
593 if (res == 0 && key) {
594 memcpy(totem_config->private_key, key, key_len);
595 totem_config->private_key_len = key_len;
596 got_key = 1;
601 /* In desperation we read the default filename */
602 if (!got_key) {
603 char *filename = getenv("OPENAIS_TOTEM_AUTHKEY_FILE");
604 if (!filename)
605 filename = "/etc/ais/authkey";
606 res = read_keyfile(filename, totem_config, error_string);
607 if (res)
608 goto key_error;
612 return (0);
614 *error_string = error_string_response;
615 key_error:
616 return (-1);