summaryrefslogtreecommitdiff
path: root/other/bootstrap_daemon/src
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2016-01-04 22:43:36 -0500
committerirungentoo <irungentoo@gmail.com>2016-01-04 22:43:36 -0500
commitc6bed82d47aa39709bdd568fccc3847714ed1b74 (patch)
tree4e2dd8676a53e78a5b84e3abd68cdbe82a636737 /other/bootstrap_daemon/src
parent760f20c9455c2ef33ec9d242f209a1543f6acaf4 (diff)
parent9d1efd594914629204d4cd1a84678daf67eb8068 (diff)
Merge branch 'tox-bootstrapd-docker-support' of https://github.com/nurupo/InsertProjectNameHere
Diffstat (limited to 'other/bootstrap_daemon/src')
-rw-r--r--other/bootstrap_daemon/src/Makefile.inc38
-rw-r--r--other/bootstrap_daemon/src/command_line_arguments.c145
-rw-r--r--other/bootstrap_daemon/src/command_line_arguments.h42
-rw-r--r--other/bootstrap_daemon/src/config.c426
-rw-r--r--other/bootstrap_daemon/src/config.h52
-rw-r--r--other/bootstrap_daemon/src/config_defaults.h42
-rw-r--r--other/bootstrap_daemon/src/global.h34
-rw-r--r--other/bootstrap_daemon/src/log.c117
-rw-r--r--other/bootstrap_daemon/src/log.h64
-rw-r--r--other/bootstrap_daemon/src/tox-bootstrapd.c342
10 files changed, 1302 insertions, 0 deletions
diff --git a/other/bootstrap_daemon/src/Makefile.inc b/other/bootstrap_daemon/src/Makefile.inc
new file mode 100644
index 00000000..a0d75fa0
--- /dev/null
+++ b/other/bootstrap_daemon/src/Makefile.inc
@@ -0,0 +1,38 @@
1if BUILD_DHT_BOOTSTRAP_DAEMON
2
3bin_PROGRAMS += tox-bootstrapd
4
5tox_bootstrapd_SOURCES = \
6 ../other/bootstrap_daemon/src/command_line_arguments.c \
7 ../other/bootstrap_daemon/src/command_line_arguments.h \
8 ../other/bootstrap_daemon/src/config.c \
9 ../other/bootstrap_daemon/src/config_defaults.h \
10 ../other/bootstrap_daemon/src/config.h \
11 ../other/bootstrap_daemon/src/log.c \
12 ../other/bootstrap_daemon/src/log.h \
13 ../other/bootstrap_daemon/src/tox-bootstrapd.c \
14 ../other/bootstrap_node_packets.c \
15 ../other/bootstrap_node_packets.h
16
17
18tox_bootstrapd_CFLAGS = \
19 -I$(top_srcdir)/other/bootstrap_daemon \
20 $(LIBSODIUM_CFLAGS) \
21 $(NACL_CFLAGS) \
22 $(LIBCONFIG_CFLAGS)
23
24tox_bootstrapd_LDADD = \
25 $(LIBSODIUM_LDFLAGS) \
26 $(NACL_LDFLAGS) \
27 libtoxcore.la \
28 $(LIBCONFIG_LIBS) \
29 $(LIBSODIUM_LIBS) \
30 $(NACL_LIBS)
31
32endif
33
34EXTRA_DIST += \
35 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.conf \
36 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.service \
37 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.sh
38
diff --git a/other/bootstrap_daemon/src/command_line_arguments.c b/other/bootstrap_daemon/src/command_line_arguments.c
new file mode 100644
index 00000000..187fa786
--- /dev/null
+++ b/other/bootstrap_daemon/src/command_line_arguments.c
@@ -0,0 +1,145 @@
1/* command_line_arguments.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Command line argument handling.
5 *
6 * Copyright (C) 2015-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include "command_line_arguments.h"
26
27#include "global.h"
28
29#include <getopt.h>
30
31#include <stdlib.h>
32#include <string.h>
33
34
35/**
36 * Prints --help message
37 */
38void print_help()
39{
40 // 2 space ident
41 // make sure all lines fit into 80 columns
42 // make sure options are listed in alphabetical order
43 write_log(LOG_LEVEL_INFO,
44 "Usage: tox-bootstrapd [OPTION]... --config=FILE_PATH\n"
45 "\n"
46 "Options:\n"
47 " --config=FILE_PATH Specify path to the config file.\n"
48 " This is a required option.\n"
49 " Set FILE_PATH to a path to an empty file in order to\n"
50 " use default settings.\n"
51 " --foreground Run the daemon in foreground. The daemon won't fork\n"
52 " (detach from the terminal) and won't use the PID file.\n"
53 " --help Print this help message.\n"
54 " --log-backend=BACKEND Specify which logging backend to use.\n"
55 " Valid BACKEND values (case sensetive):\n"
56 " syslog Writes log messages to syslog.\n"
57 " Default option when no --log-backend is\n"
58 " specified.\n"
59 " stdout Writes log messages to stdout/stderr.\n"
60 " --version Print version information.\n");
61}
62
63void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground)
64{
65 if (argc < 2) {
66 write_log(LOG_LEVEL_ERROR, "Error: No arguments provided.\n\n");
67 print_help();
68 exit(1);
69 }
70
71 opterr = 0;
72
73 static struct option long_options[] = {
74 {"config", required_argument, 0, 'c'}, // required option
75 {"foreground", no_argument, 0, 'f'},
76 {"help", no_argument, 0, 'h'},
77 {"log-backend", required_argument, 0, 'l'}, // optional, defaults to syslog
78 {"version", no_argument, 0, 'v'},
79 {0, 0, 0, 0 }
80 };
81
82 bool cfg_file_path_set = false;
83 bool log_backend_set = false;
84
85 *run_in_foreground = false;
86
87 int opt;
88
89 while ((opt = getopt_long(argc, argv, ":", long_options, NULL)) != -1) {
90
91 switch (opt) {
92
93 case 'c':
94 *cfg_file_path = optarg;
95 cfg_file_path_set = true;
96 break;
97
98 case 'f':
99 *run_in_foreground = true;
100 break;
101
102 case 'h':
103 print_help();
104 exit(0);
105
106 case 'l':
107 if (strcmp(optarg, "syslog") == 0) {
108 *log_backend = LOG_BACKEND_SYSLOG;
109 log_backend_set = true;
110 } else if (strcmp(optarg, "stdout") == 0) {
111 *log_backend = LOG_BACKEND_STDOUT;
112 log_backend_set = true;
113 } else {
114 write_log(LOG_LEVEL_ERROR, "Error: Invalid BACKEND value for --log-backend option passed: %s\n\n", optarg);
115 print_help();
116 exit(1);
117 }
118 break;
119
120 case 'v':
121 write_log(LOG_LEVEL_INFO, "Version: %lu\n", DAEMON_VERSION_NUMBER);
122 exit(0);
123
124 case '?':
125 write_log(LOG_LEVEL_ERROR, "Error: Unrecognized option %s\n\n", argv[optind-1]);
126 print_help();
127 exit(1);
128
129 case ':':
130 write_log(LOG_LEVEL_ERROR, "Error: No argument provided for option %s\n\n", argv[optind-1]);
131 print_help();
132 exit(1);
133 }
134 }
135
136 if (!log_backend_set) {
137 *log_backend = LOG_BACKEND_SYSLOG;
138 }
139
140 if (!cfg_file_path_set) {
141 write_log(LOG_LEVEL_ERROR, "Error: The required --config option wasn't specified\n\n");
142 print_help();
143 exit(1);
144 }
145}
diff --git a/other/bootstrap_daemon/src/command_line_arguments.h b/other/bootstrap_daemon/src/command_line_arguments.h
new file mode 100644
index 00000000..c73cd15e
--- /dev/null
+++ b/other/bootstrap_daemon/src/command_line_arguments.h
@@ -0,0 +1,42 @@
1/* command_line_arguments.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Command line argument handling.
5 *
6 * Copyright (C) 2015-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#ifndef COMMAND_LINE_ARGUMENTS_H
26#define COMMAND_LINE_ARGUMENTS_H
27
28#include "log.h"
29
30/**
31 * Handles command line arguments, setting cfg_file_path and log_backend.
32 * Terminates the application if incorrect arguments are specified.
33 *
34 * @param argc Argc passed into main().
35 * @param argv Argv passed into main().
36 * @param cfg_file_path Sets to the provided by the user config file path.
37 * @param log_backend Sets to the provided by the user log backend option.
38 * @param run_in_foreground Sets to the provided by the user foreground option.
39 */
40void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground);
41
42#endif // COMMAND_LINE_ARGUMENTS_H
diff --git a/other/bootstrap_daemon/src/config.c b/other/bootstrap_daemon/src/config.c
new file mode 100644
index 00000000..861a3803
--- /dev/null
+++ b/other/bootstrap_daemon/src/config.c
@@ -0,0 +1,426 @@
1/* config.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Functionality related to dealing with the config file.
5 *
6 * Copyright (C) 2014-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include "config.h"
26
27#include "config_defaults.h"
28#include "log.h"
29
30#include <stdlib.h>
31#include <string.h>
32#include <string.h>
33
34#include <libconfig.h>
35
36#include "../../bootstrap_node_packets.h"
37
38/**
39 * Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array.
40 *
41 * Supposed to be called from get_general_config only.
42 *
43 * Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`.
44 */
45void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)
46{
47 const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports";
48
49 *tcp_relay_port_count = 0;
50
51 config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);
52
53 if (ports_array == NULL) {
54 write_log(LOG_LEVEL_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS);
55 write_log(LOG_LEVEL_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS);
56
57 uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};
58
59 int i;
60
61 for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
62 write_log(LOG_LEVEL_INFO, "Port #%d: %u\n", i, default_ports[i]);
63 }
64
65 // similar procedure to the one of reading config file below
66 *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));
67
68 for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
69
70 (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];
71
72 if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
73 || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
74 write_log(LOG_LEVEL_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
75 (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
76 continue;
77 }
78
79 (*tcp_relay_port_count) ++;
80 }
81
82 // the loop above skips invalid ports, so we adjust the allocated memory size
83 if ((*tcp_relay_port_count) > 0) {
84 *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
85 } else {
86 free(*tcp_relay_ports);
87 *tcp_relay_ports = NULL;
88 }
89
90 return;
91 }
92
93 if (config_setting_is_array(ports_array) == CONFIG_FALSE) {
94 write_log(LOG_LEVEL_ERROR, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n",
95 NAME_TCP_RELAY_PORTS);
96 return;
97 }
98
99 int config_port_count = config_setting_length(ports_array);
100
101 if (config_port_count == 0) {
102 write_log(LOG_LEVEL_ERROR, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS);
103 return;
104 }
105
106 *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));
107
108 int i;
109
110 for (i = 0; i < config_port_count; i ++) {
111 config_setting_t *elem = config_setting_get_elem(ports_array, i);
112
113 if (elem == NULL) {
114 // it's NULL if `ports_array` is not an array (we have that check earlier) or if `i` is out of range, which should not be
115 write_log(LOG_LEVEL_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i);
116 break;
117 }
118
119 if (config_setting_is_number(elem) == CONFIG_FALSE) {
120 write_log(LOG_LEVEL_WARNING, "Port #%d: Not a number. Skipping.\n", i);
121 continue;
122 }
123
124 (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);
125
126 if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
127 || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
128 write_log(LOG_LEVEL_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
129 (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
130 continue;
131 }
132
133 (*tcp_relay_port_count) ++;
134 }
135
136 // the loop above skips invalid ports, so we adjust the allocated memory size
137 if ((*tcp_relay_port_count) > 0) {
138 *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
139 } else {
140 free(*tcp_relay_ports);
141 *tcp_relay_ports = NULL;
142 }
143}
144
145int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
146 int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
147 int *tcp_relay_port_count, int *enable_motd, char **motd)
148{
149 config_t cfg;
150
151 const char *NAME_PORT = "port";
152 const char *NAME_PID_FILE_PATH = "pid_file_path";
153 const char *NAME_KEYS_FILE_PATH = "keys_file_path";
154 const char *NAME_ENABLE_IPV6 = "enable_ipv6";
155 const char *NAME_ENABLE_IPV4_FALLBACK = "enable_ipv4_fallback";
156 const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
157 const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay";
158 const char *NAME_ENABLE_MOTD = "enable_motd";
159 const char *NAME_MOTD = "motd";
160
161 config_init(&cfg);
162
163 // Read the file. If there is an error, report it and exit.
164 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
165 write_log(LOG_LEVEL_ERROR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
166 config_destroy(&cfg);
167 return 0;
168 }
169
170 // Get port
171 if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
172 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
173 write_log(LOG_LEVEL_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
174 *port = DEFAULT_PORT;
175 }
176
177 // Get PID file location
178 const char *tmp_pid_file;
179
180 if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
181 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
182 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
183 tmp_pid_file = DEFAULT_PID_FILE_PATH;
184 }
185
186 *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
187 strcpy(*pid_file_path, tmp_pid_file);
188
189 // Get keys file location
190 const char *tmp_keys_file;
191
192 if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
193 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
194 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
195 tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
196 }
197
198 *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
199 strcpy(*keys_file_path, tmp_keys_file);
200
201 // Get IPv6 option
202 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
203 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
204 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
205 *enable_ipv6 = DEFAULT_ENABLE_IPV6;
206 }
207
208 // Get IPv4 fallback option
209 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) {
210 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK);
211 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK,
212 DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false");
213 *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK;
214 }
215
216 // Get LAN discovery option
217 if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
218 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
219 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
220 DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
221 *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
222 }
223
224 // Get TCP relay option
225 if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {
226 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY);
227 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY,
228 DEFAULT_ENABLE_TCP_RELAY ? "true" : "false");
229 *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;
230 }
231
232 if (*enable_tcp_relay) {
233 parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);
234 } else {
235 *tcp_relay_port_count = 0;
236 }
237
238 // Get MOTD option
239 if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {
240 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD);
241 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD,
242 DEFAULT_ENABLE_MOTD ? "true" : "false");
243 *enable_motd = DEFAULT_ENABLE_MOTD;
244 }
245
246 if (*enable_motd) {
247 // Get MOTD
248 const char *tmp_motd;
249
250 if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {
251 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_MOTD);
252 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_MOTD, DEFAULT_MOTD);
253 tmp_motd = DEFAULT_MOTD;
254 }
255
256 size_t tmp_motd_length = strlen(tmp_motd) + 1;
257 size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;
258 *motd = malloc(motd_length);
259 strncpy(*motd, tmp_motd, motd_length);
260 (*motd)[motd_length - 1] = '\0';
261 }
262
263 config_destroy(&cfg);
264
265 write_log(LOG_LEVEL_INFO, "Successfully read:\n");
266 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
267 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
268 write_log(LOG_LEVEL_INFO, "'%s': %d\n", NAME_PORT, *port);
269 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
270 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false");
271 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
272
273 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false");
274
275 // show info about tcp ports only if tcp relay is enabled
276 if (*enable_tcp_relay) {
277 if (*tcp_relay_port_count == 0) {
278 write_log(LOG_LEVEL_ERROR, "No TCP ports could be read.\n");
279 } else {
280 write_log(LOG_LEVEL_INFO, "Read %d TCP ports:\n", *tcp_relay_port_count);
281 int i;
282
283 for (i = 0; i < *tcp_relay_port_count; i ++) {
284 write_log(LOG_LEVEL_INFO, "Port #%d: %u\n", i, (*tcp_relay_ports)[i]);
285 }
286 }
287 }
288
289 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false");
290
291 if (*enable_motd) {
292 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_MOTD, *motd);
293 }
294
295 return 1;
296}
297
298/**
299 *
300 * Converts a hex string with even number of characters into binary.
301 *
302 * Important: You are responsible for freeing the return value.
303 *
304 * @return binary on success,
305 * NULL on failure.
306 */
307uint8_t *hex_string_to_bin(char *hex_string)
308{
309 if (strlen(hex_string) % 2 != 0) {
310 return NULL;
311 }
312
313 size_t len = strlen(hex_string) / 2;
314 uint8_t *ret = malloc(len);
315
316 char *pos = hex_string;
317 size_t i;
318 for (i = 0; i < len; ++i, pos += 2) {
319 sscanf(pos, "%2hhx", &ret[i]);
320 }
321
322 return ret;
323}
324
325int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6)
326{
327 const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes";
328
329 const char *NAME_PUBLIC_KEY = "public_key";
330 const char *NAME_PORT = "port";
331 const char *NAME_ADDRESS = "address";
332
333 config_t cfg;
334
335 config_init(&cfg);
336
337 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
338 write_log(LOG_LEVEL_ERROR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
339 config_destroy(&cfg);
340 return 0;
341 }
342
343 config_setting_t *node_list = config_lookup(&cfg, NAME_BOOTSTRAP_NODES);
344
345 if (node_list == NULL) {
346 write_log(LOG_LEVEL_WARNING, "No '%s' setting in the configuration file. Skipping bootstrapping.\n", NAME_BOOTSTRAP_NODES);
347 config_destroy(&cfg);
348 return 1;
349 }
350
351 if (config_setting_length(node_list) == 0) {
352 write_log(LOG_LEVEL_WARNING, "No bootstrap nodes found. Skipping bootstrapping.\n");
353 config_destroy(&cfg);
354 return 1;
355 }
356
357 int bs_port;
358 const char *bs_address;
359 const char *bs_public_key;
360
361 config_setting_t *node;
362
363 int i = 0;
364
365 while (config_setting_length(node_list)) {
366
367 node = config_setting_get_elem(node_list, 0);
368
369 if (node == NULL) {
370 config_destroy(&cfg);
371 return 0;
372 }
373
374 // Check that all settings are present
375 if (config_setting_lookup_string(node, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE) {
376 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PUBLIC_KEY);
377 goto next;
378 }
379
380 if (config_setting_lookup_int(node, NAME_PORT, &bs_port) == CONFIG_FALSE) {
381 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PORT);
382 goto next;
383 }
384
385 if (config_setting_lookup_string(node, NAME_ADDRESS, &bs_address) == CONFIG_FALSE) {
386 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_ADDRESS);
387 goto next;
388 }
389
390 // Process settings
391 if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES * 2) {
392 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_PUBLIC_KEY,
393 bs_public_key);
394 goto next;
395 }
396
397 if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {
398 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\n", i, NAME_PORT,
399 bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
400 goto next;
401 }
402
403 uint8_t *bs_public_key_bin = hex_string_to_bin((char *)bs_public_key);
404 const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
405 bs_public_key_bin);
406 free(bs_public_key_bin);
407
408 if (!address_resolved) {
409 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_ADDRESS, bs_address);
410 goto next;
411 }
412
413 write_log(LOG_LEVEL_INFO, "Successfully added bootstrap node #%d: %s:%d %s\n", i, bs_address, bs_port, bs_public_key);
414
415next:
416 // config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly
417 // though it's freed when the element is removed, so we free it right away in order to keep memory
418 // consumption minimal
419 config_setting_remove_elem(node_list, 0);
420 i++;
421 }
422
423 config_destroy(&cfg);
424
425 return 1;
426}
diff --git a/other/bootstrap_daemon/src/config.h b/other/bootstrap_daemon/src/config.h
new file mode 100644
index 00000000..13cf929a
--- /dev/null
+++ b/other/bootstrap_daemon/src/config.h
@@ -0,0 +1,52 @@
1/* config.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Functionality related to dealing with the config file.
5 *
6 * Copyright (C) 2014-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#ifndef CONFIG_H
26#define CONFIG_H
27
28#include "../../../toxcore/DHT.h"
29
30/**
31 * Gets general config options from the config file.
32 *
33 * Important: You are responsible for freeing `pid_file_path` and `keys_file_path`
34 * also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports`
35 * and also `motd` iff `enable_motd` is set.
36 *
37 * @return 1 on success,
38 * 0 on failure, doesn't modify any data pointed by arguments.
39 */
40int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
41 int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
42 int *tcp_relay_port_count, int *enable_motd, char **motd);
43
44/**
45 * Bootstraps off nodes listed in the config file.
46 *
47 * @return 1 on success, some or no bootstrap nodes were added
48 * 0 on failure, a error accured while parsing config file.
49 */
50int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6);
51
52#endif // CONFIG_H
diff --git a/other/bootstrap_daemon/src/config_defaults.h b/other/bootstrap_daemon/src/config_defaults.h
new file mode 100644
index 00000000..17bffd3a
--- /dev/null
+++ b/other/bootstrap_daemon/src/config_defaults.h
@@ -0,0 +1,42 @@
1/* config_defaults.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Default config options for when they are missing in the config file.
5 *
6 * Copyright (C) 2014-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#ifndef CONFIG_DEFAULTS_H
26#define CONFIG_DEFAULTS_H
27
28#include "global.h"
29
30#define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid"
31#define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys"
32#define DEFAULT_PORT 33445
33#define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false
34#define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false
35#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
36#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false
37#define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly
38#define DEFAULT_TCP_RELAY_PORTS_COUNT 3
39#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false
40#define DEFAULT_MOTD DAEMON_NAME
41
42#endif // CONFIG_DEFAULTS_H
diff --git a/other/bootstrap_daemon/src/global.h b/other/bootstrap_daemon/src/global.h
new file mode 100644
index 00000000..9ae3ec45
--- /dev/null
+++ b/other/bootstrap_daemon/src/global.h
@@ -0,0 +1,34 @@
1/* global.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Globally used defines.
5 *
6 * Copyright (C) 2014-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#ifndef GLOBAL_H
26#define GLOBAL_H
27
28#define DAEMON_NAME "tox-bootstrapd"
29#define DAEMON_VERSION_NUMBER 2016010100UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day
30
31#define MIN_ALLOWED_PORT 1
32#define MAX_ALLOWED_PORT 65535
33
34#endif // GLOBAL_H
diff --git a/other/bootstrap_daemon/src/log.c b/other/bootstrap_daemon/src/log.c
new file mode 100644
index 00000000..d441b98e
--- /dev/null
+++ b/other/bootstrap_daemon/src/log.c
@@ -0,0 +1,117 @@
1/* log.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Logging utility with support of multipel logging backends.
5 *
6 * Copyright (C) 2015-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include "log.h"
26
27#include "global.h"
28
29#include <syslog.h>
30
31#include <stdarg.h>
32#include <stdio.h>
33
34LOG_BACKEND current_backend = -1;
35
36bool open_log(LOG_BACKEND backend)
37{
38 if (current_backend != -1) {
39 return false;
40 }
41
42 if (backend == LOG_BACKEND_SYSLOG) {
43 openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
44 }
45
46 current_backend = backend;
47
48 return true;
49}
50
51bool close_log()
52{
53 if (current_backend == -1) {
54 return false;
55 }
56
57 if (current_backend == LOG_BACKEND_SYSLOG) {
58 closelog();
59 }
60
61 current_backend = -1;
62
63 return true;
64}
65
66int level_syslog(LOG_LEVEL level)
67{
68 switch (level) {
69 case LOG_LEVEL_INFO:
70 return LOG_INFO;
71 case LOG_LEVEL_WARNING:
72 return LOG_WARNING;
73 case LOG_LEVEL_ERROR:
74 return LOG_ERR;
75 }
76}
77
78void log_syslog(LOG_LEVEL level, const char *format, va_list args)
79{
80 vsyslog(level_syslog(level), format, args);
81}
82
83FILE* level_stdout(LOG_LEVEL level)
84{
85 switch (level) {
86 case LOG_LEVEL_INFO:
87 return stdout;
88 case LOG_LEVEL_WARNING: // intentional fallthrough
89 case LOG_LEVEL_ERROR:
90 return stderr;
91 }
92}
93
94void log_stdout(LOG_LEVEL level, const char *format, va_list args)
95{
96 vfprintf(level_stdout(level), format, args);
97 fflush(level_stdout(level));
98}
99
100bool write_log(LOG_LEVEL level, const char *format, ...)
101{
102 va_list args;
103 va_start(args, format);
104
105 switch (current_backend) {
106 case LOG_BACKEND_SYSLOG:
107 log_syslog(level, format, args);
108 break;
109 case LOG_BACKEND_STDOUT:
110 log_stdout(level, format, args);
111 break;
112 }
113
114 va_end(args);
115
116 return current_backend != -1;
117}
diff --git a/other/bootstrap_daemon/src/log.h b/other/bootstrap_daemon/src/log.h
new file mode 100644
index 00000000..61cb2ee3
--- /dev/null
+++ b/other/bootstrap_daemon/src/log.h
@@ -0,0 +1,64 @@
1/* log.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Logging utility with support of multipel logging backends.
5 *
6 * Copyright (C) 2015-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#ifndef LOG_H
26#define LOG_H
27
28#include <stdbool.h>
29
30typedef enum LOG_BACKEND {
31 LOG_BACKEND_SYSLOG,
32 LOG_BACKEND_STDOUT
33} LOG_BACKEND;
34
35typedef enum LOG_LEVEL {
36 LOG_LEVEL_INFO,
37 LOG_LEVEL_WARNING,
38 LOG_LEVEL_ERROR
39} LOG_LEVEL;
40
41/**
42 * Initializes logger.
43 * @param backend Specifies which backend to use.
44 * @return true on success, flase if log is already opened.
45 */
46bool open_log(LOG_BACKEND backend);
47
48/**
49 * Releases all used resources by the logger.
50 * @return true on success, flase if log is already closed.
51 */
52bool close_log();
53
54/**
55 * Writes a message to the log.
56 * @param level Log level to use.
57 * @param format printf-like format string.
58 * @param ... Zero or more arguments, similar to printf function.
59 * @return true on success, flase if log is closed.
60 */
61bool write_log(LOG_LEVEL level, const char *format, ...);
62
63
64#endif // LOG_H
diff --git a/other/bootstrap_daemon/src/tox-bootstrapd.c b/other/bootstrap_daemon/src/tox-bootstrapd.c
new file mode 100644
index 00000000..e252a37d
--- /dev/null
+++ b/other/bootstrap_daemon/src/tox-bootstrapd.c
@@ -0,0 +1,342 @@
1/* tox-bootstrapd.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Main file.
5 *
6 * Copyright (C) 2014-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25// system provided
26#include <unistd.h>
27
28// C
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33// toxcore
34#include "../../../toxcore/LAN_discovery.h"
35#include "../../../toxcore/onion_announce.h"
36#include "../../../toxcore/TCP_server.h"
37#include "../../../toxcore/util.h"
38
39// misc
40#include "../../bootstrap_node_packets.h"
41
42#include "command_line_arguments.h"
43#include "config.h"
44#include "global.h"
45#include "log.h"
46
47
48#define SLEEP_MILLISECONDS(MS) usleep(1000*MS)
49
50// Uses the already existing key or creates one if it didn't exist
51//
52// retirns 1 on success
53// 0 on failure - no keys were read or stored
54
55int manage_keys(DHT *dht, char *keys_file_path)
56{
57 const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
58 uint8_t keys[KEYS_SIZE];
59 FILE *keys_file;
60
61 // Check if file exits, proceed to open and load keys
62 keys_file = fopen(keys_file_path, "r");
63
64 if (keys_file != NULL) {
65 const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
66
67 if (read_size != KEYS_SIZE) {
68 fclose(keys_file);
69 return 0;
70 }
71
72 memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
73 memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
74 } else {
75 // Otherwise save new keys
76 memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
77 memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
78
79 keys_file = fopen(keys_file_path, "w");
80
81 if (!keys_file)
82 return 0;
83
84 const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
85
86 if (write_size != KEYS_SIZE) {
87 fclose(keys_file);
88 return 0;
89 }
90 }
91
92 fclose(keys_file);
93
94 return 1;
95}
96
97// Prints public key
98
99void print_public_key(const uint8_t *public_key)
100{
101 char buffer[2 * crypto_box_PUBLICKEYBYTES + 1];
102 int index = 0;
103
104 size_t i;
105
106 for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {
107 index += sprintf(buffer + index, "%02hhX", public_key[i]);
108 }
109
110 write_log(LOG_LEVEL_INFO, "Public Key: %s\n", buffer);
111
112 return;
113}
114
115// Demonizes the process, appending PID to the PID file and closing file descriptors based on log backend
116// Terminates the application if the daemonization fails.
117
118void daemonize(LOG_BACKEND log_backend, char *pid_file_path)
119{
120 // Check if the PID file exists
121 FILE *pid_file;
122
123 if ((pid_file = fopen(pid_file_path, "r"))) {
124 write_log(LOG_LEVEL_WARNING, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path);
125 fclose(pid_file);
126 }
127
128 // Open the PID file for writing
129 pid_file = fopen(pid_file_path, "a+");
130 if (pid_file == NULL) {
131 write_log(LOG_LEVEL_ERROR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path);
132 exit(1);
133 }
134
135 // Fork off from the parent process
136 const pid_t pid = fork();
137
138 if (pid > 0) {
139 fprintf(pid_file, "%d", pid);
140 fclose(pid_file);
141 write_log(LOG_LEVEL_INFO, "Forked successfully: PID: %d.\n", pid);
142 exit(0);
143 } else {
144 fclose(pid_file);
145 }
146
147 if (pid < 0) {
148 write_log(LOG_LEVEL_ERROR, "Forking failed. Exiting.\n");
149 exit(1);
150 }
151
152 // Create a new SID for the child process
153 if (setsid() < 0) {
154 write_log(LOG_LEVEL_ERROR, "SID creation failure. Exiting.\n");
155 exit(1);
156 }
157
158 // Change the file mode mask
159 umask(0);
160
161 // Change the current working directory
162 if ((chdir("/")) < 0) {
163 write_log(LOG_LEVEL_ERROR, "Couldn't change working directory to '/'. Exiting.\n");
164 exit(1);
165 }
166
167 // Go quiet
168 if (log_backend != LOG_BACKEND_STDOUT) {
169 close(STDOUT_FILENO);
170 close(STDIN_FILENO);
171 close(STDERR_FILENO);
172 }
173}
174
175int main(int argc, char *argv[])
176{
177 char *cfg_file_path;
178 LOG_BACKEND log_backend;
179 bool run_in_foreground;
180
181 // choose backend for printing command line argument parsing output based on whether the daemon is being run from a terminal
182 log_backend = isatty(STDOUT_FILENO) ? LOG_BACKEND_STDOUT : LOG_BACKEND_SYSLOG;
183
184 open_log(log_backend);
185 handle_command_line_arguments(argc, argv, &cfg_file_path, &log_backend, &run_in_foreground);
186 close_log();
187
188 open_log(log_backend);
189
190 write_log(LOG_LEVEL_INFO, "Running \"%s\" version %lu.\n", DAEMON_NAME, DAEMON_VERSION_NUMBER);
191
192 char *pid_file_path, *keys_file_path;
193 int port;
194 int enable_ipv6;
195 int enable_ipv4_fallback;
196 int enable_lan_discovery;
197 int enable_tcp_relay;
198 uint16_t *tcp_relay_ports;
199 int tcp_relay_port_count;
200 int enable_motd;
201 char *motd;
202
203 if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback,
204 &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {
205 write_log(LOG_LEVEL_INFO, "General config read successfully\n");
206 } else {
207 write_log(LOG_LEVEL_ERROR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
208 return 1;
209 }
210
211 if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {
212 write_log(LOG_LEVEL_ERROR, "Invalid port: %d, should be in [%d, %d]. Exiting.\n", port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
213 return 1;
214 }
215
216 if (!run_in_foreground) {
217 daemonize(log_backend, pid_file_path);
218 }
219
220 free(pid_file_path);
221
222 IP ip;
223 ip_init(&ip, enable_ipv6);
224
225 Networking_Core *net = new_networking(ip, port);
226
227 if (net == NULL) {
228 if (enable_ipv6 && enable_ipv4_fallback) {
229 write_log(LOG_LEVEL_WARNING, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n");
230 enable_ipv6 = 0;
231 ip_init(&ip, enable_ipv6);
232 net = new_networking(ip, port);
233
234 if (net == NULL) {
235 write_log(LOG_LEVEL_ERROR, "Couldn't fallback to IPv4. Exiting.\n");
236 return 1;
237 }
238 } else {
239 write_log(LOG_LEVEL_ERROR, "Couldn't initialize networking. Exiting.\n");
240 return 1;
241 }
242 }
243
244 DHT *dht = new_DHT(net);
245
246 if (dht == NULL) {
247 write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox DHT instance. Exiting.\n");
248 return 1;
249 }
250
251 Onion *onion = new_onion(dht);
252 Onion_Announce *onion_a = new_onion_announce(dht);
253
254 if (!(onion && onion_a)) {
255 write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox Onion. Exiting.\n");
256 return 1;
257 }
258
259 if (enable_motd) {
260 if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) {
261 write_log(LOG_LEVEL_INFO, "Set MOTD successfully.\n");
262 } else {
263 write_log(LOG_LEVEL_ERROR, "Couldn't set MOTD: %s. Exiting.\n", motd);
264 return 1;
265 }
266
267 free(motd);
268 }
269
270 if (manage_keys(dht, keys_file_path)) {
271 write_log(LOG_LEVEL_INFO, "Keys are managed successfully.\n");
272 } else {
273 write_log(LOG_LEVEL_ERROR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
274 return 1;
275 }
276
277 free(keys_file_path);
278
279 TCP_Server *tcp_server = NULL;
280
281 if (enable_tcp_relay) {
282 if (tcp_relay_port_count == 0) {
283 write_log(LOG_LEVEL_ERROR, "No TCP relay ports read. Exiting.\n");
284 return 1;
285 }
286
287 tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_secret_key, onion);
288
289 // tcp_relay_port_count != 0 at this point
290 free(tcp_relay_ports);
291
292 if (tcp_server != NULL) {
293 write_log(LOG_LEVEL_INFO, "Initialized Tox TCP server successfully.\n");
294 } else {
295 write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox TCP server. Exiting.\n");
296 return 1;
297 }
298 }
299
300 if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
301 write_log(LOG_LEVEL_INFO, "List of bootstrap nodes read successfully.\n");
302 } else {
303 write_log(LOG_LEVEL_ERROR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path);
304 return 1;
305 }
306
307 print_public_key(dht->self_public_key);
308
309 uint64_t last_LANdiscovery = 0;
310 const uint16_t htons_port = htons(port);
311
312 int waiting_for_dht_connection = 1;
313
314 if (enable_lan_discovery) {
315 LANdiscovery_init(dht);
316 write_log(LOG_LEVEL_INFO, "Initialized LAN discovery successfully.\n");
317 }
318
319 while (1) {
320 do_DHT(dht);
321
322 if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
323 send_LANdiscovery(htons_port, dht);
324 last_LANdiscovery = unix_time();
325 }
326
327 if (enable_tcp_relay) {
328 do_TCP_server(tcp_server);
329 }
330
331 networking_poll(dht->net);
332
333 if (waiting_for_dht_connection && DHT_isconnected(dht)) {
334 write_log(LOG_LEVEL_INFO, "Connected to another bootstrap node successfully.\n");
335 waiting_for_dht_connection = 0;
336 }
337
338 SLEEP_MILLISECONDS(30);
339 }
340
341 return 1;
342}