diff --git a/build/Makefile.am b/build/Makefile.am
index c0e59645..ea844b3f 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -10,5 +10,5 @@ include ../toxencryptsave/Makefile.inc
include ../toxav/Makefile.inc
include ../other/Makefile.inc
include ../testing/Makefile.inc
-include ../other/bootstrap_daemon/Makefile.inc
+include ../other/bootstrap_daemon/src/Makefile.inc
include ../auto_tests/Makefile.inc
diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c
index 52e84315..16dc87b9 100644
--- a/other/DHT_bootstrap.c
+++ b/other/DHT_bootstrap.c
@@ -40,7 +40,7 @@
#include "../testing/misc_tools.c"
#ifdef DHT_NODE_EXTRA_PACKETS
-#include "./bootstrap_node_packets.c"
+#include "./bootstrap_node_packets.h"
#define DHT_VERSION_NUMBER 1
#define DHT_MOTD "This is a test motd"
diff --git a/other/Makefile.inc b/other/Makefile.inc
index 368a32f2..c86b7922 100644
--- a/other/Makefile.inc
+++ b/other/Makefile.inc
@@ -2,7 +2,9 @@ bin_PROGRAMS += DHT_bootstrap
DHT_bootstrap_SOURCES = ../other/DHT_bootstrap.c \
../toxcore/DHT.h \
- ../toxcore/friend_requests.h
+ ../toxcore/friend_requests.h \
+ ../other/bootstrap_node_packets.h \
+ ../other/bootstrap_node_packets.c
DHT_bootstrap_CFLAGS = -I$(top_srcdir)/other \
$(LIBSODIUM_CFLAGS) \
diff --git a/other/bootstrap_daemon/Makefile.inc b/other/bootstrap_daemon/Makefile.inc
deleted file mode 100644
index f274aba0..00000000
--- a/other/bootstrap_daemon/Makefile.inc
+++ /dev/null
@@ -1,27 +0,0 @@
-if BUILD_DHT_BOOTSTRAP_DAEMON
-
-bin_PROGRAMS += tox-bootstrapd
-
-tox_bootstrapd_SOURCES = \
- ../other/bootstrap_daemon/tox-bootstrapd.c
-
-tox_bootstrapd_CFLAGS = \
- -I$(top_srcdir)/other/bootstrap_daemon \
- $(LIBSODIUM_CFLAGS) \
- $(NACL_CFLAGS) \
- $(LIBCONFIG_CFLAGS)
-
-tox_bootstrapd_LDADD = \
- $(LIBSODIUM_LDFLAGS) \
- $(NACL_LDFLAGS) \
- libtoxcore.la \
- $(LIBCONFIG_LIBS) \
- $(LIBSODIUM_LIBS) \
- $(NACL_LIBS)
-
-endif
-
-EXTRA_DIST += \
- $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.conf \
- $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.sh
-
diff --git a/other/bootstrap_daemon/README.md b/other/bootstrap_daemon/README.md
index e77e3ae0..93e390ef 100644
--- a/other/bootstrap_daemon/README.md
+++ b/other/bootstrap_daemon/README.md
@@ -1,17 +1,29 @@
#Instructions
- [For `systemd` users](#systemd)
+ - [Setting up](#systemd-setting-up)
+ - [Updating](#systemd-updating)
- [Troubleshooting](#systemd-troubleshooting)
-- [For `init.d` users](#initd)
- - [Troubleshooting](#initd-troubleshooting)
+- [For `SysVinit` users](#sysvinit)
+ - [Setting up](#sysvinit-setting-up)
+ - [Updating](#sysvinit-updating)
+ - [Troubleshooting](#sysvinit-troubleshooting)
+
+- [For `Docker` users](#docker)
+ - [Setting up](#docker-setting-up)
+ - [Updating](#docker-updating)
+ - [Troubleshooting](#docker-troubleshooting)
-These instructions are primarily tested on Debian Linux, Wheezy for init.d and Jessie for systemd, but they should work on other POSIX-compliant systems too.
+These instructions are primarily tested on Debian Linux, Wheezy for SysVinit and Jessie for systemd, but they should work on other POSIX-compliant systems too.
-##For `systemd` users:
+##For `systemd` users
+
+
+###Setting up
For security reasons we run the daemon under its own user.
@@ -56,8 +68,31 @@ Get your public key and check that the daemon initialized correctly:
sudo grep "tox-bootstrapd" /var/log/syslog
```
+
+###Updating
+
+You want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.
+
+To update the daemon first stop it:
+
+```sh
+sudo systemctl stop tox-bootstrapd.service
+```
+
+Then update your toxcore git repository, rebuild the toxcore and the daemon and make sure to install them.
+
+Check if `tox-bootstrapd.service` in toxcore git repository was modified since the last time you copied it, as you might need to update it too.
+
+After all of this is done, simply start the daemon back again:
+
+```sh
+sudo systemctl start tox-bootstrapd.service
+```
+
+Note that `tox-bootstrapd.service` file might
+
-###Troubleshooting:
+###Troubleshooting
- Check daemon's status:
```sh
@@ -80,8 +115,11 @@ sudo journalctl -f _SYSTEMD_UNIT=tox-bootstrapd.service
- Make sure tox-bootstrapd location matches its path in tox-bootstrapd.service file.
-
-##For `init.d` users
+
+##For `SysVinit` users
+
+
+###Setting up
For security reasons we run the daemon under its own user.
@@ -126,8 +164,29 @@ Get your public key and check that the daemon initialized correctly:
sudo grep "tox-bootstrapd" /var/log/syslog
```
-
-###Troubleshooting:
+
+###Updating
+
+You want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.
+
+To update the daemon first stop it:
+
+```sh
+sudo service tox-bootstrapd stop
+```
+
+Then update your toxcore git repository, rebuild the toxcore and the daemon and make sure to install them.
+
+Check if `tox-bootstrapd.sh` in toxcore git repository was modified since the last time you copied it, as you might need to update it too.
+
+After all of this is done, simply start the daemon back again:
+
+```sh
+sudo service tox-bootstrapd start
+```
+
+
+###Troubleshooting
- Check daemon's status:
```sh
@@ -146,3 +205,63 @@ sudo grep "tox-bootstrapd" /var/log/syslog
- Make sure tox-bootstrapd has read permission for the config file.
- Make sure tox-bootstrapd location matches its path in the `/etc/init.d/tox-bootstrapd` init script.
+
+
+
+##For `Docker` users:
+
+
+###Setting up
+
+If you are familiar with Docker and would rather run the daemon in a Docker container, run the following from this directory:
+
+```sh
+sudo docker build -t tox-bootstrapd docker/
+
+sudo useradd --home-dir /var/lib/tox-bootstrapd --create-home --system --shell /sbin/nologin --comment "Account to run Tox's DHT bootstrap daemon" --user-group tox-bootstrapd
+sudo chmod 700 /var/lib/tox-bootstrapd
+
+sudo docker run -d --name tox-bootstrapd --restart always -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ -p 443:443 -p 3389:3389 -p 33445:33445 -p 33445:33445/udp tox-bootstrapd
+```
+
+We create a new user and protect its home directory in order to mount it in the Docker image, so that the kyepair the daemon uses would be stored on the host system, which makes it less likely that you would loose the keypair while playing with or updating the Docker container.
+
+You can check logs for your public key or any errors:
+```sh
+sudo docker logs tox-bootstrapd
+```
+
+Note that the Docker container runs a script which pulls a list of bootstrap nodes off https://nodes.tox.chat/ and adds them in the config file.
+
+
+###Updating
+
+You want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.
+
+To update the daemon, all you need is to erase current container with its image:
+
+```sh
+sudo docker stop tox-bootstrapd
+sudo docker rm tox-bootstrapd
+sudo docker rmi tox-bootstrapd
+```
+
+Then rebuild and run the image again:
+
+```sh
+sudo docker build -t tox-bootstrapd docker/
+sudo docker run -d --name tox-bootstrapd --restart always -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ -p 443:443 -p 3389:3389 -p 33445:33445 -p 33445:33445/udp tox-bootstrapd
+```
+
+
+###Troubleshooting
+
+- Check if the container is running:
+```sh
+sudo docker ps -a
+```
+
+- Check the log for errors:
+```sh
+sudo docker logs tox-bootstrapd
+```
diff --git a/other/bootstrap_daemon/docker/Dockerfile b/other/bootstrap_daemon/docker/Dockerfile
new file mode 100644
index 00000000..ef9d525c
--- /dev/null
+++ b/other/bootstrap_daemon/docker/Dockerfile
@@ -0,0 +1,59 @@
+FROM debian:jessie
+
+# get all deps
+RUN apt-get update && apt-get install -y \
+ build-essential \
+ libtool \
+ autotools-dev \
+ automake \
+ checkinstall \
+ check \
+ git \
+ yasm \
+ libsodium-dev \
+ libconfig-dev \
+ python3 \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
+
+# install toxcore and daemon
+WORKDIR /root/
+RUN git clone https://github.com/irungentoo/toxcore
+WORKDIR /root/toxcore/
+RUN ./autogen.sh
+RUN ./configure --enable-daemon
+RUN make -j`nproc`
+RUN make install -j`nproc`
+RUN ldconfig
+
+WORKDIR /root/toxcore/other/bootstrap_daemon/
+
+# add new user
+RUN useradd --home-dir /var/lib/tox-bootstrapd --create-home \
+ --system --shell /sbin/nologin \
+ --comment "Account to run Tox's DHT bootstrap daemon" \
+ --user-group tox-bootstrapd
+RUN chmod 700 /var/lib/tox-bootstrapd
+
+RUN cp tox-bootstrapd.conf /etc/tox-bootstrapd.conf
+
+# remove all the example bootstrap nodes from the config file
+RUN N=-1 && \
+ while grep -q "bootstrap_nodes =" /etc/tox-bootstrapd.conf; \
+ do \
+ head -n $N tox-bootstrapd.conf > /etc/tox-bootstrapd.conf; \
+ N=$((N-1)); \
+ done
+
+# add bootstrap nodes from https://nodes.tox.chat/
+RUN python3 docker/get-nodes.py >> /etc/tox-bootstrapd.conf
+
+USER tox-bootstrapd
+
+ENTRYPOINT /usr/local/bin/tox-bootstrapd \
+ --config /etc/tox-bootstrapd.conf \
+ --log-backend stdout \
+ --foreground
+
+EXPOSE 443 3389 33445
+EXPOSE 33445/udp
diff --git a/other/bootstrap_daemon/docker/get-nodes.py b/other/bootstrap_daemon/docker/get-nodes.py
new file mode 100644
index 00000000..9a284748
--- /dev/null
+++ b/other/bootstrap_daemon/docker/get-nodes.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+"""
+Copyright (c) 2016 by nurupo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+# Gets a list of nodes from https://nodes.tox.chat/json and prints them out
+# in the format of tox-bootstrapd config file.
+
+import urllib.request
+import json
+
+response = urllib.request.urlopen('https://nodes.tox.chat/json')
+raw_json = response.read().decode('ascii', 'ignore')
+nodes = json.loads(raw_json)['nodes']
+
+output = 'bootstrap_nodes = ('
+
+for node in nodes:
+ node_output = ' { // ' + node['maintainer'] + '\n'
+ node_output += ' public_key = "' + node['public_key'] + '"\n'
+ node_output += ' port = ' + str(node['port']) + '\n'
+ node_output += ' address = "'
+ if len(node['ipv4']) > 4:
+ output += node_output + node['ipv4'] + '"\n },\n'
+ if len(node['ipv6']) > 4:
+ output += node_output + node['ipv6'] + '"\n },\n'
+
+# remove last comma
+output = output[:-2] + '\n)\n'
+
+print(output)
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 @@
+if BUILD_DHT_BOOTSTRAP_DAEMON
+
+bin_PROGRAMS += tox-bootstrapd
+
+tox_bootstrapd_SOURCES = \
+ ../other/bootstrap_daemon/src/command_line_arguments.c \
+ ../other/bootstrap_daemon/src/command_line_arguments.h \
+ ../other/bootstrap_daemon/src/config.c \
+ ../other/bootstrap_daemon/src/config_defaults.h \
+ ../other/bootstrap_daemon/src/config.h \
+ ../other/bootstrap_daemon/src/log.c \
+ ../other/bootstrap_daemon/src/log.h \
+ ../other/bootstrap_daemon/src/tox-bootstrapd.c \
+ ../other/bootstrap_node_packets.c \
+ ../other/bootstrap_node_packets.h
+
+
+tox_bootstrapd_CFLAGS = \
+ -I$(top_srcdir)/other/bootstrap_daemon \
+ $(LIBSODIUM_CFLAGS) \
+ $(NACL_CFLAGS) \
+ $(LIBCONFIG_CFLAGS)
+
+tox_bootstrapd_LDADD = \
+ $(LIBSODIUM_LDFLAGS) \
+ $(NACL_LDFLAGS) \
+ libtoxcore.la \
+ $(LIBCONFIG_LIBS) \
+ $(LIBSODIUM_LIBS) \
+ $(NACL_LIBS)
+
+endif
+
+EXTRA_DIST += \
+ $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.conf \
+ $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.service \
+ $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.sh
+
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 @@
+/* command_line_arguments.c
+ *
+ * Tox DHT bootstrap daemon.
+ * Command line argument handling.
+ *
+ * Copyright (C) 2015-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#include "command_line_arguments.h"
+
+#include "global.h"
+
+#include
+
+#include
+#include
+
+
+/**
+ * Prints --help message
+ */
+void print_help()
+{
+ // 2 space ident
+ // make sure all lines fit into 80 columns
+ // make sure options are listed in alphabetical order
+ write_log(LOG_LEVEL_INFO,
+ "Usage: tox-bootstrapd [OPTION]... --config=FILE_PATH\n"
+ "\n"
+ "Options:\n"
+ " --config=FILE_PATH Specify path to the config file.\n"
+ " This is a required option.\n"
+ " Set FILE_PATH to a path to an empty file in order to\n"
+ " use default settings.\n"
+ " --foreground Run the daemon in foreground. The daemon won't fork\n"
+ " (detach from the terminal) and won't use the PID file.\n"
+ " --help Print this help message.\n"
+ " --log-backend=BACKEND Specify which logging backend to use.\n"
+ " Valid BACKEND values (case sensetive):\n"
+ " syslog Writes log messages to syslog.\n"
+ " Default option when no --log-backend is\n"
+ " specified.\n"
+ " stdout Writes log messages to stdout/stderr.\n"
+ " --version Print version information.\n");
+}
+
+void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground)
+{
+ if (argc < 2) {
+ write_log(LOG_LEVEL_ERROR, "Error: No arguments provided.\n\n");
+ print_help();
+ exit(1);
+ }
+
+ opterr = 0;
+
+ static struct option long_options[] = {
+ {"config", required_argument, 0, 'c'}, // required option
+ {"foreground", no_argument, 0, 'f'},
+ {"help", no_argument, 0, 'h'},
+ {"log-backend", required_argument, 0, 'l'}, // optional, defaults to syslog
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0 }
+ };
+
+ bool cfg_file_path_set = false;
+ bool log_backend_set = false;
+
+ *run_in_foreground = false;
+
+ int opt;
+
+ while ((opt = getopt_long(argc, argv, ":", long_options, NULL)) != -1) {
+
+ switch (opt) {
+
+ case 'c':
+ *cfg_file_path = optarg;
+ cfg_file_path_set = true;
+ break;
+
+ case 'f':
+ *run_in_foreground = true;
+ break;
+
+ case 'h':
+ print_help();
+ exit(0);
+
+ case 'l':
+ if (strcmp(optarg, "syslog") == 0) {
+ *log_backend = LOG_BACKEND_SYSLOG;
+ log_backend_set = true;
+ } else if (strcmp(optarg, "stdout") == 0) {
+ *log_backend = LOG_BACKEND_STDOUT;
+ log_backend_set = true;
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Error: Invalid BACKEND value for --log-backend option passed: %s\n\n", optarg);
+ print_help();
+ exit(1);
+ }
+ break;
+
+ case 'v':
+ write_log(LOG_LEVEL_INFO, "Version: %lu\n", DAEMON_VERSION_NUMBER);
+ exit(0);
+
+ case '?':
+ write_log(LOG_LEVEL_ERROR, "Error: Unrecognized option %s\n\n", argv[optind-1]);
+ print_help();
+ exit(1);
+
+ case ':':
+ write_log(LOG_LEVEL_ERROR, "Error: No argument provided for option %s\n\n", argv[optind-1]);
+ print_help();
+ exit(1);
+ }
+ }
+
+ if (!log_backend_set) {
+ *log_backend = LOG_BACKEND_SYSLOG;
+ }
+
+ if (!cfg_file_path_set) {
+ write_log(LOG_LEVEL_ERROR, "Error: The required --config option wasn't specified\n\n");
+ print_help();
+ exit(1);
+ }
+}
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 @@
+/* command_line_arguments.h
+ *
+ * Tox DHT bootstrap daemon.
+ * Command line argument handling.
+ *
+ * Copyright (C) 2015-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#ifndef COMMAND_LINE_ARGUMENTS_H
+#define COMMAND_LINE_ARGUMENTS_H
+
+#include "log.h"
+
+/**
+ * Handles command line arguments, setting cfg_file_path and log_backend.
+ * Terminates the application if incorrect arguments are specified.
+ *
+ * @param argc Argc passed into main().
+ * @param argv Argv passed into main().
+ * @param cfg_file_path Sets to the provided by the user config file path.
+ * @param log_backend Sets to the provided by the user log backend option.
+ * @param run_in_foreground Sets to the provided by the user foreground option.
+ */
+void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground);
+
+#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 @@
+/* config.c
+ *
+ * Tox DHT bootstrap daemon.
+ * Functionality related to dealing with the config file.
+ *
+ * Copyright (C) 2014-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#include "config.h"
+
+#include "config_defaults.h"
+#include "log.h"
+
+#include
+#include
+#include
+
+#include
+
+#include "../../bootstrap_node_packets.h"
+
+/**
+ * Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array.
+ *
+ * Supposed to be called from get_general_config only.
+ *
+ * Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`.
+ */
+void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)
+{
+ const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports";
+
+ *tcp_relay_port_count = 0;
+
+ config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);
+
+ if (ports_array == NULL) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS);
+
+ uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};
+
+ int i;
+
+ for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
+ write_log(LOG_LEVEL_INFO, "Port #%d: %u\n", i, default_ports[i]);
+ }
+
+ // similar procedure to the one of reading config file below
+ *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));
+
+ for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
+
+ (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];
+
+ if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
+ || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
+ write_log(LOG_LEVEL_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
+ (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
+ continue;
+ }
+
+ (*tcp_relay_port_count) ++;
+ }
+
+ // the loop above skips invalid ports, so we adjust the allocated memory size
+ if ((*tcp_relay_port_count) > 0) {
+ *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
+ } else {
+ free(*tcp_relay_ports);
+ *tcp_relay_ports = NULL;
+ }
+
+ return;
+ }
+
+ if (config_setting_is_array(ports_array) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_ERROR, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n",
+ NAME_TCP_RELAY_PORTS);
+ return;
+ }
+
+ int config_port_count = config_setting_length(ports_array);
+
+ if (config_port_count == 0) {
+ write_log(LOG_LEVEL_ERROR, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS);
+ return;
+ }
+
+ *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));
+
+ int i;
+
+ for (i = 0; i < config_port_count; i ++) {
+ config_setting_t *elem = config_setting_get_elem(ports_array, i);
+
+ if (elem == NULL) {
+ // 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
+ write_log(LOG_LEVEL_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i);
+ break;
+ }
+
+ if (config_setting_is_number(elem) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "Port #%d: Not a number. Skipping.\n", i);
+ continue;
+ }
+
+ (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);
+
+ if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
+ || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
+ write_log(LOG_LEVEL_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
+ (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
+ continue;
+ }
+
+ (*tcp_relay_port_count) ++;
+ }
+
+ // the loop above skips invalid ports, so we adjust the allocated memory size
+ if ((*tcp_relay_port_count) > 0) {
+ *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
+ } else {
+ free(*tcp_relay_ports);
+ *tcp_relay_ports = NULL;
+ }
+}
+
+int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
+ int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
+ int *tcp_relay_port_count, int *enable_motd, char **motd)
+{
+ config_t cfg;
+
+ const char *NAME_PORT = "port";
+ const char *NAME_PID_FILE_PATH = "pid_file_path";
+ const char *NAME_KEYS_FILE_PATH = "keys_file_path";
+ const char *NAME_ENABLE_IPV6 = "enable_ipv6";
+ const char *NAME_ENABLE_IPV4_FALLBACK = "enable_ipv4_fallback";
+ const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
+ const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay";
+ const char *NAME_ENABLE_MOTD = "enable_motd";
+ const char *NAME_MOTD = "motd";
+
+ config_init(&cfg);
+
+ // Read the file. If there is an error, report it and exit.
+ if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_ERROR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ return 0;
+ }
+
+ // Get port
+ if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
+ *port = DEFAULT_PORT;
+ }
+
+ // Get PID file location
+ const char *tmp_pid_file;
+
+ if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
+ tmp_pid_file = DEFAULT_PID_FILE_PATH;
+ }
+
+ *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
+ strcpy(*pid_file_path, tmp_pid_file);
+
+ // Get keys file location
+ const char *tmp_keys_file;
+
+ if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
+ tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
+ }
+
+ *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
+ strcpy(*keys_file_path, tmp_keys_file);
+
+ // Get IPv6 option
+ if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
+ *enable_ipv6 = DEFAULT_ENABLE_IPV6;
+ }
+
+ // Get IPv4 fallback option
+ if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK,
+ DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false");
+ *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK;
+ }
+
+ // Get LAN discovery option
+ if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
+ DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
+ *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
+ }
+
+ // Get TCP relay option
+ if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY,
+ DEFAULT_ENABLE_TCP_RELAY ? "true" : "false");
+ *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;
+ }
+
+ if (*enable_tcp_relay) {
+ parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);
+ } else {
+ *tcp_relay_port_count = 0;
+ }
+
+ // Get MOTD option
+ if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD,
+ DEFAULT_ENABLE_MOTD ? "true" : "false");
+ *enable_motd = DEFAULT_ENABLE_MOTD;
+ }
+
+ if (*enable_motd) {
+ // Get MOTD
+ const char *tmp_motd;
+
+ if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_MOTD);
+ write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_MOTD, DEFAULT_MOTD);
+ tmp_motd = DEFAULT_MOTD;
+ }
+
+ size_t tmp_motd_length = strlen(tmp_motd) + 1;
+ size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;
+ *motd = malloc(motd_length);
+ strncpy(*motd, tmp_motd, motd_length);
+ (*motd)[motd_length - 1] = '\0';
+ }
+
+ config_destroy(&cfg);
+
+ write_log(LOG_LEVEL_INFO, "Successfully read:\n");
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
+ write_log(LOG_LEVEL_INFO, "'%s': %d\n", NAME_PORT, *port);
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false");
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
+
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false");
+
+ // show info about tcp ports only if tcp relay is enabled
+ if (*enable_tcp_relay) {
+ if (*tcp_relay_port_count == 0) {
+ write_log(LOG_LEVEL_ERROR, "No TCP ports could be read.\n");
+ } else {
+ write_log(LOG_LEVEL_INFO, "Read %d TCP ports:\n", *tcp_relay_port_count);
+ int i;
+
+ for (i = 0; i < *tcp_relay_port_count; i ++) {
+ write_log(LOG_LEVEL_INFO, "Port #%d: %u\n", i, (*tcp_relay_ports)[i]);
+ }
+ }
+ }
+
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false");
+
+ if (*enable_motd) {
+ write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_MOTD, *motd);
+ }
+
+ return 1;
+}
+
+/**
+ *
+ * Converts a hex string with even number of characters into binary.
+ *
+ * Important: You are responsible for freeing the return value.
+ *
+ * @return binary on success,
+ * NULL on failure.
+ */
+uint8_t *hex_string_to_bin(char *hex_string)
+{
+ if (strlen(hex_string) % 2 != 0) {
+ return NULL;
+ }
+
+ size_t len = strlen(hex_string) / 2;
+ uint8_t *ret = malloc(len);
+
+ char *pos = hex_string;
+ size_t i;
+ for (i = 0; i < len; ++i, pos += 2) {
+ sscanf(pos, "%2hhx", &ret[i]);
+ }
+
+ return ret;
+}
+
+int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6)
+{
+ const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes";
+
+ const char *NAME_PUBLIC_KEY = "public_key";
+ const char *NAME_PORT = "port";
+ const char *NAME_ADDRESS = "address";
+
+ config_t cfg;
+
+ config_init(&cfg);
+
+ if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_ERROR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ return 0;
+ }
+
+ config_setting_t *node_list = config_lookup(&cfg, NAME_BOOTSTRAP_NODES);
+
+ if (node_list == NULL) {
+ write_log(LOG_LEVEL_WARNING, "No '%s' setting in the configuration file. Skipping bootstrapping.\n", NAME_BOOTSTRAP_NODES);
+ config_destroy(&cfg);
+ return 1;
+ }
+
+ if (config_setting_length(node_list) == 0) {
+ write_log(LOG_LEVEL_WARNING, "No bootstrap nodes found. Skipping bootstrapping.\n");
+ config_destroy(&cfg);
+ return 1;
+ }
+
+ int bs_port;
+ const char *bs_address;
+ const char *bs_public_key;
+
+ config_setting_t *node;
+
+ int i = 0;
+
+ while (config_setting_length(node_list)) {
+
+ node = config_setting_get_elem(node_list, 0);
+
+ if (node == NULL) {
+ config_destroy(&cfg);
+ return 0;
+ }
+
+ // Check that all settings are present
+ if (config_setting_lookup_string(node, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PUBLIC_KEY);
+ goto next;
+ }
+
+ if (config_setting_lookup_int(node, NAME_PORT, &bs_port) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PORT);
+ goto next;
+ }
+
+ if (config_setting_lookup_string(node, NAME_ADDRESS, &bs_address) == CONFIG_FALSE) {
+ write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_ADDRESS);
+ goto next;
+ }
+
+ // Process settings
+ if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES * 2) {
+ write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_PUBLIC_KEY,
+ bs_public_key);
+ goto next;
+ }
+
+ if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {
+ write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\n", i, NAME_PORT,
+ bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
+ goto next;
+ }
+
+ uint8_t *bs_public_key_bin = hex_string_to_bin((char *)bs_public_key);
+ const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
+ bs_public_key_bin);
+ free(bs_public_key_bin);
+
+ if (!address_resolved) {
+ write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_ADDRESS, bs_address);
+ goto next;
+ }
+
+ write_log(LOG_LEVEL_INFO, "Successfully added bootstrap node #%d: %s:%d %s\n", i, bs_address, bs_port, bs_public_key);
+
+next:
+ // config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly
+ // though it's freed when the element is removed, so we free it right away in order to keep memory
+ // consumption minimal
+ config_setting_remove_elem(node_list, 0);
+ i++;
+ }
+
+ config_destroy(&cfg);
+
+ return 1;
+}
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 @@
+/* config.h
+ *
+ * Tox DHT bootstrap daemon.
+ * Functionality related to dealing with the config file.
+ *
+ * Copyright (C) 2014-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include "../../../toxcore/DHT.h"
+
+/**
+ * Gets general config options from the config file.
+ *
+ * Important: You are responsible for freeing `pid_file_path` and `keys_file_path`
+ * also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports`
+ * and also `motd` iff `enable_motd` is set.
+ *
+ * @return 1 on success,
+ * 0 on failure, doesn't modify any data pointed by arguments.
+ */
+int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
+ int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
+ int *tcp_relay_port_count, int *enable_motd, char **motd);
+
+/**
+ * Bootstraps off nodes listed in the config file.
+ *
+ * @return 1 on success, some or no bootstrap nodes were added
+ * 0 on failure, a error accured while parsing config file.
+ */
+int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6);
+
+#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 @@
+/* config_defaults.h
+ *
+ * Tox DHT bootstrap daemon.
+ * Default config options for when they are missing in the config file.
+ *
+ * Copyright (C) 2014-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#ifndef CONFIG_DEFAULTS_H
+#define CONFIG_DEFAULTS_H
+
+#include "global.h"
+
+#define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid"
+#define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys"
+#define DEFAULT_PORT 33445
+#define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false
+#define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false
+#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
+#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false
+#define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly
+#define DEFAULT_TCP_RELAY_PORTS_COUNT 3
+#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false
+#define DEFAULT_MOTD DAEMON_NAME
+
+#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 @@
+/* global.h
+ *
+ * Tox DHT bootstrap daemon.
+ * Globally used defines.
+ *
+ * Copyright (C) 2014-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#define DAEMON_NAME "tox-bootstrapd"
+#define DAEMON_VERSION_NUMBER 2016010100UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day
+
+#define MIN_ALLOWED_PORT 1
+#define MAX_ALLOWED_PORT 65535
+
+#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 @@
+/* log.c
+ *
+ * Tox DHT bootstrap daemon.
+ * Logging utility with support of multipel logging backends.
+ *
+ * Copyright (C) 2015-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#include "log.h"
+
+#include "global.h"
+
+#include
+
+#include
+#include
+
+LOG_BACKEND current_backend = -1;
+
+bool open_log(LOG_BACKEND backend)
+{
+ if (current_backend != -1) {
+ return false;
+ }
+
+ if (backend == LOG_BACKEND_SYSLOG) {
+ openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
+ }
+
+ current_backend = backend;
+
+ return true;
+}
+
+bool close_log()
+{
+ if (current_backend == -1) {
+ return false;
+ }
+
+ if (current_backend == LOG_BACKEND_SYSLOG) {
+ closelog();
+ }
+
+ current_backend = -1;
+
+ return true;
+}
+
+int level_syslog(LOG_LEVEL level)
+{
+ switch (level) {
+ case LOG_LEVEL_INFO:
+ return LOG_INFO;
+ case LOG_LEVEL_WARNING:
+ return LOG_WARNING;
+ case LOG_LEVEL_ERROR:
+ return LOG_ERR;
+ }
+}
+
+void log_syslog(LOG_LEVEL level, const char *format, va_list args)
+{
+ vsyslog(level_syslog(level), format, args);
+}
+
+FILE* level_stdout(LOG_LEVEL level)
+{
+ switch (level) {
+ case LOG_LEVEL_INFO:
+ return stdout;
+ case LOG_LEVEL_WARNING: // intentional fallthrough
+ case LOG_LEVEL_ERROR:
+ return stderr;
+ }
+}
+
+void log_stdout(LOG_LEVEL level, const char *format, va_list args)
+{
+ vfprintf(level_stdout(level), format, args);
+ fflush(level_stdout(level));
+}
+
+bool write_log(LOG_LEVEL level, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ switch (current_backend) {
+ case LOG_BACKEND_SYSLOG:
+ log_syslog(level, format, args);
+ break;
+ case LOG_BACKEND_STDOUT:
+ log_stdout(level, format, args);
+ break;
+ }
+
+ va_end(args);
+
+ return current_backend != -1;
+}
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 @@
+/* log.h
+ *
+ * Tox DHT bootstrap daemon.
+ * Logging utility with support of multipel logging backends.
+ *
+ * Copyright (C) 2015-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#include
+
+typedef enum LOG_BACKEND {
+ LOG_BACKEND_SYSLOG,
+ LOG_BACKEND_STDOUT
+} LOG_BACKEND;
+
+typedef enum LOG_LEVEL {
+ LOG_LEVEL_INFO,
+ LOG_LEVEL_WARNING,
+ LOG_LEVEL_ERROR
+} LOG_LEVEL;
+
+/**
+ * Initializes logger.
+ * @param backend Specifies which backend to use.
+ * @return true on success, flase if log is already opened.
+ */
+bool open_log(LOG_BACKEND backend);
+
+/**
+ * Releases all used resources by the logger.
+ * @return true on success, flase if log is already closed.
+ */
+bool close_log();
+
+/**
+ * Writes a message to the log.
+ * @param level Log level to use.
+ * @param format printf-like format string.
+ * @param ... Zero or more arguments, similar to printf function.
+ * @return true on success, flase if log is closed.
+ */
+bool write_log(LOG_LEVEL level, const char *format, ...);
+
+
+#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 @@
+/* tox-bootstrapd.c
+ *
+ * Tox DHT bootstrap daemon.
+ * Main file.
+ *
+ * Copyright (C) 2014-2016 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+// system provided
+#include
+
+// C
+#include
+#include
+#include
+
+// toxcore
+#include "../../../toxcore/LAN_discovery.h"
+#include "../../../toxcore/onion_announce.h"
+#include "../../../toxcore/TCP_server.h"
+#include "../../../toxcore/util.h"
+
+// misc
+#include "../../bootstrap_node_packets.h"
+
+#include "command_line_arguments.h"
+#include "config.h"
+#include "global.h"
+#include "log.h"
+
+
+#define SLEEP_MILLISECONDS(MS) usleep(1000*MS)
+
+// Uses the already existing key or creates one if it didn't exist
+//
+// retirns 1 on success
+// 0 on failure - no keys were read or stored
+
+int manage_keys(DHT *dht, char *keys_file_path)
+{
+ const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
+ uint8_t keys[KEYS_SIZE];
+ FILE *keys_file;
+
+ // Check if file exits, proceed to open and load keys
+ keys_file = fopen(keys_file_path, "r");
+
+ if (keys_file != NULL) {
+ const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
+
+ if (read_size != KEYS_SIZE) {
+ fclose(keys_file);
+ return 0;
+ }
+
+ memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
+ memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
+ } else {
+ // Otherwise save new keys
+ memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
+ memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
+
+ keys_file = fopen(keys_file_path, "w");
+
+ if (!keys_file)
+ return 0;
+
+ const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
+
+ if (write_size != KEYS_SIZE) {
+ fclose(keys_file);
+ return 0;
+ }
+ }
+
+ fclose(keys_file);
+
+ return 1;
+}
+
+// Prints public key
+
+void print_public_key(const uint8_t *public_key)
+{
+ char buffer[2 * crypto_box_PUBLICKEYBYTES + 1];
+ int index = 0;
+
+ size_t i;
+
+ for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {
+ index += sprintf(buffer + index, "%02hhX", public_key[i]);
+ }
+
+ write_log(LOG_LEVEL_INFO, "Public Key: %s\n", buffer);
+
+ return;
+}
+
+// Demonizes the process, appending PID to the PID file and closing file descriptors based on log backend
+// Terminates the application if the daemonization fails.
+
+void daemonize(LOG_BACKEND log_backend, char *pid_file_path)
+{
+ // Check if the PID file exists
+ FILE *pid_file;
+
+ if ((pid_file = fopen(pid_file_path, "r"))) {
+ write_log(LOG_LEVEL_WARNING, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path);
+ fclose(pid_file);
+ }
+
+ // Open the PID file for writing
+ pid_file = fopen(pid_file_path, "a+");
+ if (pid_file == NULL) {
+ write_log(LOG_LEVEL_ERROR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path);
+ exit(1);
+ }
+
+ // Fork off from the parent process
+ const pid_t pid = fork();
+
+ if (pid > 0) {
+ fprintf(pid_file, "%d", pid);
+ fclose(pid_file);
+ write_log(LOG_LEVEL_INFO, "Forked successfully: PID: %d.\n", pid);
+ exit(0);
+ } else {
+ fclose(pid_file);
+ }
+
+ if (pid < 0) {
+ write_log(LOG_LEVEL_ERROR, "Forking failed. Exiting.\n");
+ exit(1);
+ }
+
+ // Create a new SID for the child process
+ if (setsid() < 0) {
+ write_log(LOG_LEVEL_ERROR, "SID creation failure. Exiting.\n");
+ exit(1);
+ }
+
+ // Change the file mode mask
+ umask(0);
+
+ // Change the current working directory
+ if ((chdir("/")) < 0) {
+ write_log(LOG_LEVEL_ERROR, "Couldn't change working directory to '/'. Exiting.\n");
+ exit(1);
+ }
+
+ // Go quiet
+ if (log_backend != LOG_BACKEND_STDOUT) {
+ close(STDOUT_FILENO);
+ close(STDIN_FILENO);
+ close(STDERR_FILENO);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ char *cfg_file_path;
+ LOG_BACKEND log_backend;
+ bool run_in_foreground;
+
+ // choose backend for printing command line argument parsing output based on whether the daemon is being run from a terminal
+ log_backend = isatty(STDOUT_FILENO) ? LOG_BACKEND_STDOUT : LOG_BACKEND_SYSLOG;
+
+ open_log(log_backend);
+ handle_command_line_arguments(argc, argv, &cfg_file_path, &log_backend, &run_in_foreground);
+ close_log();
+
+ open_log(log_backend);
+
+ write_log(LOG_LEVEL_INFO, "Running \"%s\" version %lu.\n", DAEMON_NAME, DAEMON_VERSION_NUMBER);
+
+ char *pid_file_path, *keys_file_path;
+ int port;
+ int enable_ipv6;
+ int enable_ipv4_fallback;
+ int enable_lan_discovery;
+ int enable_tcp_relay;
+ uint16_t *tcp_relay_ports;
+ int tcp_relay_port_count;
+ int enable_motd;
+ char *motd;
+
+ if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback,
+ &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {
+ write_log(LOG_LEVEL_INFO, "General config read successfully\n");
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
+ return 1;
+ }
+
+ if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {
+ write_log(LOG_LEVEL_ERROR, "Invalid port: %d, should be in [%d, %d]. Exiting.\n", port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
+ return 1;
+ }
+
+ if (!run_in_foreground) {
+ daemonize(log_backend, pid_file_path);
+ }
+
+ free(pid_file_path);
+
+ IP ip;
+ ip_init(&ip, enable_ipv6);
+
+ Networking_Core *net = new_networking(ip, port);
+
+ if (net == NULL) {
+ if (enable_ipv6 && enable_ipv4_fallback) {
+ write_log(LOG_LEVEL_WARNING, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n");
+ enable_ipv6 = 0;
+ ip_init(&ip, enable_ipv6);
+ net = new_networking(ip, port);
+
+ if (net == NULL) {
+ write_log(LOG_LEVEL_ERROR, "Couldn't fallback to IPv4. Exiting.\n");
+ return 1;
+ }
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Couldn't initialize networking. Exiting.\n");
+ return 1;
+ }
+ }
+
+ DHT *dht = new_DHT(net);
+
+ if (dht == NULL) {
+ write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox DHT instance. Exiting.\n");
+ return 1;
+ }
+
+ Onion *onion = new_onion(dht);
+ Onion_Announce *onion_a = new_onion_announce(dht);
+
+ if (!(onion && onion_a)) {
+ write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox Onion. Exiting.\n");
+ return 1;
+ }
+
+ if (enable_motd) {
+ if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) {
+ write_log(LOG_LEVEL_INFO, "Set MOTD successfully.\n");
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Couldn't set MOTD: %s. Exiting.\n", motd);
+ return 1;
+ }
+
+ free(motd);
+ }
+
+ if (manage_keys(dht, keys_file_path)) {
+ write_log(LOG_LEVEL_INFO, "Keys are managed successfully.\n");
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
+ return 1;
+ }
+
+ free(keys_file_path);
+
+ TCP_Server *tcp_server = NULL;
+
+ if (enable_tcp_relay) {
+ if (tcp_relay_port_count == 0) {
+ write_log(LOG_LEVEL_ERROR, "No TCP relay ports read. Exiting.\n");
+ return 1;
+ }
+
+ tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_secret_key, onion);
+
+ // tcp_relay_port_count != 0 at this point
+ free(tcp_relay_ports);
+
+ if (tcp_server != NULL) {
+ write_log(LOG_LEVEL_INFO, "Initialized Tox TCP server successfully.\n");
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox TCP server. Exiting.\n");
+ return 1;
+ }
+ }
+
+ if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
+ write_log(LOG_LEVEL_INFO, "List of bootstrap nodes read successfully.\n");
+ } else {
+ write_log(LOG_LEVEL_ERROR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path);
+ return 1;
+ }
+
+ print_public_key(dht->self_public_key);
+
+ uint64_t last_LANdiscovery = 0;
+ const uint16_t htons_port = htons(port);
+
+ int waiting_for_dht_connection = 1;
+
+ if (enable_lan_discovery) {
+ LANdiscovery_init(dht);
+ write_log(LOG_LEVEL_INFO, "Initialized LAN discovery successfully.\n");
+ }
+
+ while (1) {
+ do_DHT(dht);
+
+ if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
+ send_LANdiscovery(htons_port, dht);
+ last_LANdiscovery = unix_time();
+ }
+
+ if (enable_tcp_relay) {
+ do_TCP_server(tcp_server);
+ }
+
+ networking_poll(dht->net);
+
+ if (waiting_for_dht_connection && DHT_isconnected(dht)) {
+ write_log(LOG_LEVEL_INFO, "Connected to another bootstrap node successfully.\n");
+ waiting_for_dht_connection = 0;
+ }
+
+ SLEEP_MILLISECONDS(30);
+ }
+
+ return 1;
+}
diff --git a/other/bootstrap_daemon/tox-bootstrapd.c b/other/bootstrap_daemon/tox-bootstrapd.c
deleted file mode 100644
index 267e7238..00000000
--- a/other/bootstrap_daemon/tox-bootstrapd.c
+++ /dev/null
@@ -1,730 +0,0 @@
-/* tox-bootstrapd.c
- *
- * Tox DHT bootstrap daemon.
- *
- * Copyright (C) 2014 Tox project All Rights Reserved.
- *
- * This file is part of Tox.
- *
- * Tox is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Tox is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Tox. If not, see .
- *
- */
-
-// system provided
-#include
-#include
-#include
-#include
-#include
-
-// C
-#include
-#include
-#include
-
-// 3rd party
-#include
-
-// ./configure
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-// toxcore
-#include "../../toxcore/LAN_discovery.h"
-#include "../../toxcore/onion_announce.h"
-#include "../../toxcore/TCP_server.h"
-#include "../../toxcore/util.h"
-
-// misc
-#include "../bootstrap_node_packets.c"
-#include "../../testing/misc_tools.c"
-
-
-#define DAEMON_NAME "tox-bootstrapd"
-#define DAEMON_VERSION_NUMBER 2014101200UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day
-
-#define SLEEP_TIME_MILLISECONDS 30
-#define sleep usleep(1000*SLEEP_TIME_MILLISECONDS)
-
-#define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid"
-#define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys"
-#define DEFAULT_PORT 33445
-#define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false
-#define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false
-#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
-#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false
-#define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly
-#define DEFAULT_TCP_RELAY_PORTS_COUNT 3
-#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false
-#define DEFAULT_MOTD DAEMON_NAME
-
-#define MIN_ALLOWED_PORT 1
-#define MAX_ALLOWED_PORT 65535
-
-
-// Uses the already existing key or creates one if it didn't exist
-//
-// retirns 1 on success
-// 0 on failure - no keys were read or stored
-
-int manage_keys(DHT *dht, char *keys_file_path)
-{
- const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
- uint8_t keys[KEYS_SIZE];
- FILE *keys_file;
-
- // Check if file exits, proceed to open and load keys
- keys_file = fopen(keys_file_path, "r");
-
- if (keys_file != NULL) {
- const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
-
- if (read_size != KEYS_SIZE) {
- fclose(keys_file);
- return 0;
- }
-
- memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
- memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
- } else {
- // Otherwise save new keys
- memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
- memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
-
- keys_file = fopen(keys_file_path, "w");
-
- if (!keys_file)
- return 0;
-
- const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
-
- if (write_size != KEYS_SIZE) {
- fclose(keys_file);
- return 0;
- }
- }
-
- fclose(keys_file);
-
- return 1;
-}
-
-// Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array
-//
-// Supposed to be called from get_general_config only
-//
-// Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`
-
-void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)
-{
- const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports";
-
- *tcp_relay_port_count = 0;
-
- config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);
-
- if (ports_array == NULL) {
- syslog(LOG_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS);
- syslog(LOG_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS);
-
- uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};
-
- int i;
-
- for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
- syslog(LOG_WARNING, "Port #%d: %u\n", i, default_ports[i]);
- }
-
- // similar procedure to the one of reading config file below
- *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));
-
- for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
-
- (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];
-
- if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
- || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
- syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
- (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
- continue;
- }
-
- (*tcp_relay_port_count) ++;
- }
-
- // the loop above skips invalid ports, so we adjust the allocated memory size
- if ((*tcp_relay_port_count) > 0) {
- *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
- } else {
- free(*tcp_relay_ports);
- *tcp_relay_ports = NULL;
- }
-
- return;
- }
-
- if (config_setting_is_array(ports_array) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n",
- NAME_TCP_RELAY_PORTS);
- return;
- }
-
- int config_port_count = config_setting_length(ports_array);
-
- if (config_port_count == 0) {
- syslog(LOG_WARNING, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS);
- return;
- }
-
- *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));
-
- int i;
-
- for (i = 0; i < config_port_count; i ++) {
- config_setting_t *elem = config_setting_get_elem(ports_array, i);
-
- if (elem == NULL) {
- // 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
- syslog(LOG_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i);
- break;
- }
-
- if (config_setting_is_number(elem) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "Port #%d: Not a number. Skipping.\n", i);
- continue;
- }
-
- (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);
-
- if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
- || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
- syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
- (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
- continue;
- }
-
- (*tcp_relay_port_count) ++;
- }
-
- // the loop above skips invalid ports, so we adjust the allocated memory size
- if ((*tcp_relay_port_count) > 0) {
- *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
- } else {
- free(*tcp_relay_ports);
- *tcp_relay_ports = NULL;
- }
-}
-
-// Gets general config options
-//
-// Important: you are responsible for freeing `pid_file_path` and `keys_file_path`
-// also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports`
-// and also `motd` iff `enable_motd` is set
-//
-// returns 1 on success
-// 0 on failure, doesn't modify any data pointed by arguments
-
-int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port,
- int *enable_ipv6,
- int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
- int *tcp_relay_port_count, int *enable_motd, char **motd)
-{
- config_t cfg;
-
- const char *NAME_PORT = "port";
- const char *NAME_PID_FILE_PATH = "pid_file_path";
- const char *NAME_KEYS_FILE_PATH = "keys_file_path";
- const char *NAME_ENABLE_IPV6 = "enable_ipv6";
- const char *NAME_ENABLE_IPV4_FALLBACK = "enable_ipv4_fallback";
- const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
- const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay";
- const char *NAME_ENABLE_MOTD = "enable_motd";
- const char *NAME_MOTD = "motd";
-
- config_init(&cfg);
-
- // Read the file. If there is an error, report it and exit.
- if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
- syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
- config_destroy(&cfg);
- return 0;
- }
-
- // Get port
- if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
- syslog(LOG_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
- *port = DEFAULT_PORT;
- }
-
- // Get PID file location
- const char *tmp_pid_file;
-
- if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
- tmp_pid_file = DEFAULT_PID_FILE_PATH;
- }
-
- *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
- strcpy(*pid_file_path, tmp_pid_file);
-
- // Get keys file location
- const char *tmp_keys_file;
-
- if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
- tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
- }
-
- *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
- strcpy(*keys_file_path, tmp_keys_file);
-
- // Get IPv6 option
- if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
- *enable_ipv6 = DEFAULT_ENABLE_IPV6;
- }
-
- // Get IPv4 fallback option
- if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK,
- DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false");
- *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK;
- }
-
- // Get LAN discovery option
- if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
- DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
- *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
- }
-
- // Get TCP relay option
- if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY,
- DEFAULT_ENABLE_TCP_RELAY ? "true" : "false");
- *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;
- }
-
- if (*enable_tcp_relay) {
- parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);
- } else {
- *tcp_relay_port_count = 0;
- }
-
- // Get MOTD option
- if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD,
- DEFAULT_ENABLE_MOTD ? "true" : "false");
- *enable_motd = DEFAULT_ENABLE_MOTD;
- }
-
- if (*enable_motd) {
- // Get MOTD
- const char *tmp_motd;
-
- if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_MOTD);
- syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_MOTD, DEFAULT_MOTD);
- tmp_motd = DEFAULT_MOTD;
- }
-
- size_t tmp_motd_length = strlen(tmp_motd) + 1;
- size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;
- *motd = malloc(motd_length);
- strncpy(*motd, tmp_motd, motd_length);
- (*motd)[motd_length - 1] = '\0';
- }
-
- config_destroy(&cfg);
-
- syslog(LOG_DEBUG, "Successfully read:\n");
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
- syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port);
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false");
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
-
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false");
-
- // show info about tcp ports only if tcp relay is enabled
- if (*enable_tcp_relay) {
- if (*tcp_relay_port_count == 0) {
- syslog(LOG_DEBUG, "No TCP ports could be read.\n");
- } else {
- syslog(LOG_DEBUG, "Read %d TCP ports:\n", *tcp_relay_port_count);
- int i;
-
- for (i = 0; i < *tcp_relay_port_count; i ++) {
- syslog(LOG_DEBUG, "Port #%d: %u\n", i, (*tcp_relay_ports)[i]);
- }
- }
- }
-
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false");
-
- if (*enable_motd) {
- syslog(LOG_DEBUG, "'%s': %s\n", NAME_MOTD, *motd);
- }
-
- return 1;
-}
-
-// Bootstraps nodes listed in the config file
-//
-// returns 1 on success, some or no bootstrap nodes were added
-// 0 on failure, a error accured while parsing config file
-
-int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6)
-{
- const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes";
-
- const char *NAME_PUBLIC_KEY = "public_key";
- const char *NAME_PORT = "port";
- const char *NAME_ADDRESS = "address";
-
- config_t cfg;
-
- config_init(&cfg);
-
- if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
- syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
- config_destroy(&cfg);
- return 0;
- }
-
- config_setting_t *node_list = config_lookup(&cfg, NAME_BOOTSTRAP_NODES);
-
- if (node_list == NULL) {
- syslog(LOG_WARNING, "No '%s' setting in the configuration file. Skipping bootstrapping.\n", NAME_BOOTSTRAP_NODES);
- config_destroy(&cfg);
- return 1;
- }
-
- if (config_setting_length(node_list) == 0) {
- syslog(LOG_WARNING, "No bootstrap nodes found. Skipping bootstrapping.\n");
- config_destroy(&cfg);
- return 1;
- }
-
- int bs_port;
- const char *bs_address;
- const char *bs_public_key;
-
- config_setting_t *node;
-
- int i = 0;
-
- while (config_setting_length(node_list)) {
-
- node = config_setting_get_elem(node_list, 0);
-
- if (node == NULL) {
- config_destroy(&cfg);
- return 0;
- }
-
- // Check that all settings are present
- if (config_setting_lookup_string(node, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PUBLIC_KEY);
- goto next;
- }
-
- if (config_setting_lookup_int(node, NAME_PORT, &bs_port) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PORT);
- goto next;
- }
-
- if (config_setting_lookup_string(node, NAME_ADDRESS, &bs_address) == CONFIG_FALSE) {
- syslog(LOG_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_ADDRESS);
- goto next;
- }
-
- // Process settings
- if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES * 2) {
- syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_PUBLIC_KEY,
- bs_public_key);
- goto next;
- }
-
- if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {
- syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\n", i, NAME_PORT,
- bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
- goto next;
- }
-
- uint8_t *bs_public_key_bin = hex_string_to_bin((char *)bs_public_key);
- const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
- bs_public_key_bin);
- free(bs_public_key_bin);
-
- if (!address_resolved) {
- syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_ADDRESS, bs_address);
- goto next;
- }
-
- syslog(LOG_DEBUG, "Successfully added bootstrap node #%d: %s:%d %s\n", i, bs_address, bs_port, bs_public_key);
-
-next:
- // config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly
- // though it's freed when the element is removed, so we free it right away in order to keep memory
- // consumption minimal
- config_setting_remove_elem(node_list, 0);
- i++;
- }
-
- config_destroy(&cfg);
-
- return 1;
-}
-
-// Prints public key
-
-void print_public_key(const uint8_t *public_key)
-{
- char buffer[2 * crypto_box_PUBLICKEYBYTES + 1];
- int index = 0;
-
- size_t i;
-
- for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {
- index += sprintf(buffer + index, "%02hhX", public_key[i]);
- }
-
- syslog(LOG_INFO, "Public Key: %s\n", buffer);
-
- return;
-}
-
-int main(int argc, char *argv[])
-{
- openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
-
- syslog(LOG_INFO, "Running \"%s\" version %lu.\n", DAEMON_NAME, DAEMON_VERSION_NUMBER);
-
- if (argc < 2) {
- syslog(LOG_ERR, "Please specify a path to a configuration file as the first argument. Exiting.\n");
- return 1;
- }
-
- const char *cfg_file_path = argv[1];
- char *pid_file_path, *keys_file_path;
- int port;
- int enable_ipv6;
- int enable_ipv4_fallback;
- int enable_lan_discovery;
- int enable_tcp_relay;
- uint16_t *tcp_relay_ports;
- int tcp_relay_port_count;
- int enable_motd;
- char *motd;
-
- if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback,
- &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {
- syslog(LOG_DEBUG, "General config read successfully\n");
- } else {
- syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
- return 1;
- }
-
- if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {
- syslog(LOG_ERR, "Invalid port: %d, should be in [%d, %d]. Exiting.\n", port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
- return 1;
- }
-
- // Check if the PID file exists
- FILE *pid_file;
-
- if ((pid_file = fopen(pid_file_path, "r"))) {
- syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path);
- fclose(pid_file);
- }
-
- IP ip;
- ip_init(&ip, enable_ipv6);
-
- Networking_Core *net = new_networking(ip, port);
-
- if (net == NULL) {
- if (enable_ipv6 && enable_ipv4_fallback) {
- syslog(LOG_DEBUG, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n");
- enable_ipv6 = 0;
- ip_init(&ip, enable_ipv6);
- net = new_networking(ip, port);
-
- if (net == NULL) {
- syslog(LOG_DEBUG, "Couldn't fallback to IPv4. Exiting.\n");
- return 1;
- }
- } else {
- syslog(LOG_DEBUG, "Couldn't initialize networking. Exiting.\n");
- return 1;
- }
- }
-
-
- DHT *dht = new_DHT(net);
-
- if (dht == NULL) {
- syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n");
- return 1;
- }
-
- Onion *onion = new_onion(dht);
- Onion_Announce *onion_a = new_onion_announce(dht);
-
- if (!(onion && onion_a)) {
- syslog(LOG_ERR, "Couldn't initialize Tox Onion. Exiting.\n");
- return 1;
- }
-
- if (enable_motd) {
- if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) {
- syslog(LOG_DEBUG, "Set MOTD successfully.\n");
- } else {
- syslog(LOG_ERR, "Couldn't set MOTD: %s. Exiting.\n", motd);
- return 1;
- }
-
- free(motd);
- }
-
- if (manage_keys(dht, keys_file_path)) {
- syslog(LOG_DEBUG, "Keys are managed successfully.\n");
- } else {
- syslog(LOG_ERR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
- return 1;
- }
-
- TCP_Server *tcp_server = NULL;
-
- if (enable_tcp_relay) {
- if (tcp_relay_port_count == 0) {
- syslog(LOG_ERR, "No TCP relay ports read. Exiting.\n");
- return 1;
- }
-
- tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_secret_key, onion);
-
- // tcp_relay_port_count != 0 at this point
- free(tcp_relay_ports);
-
- if (tcp_server != NULL) {
- syslog(LOG_DEBUG, "Initialized Tox TCP server successfully.\n");
- } else {
- syslog(LOG_ERR, "Couldn't initialize Tox TCP server. Exiting.\n");
- return 1;
- }
- }
-
- if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
- syslog(LOG_DEBUG, "List of bootstrap nodes read successfully.\n");
- } else {
- syslog(LOG_ERR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path);
- return 1;
- }
-
- print_public_key(dht->self_public_key);
-
- // Write the PID file
- FILE *pidf = fopen(pid_file_path, "a+");
-
- if (pidf == NULL) {
- syslog(LOG_ERR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path);
- return 1;
- }
-
- free(pid_file_path);
- free(keys_file_path);
-
- // Fork off from the parent process
- const pid_t pid = fork();
-
- if (pid > 0) {
- fprintf(pidf, "%d", pid);
- fclose(pidf);
- syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid);
- return 0;
- } else {
- fclose(pidf);
- }
-
- if (pid < 0) {
- syslog(LOG_ERR, "Forking failed. Exiting.\n");
- return 1;
- }
-
- // Change the file mode mask
- umask(0);
-
- // Create a new SID for the child process
- if (setsid() < 0) {
- syslog(LOG_ERR, "SID creation failure. Exiting.\n");
- return 1;
- }
-
- // Change the current working directory
- if ((chdir("/")) < 0) {
- syslog(LOG_ERR, "Couldn't change working directory to '/'. Exiting.\n");
- return 1;
- }
-
- // Go quiet
- close(STDOUT_FILENO);
- close(STDIN_FILENO);
- close(STDERR_FILENO);
-
- uint64_t last_LANdiscovery = 0;
- const uint16_t htons_port = htons(port);
-
- int waiting_for_dht_connection = 1;
-
- if (enable_lan_discovery) {
- LANdiscovery_init(dht);
- syslog(LOG_DEBUG, "Initialized LAN discovery.\n");
- }
-
- while (1) {
- do_DHT(dht);
-
- if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
- send_LANdiscovery(htons_port, dht);
- last_LANdiscovery = unix_time();
- }
-
- if (enable_tcp_relay) {
- do_TCP_server(tcp_server);
- }
-
- networking_poll(dht->net);
-
- if (waiting_for_dht_connection && DHT_isconnected(dht)) {
- syslog(LOG_DEBUG, "Connected to other bootstrap node successfully.\n");
- waiting_for_dht_connection = 0;
- }
-
- sleep;
- }
-
- return 1;
-}
diff --git a/other/bootstrap_daemon/tox-bootstrapd.service b/other/bootstrap_daemon/tox-bootstrapd.service
index db54cc41..20f698d2 100644
--- a/other/bootstrap_daemon/tox-bootstrapd.service
+++ b/other/bootstrap_daemon/tox-bootstrapd.service
@@ -8,7 +8,7 @@ RuntimeDirectory=tox-bootstrapd
RuntimeDirectoryMode=750
PIDFile=/var/run/tox-bootstrapd/tox-bootstrapd.pid
WorkingDirectory=/var/lib/tox-bootstrapd
-ExecStart=/usr/local/bin/tox-bootstrapd /etc/tox-bootstrapd.conf
+ExecStart=/usr/local/bin/tox-bootstrapd --config /etc/tox-bootstrapd.conf
User=tox-bootstrapd
Group=tox-bootstrapd
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
diff --git a/other/bootstrap_daemon/tox-bootstrapd.sh b/other/bootstrap_daemon/tox-bootstrapd.sh
index 1431bde0..d33c38da 100644
--- a/other/bootstrap_daemon/tox-bootstrapd.sh
+++ b/other/bootstrap_daemon/tox-bootstrapd.sh
@@ -15,7 +15,7 @@ DESC="Tox DHT bootstrap daemon"
NAME=tox-bootstrapd
DAEMON=/usr/local/bin/$NAME
CFGFILE=/etc/$NAME.conf
-DAEMON_ARGS="$CFGFILE"
+DAEMON_ARGS="--config $CFGFILE"
PIDDIR=/var/run/$NAME
PIDFILE=$PIDDIR/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
diff --git a/other/bootstrap_node_packets.c b/other/bootstrap_node_packets.c
index 0bf9b9b0..21bb2894 100644
--- a/other/bootstrap_node_packets.c
+++ b/other/bootstrap_node_packets.c
@@ -23,7 +23,7 @@
*
*/
-#define MAX_MOTD_LENGTH 256 /* I recommend you use a maximum of 96 bytes. The hard maximum is this though. */
+#include "bootstrap_node_packets.h"
#define INFO_REQUEST_PACKET_LENGTH 78
diff --git a/other/bootstrap_node_packets.h b/other/bootstrap_node_packets.h
new file mode 100644
index 00000000..43356e7b
--- /dev/null
+++ b/other/bootstrap_node_packets.h
@@ -0,0 +1,35 @@
+/* bootstrap_node_packets.h
+ *
+ * Special bootstrap node only packets.
+ *
+ * Include it in your bootstrap node and use: bootstrap_set_callbacks() to enable.
+ *
+ * Copyright (C) 2015 Tox project All Rights Reserved.
+ *
+ * This file is part of Tox.
+ *
+ * Tox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Tox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tox. If not, see .
+ *
+ */
+
+#ifndef BOOTSTRAP_NODE_PACKETS_H
+#define BOOTSTRAP_NODE_PACKETS_H
+
+#include "../toxcore/network.h"
+
+#define MAX_MOTD_LENGTH 256 /* I recommend you use a maximum of 96 bytes. The hard maximum is this though. */
+
+int bootstrap_set_callbacks(Networking_Core *net, uint32_t version, uint8_t *motd, uint16_t motd_length);
+
+#endif // BOOTSTRAP_NODE_PACKETS_H