diff --git a/.travis.yml b/.travis.yml index 0a294bf1..4d49f5fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ compiler: - clang before_script: +# installing libsodium, needed for Core - git clone git://github.com/jedisct1/libsodium.git - cd libsodium - git checkout tags/0.4.2 @@ -12,6 +13,10 @@ before_script: - sudo make install - sudo ldconfig - cd .. +# installing libconfig, needed for DHT_bootstrap_daemon + - sudo sed -i 's/precise/quantal/' /etc/apt/sources.list # needed for libconfig-dev + - sudo apt-get update -qq + - yes | sudo apt-get install libconfig-dev script: - mkdir build && cd build diff --git a/other/bootstrap_serverdaemon/CMakeLists.txt b/other/bootstrap_serverdaemon/CMakeLists.txt index bc717d4b..6aa4dbee 100644 --- a/other/bootstrap_serverdaemon/CMakeLists.txt +++ b/other/bootstrap_serverdaemon/CMakeLists.txt @@ -6,4 +6,5 @@ set(exe_name DHT_bootstrap_daemon) add_executable(${exe_name} DHT_bootstrap_daemon.c) +target_link_libraries(${exe_name} config) linkCoreLibraries(${exe_name}) diff --git a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c index 4d79c48b..395bd7f2 100644 --- a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c +++ b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c @@ -1,50 +1,305 @@ /* DHT boostrap -* -* A simple DHT boostrap server for tox (daemon edition) -*/ - + * + * A simple DHT boostrap server for tox - daemon edition. + */ + #include /* pid_t */ #include /* umask */ -#include -#include #include /* POSIX things */ #include - + +#include +#include +#include +#include /* htons() */ +#include /* strcpy() */ + #include "../../core/DHT.h" #include "../../core/friend_requests.h" - -/* Sleep function (x = milliseconds) */ -#ifdef WIN32 -#define c_sleep(x) Sleep(1*x) -#else -#include -#define c_sleep(x) usleep(1000*x) -#endif - -#define PORT 33445 -#define USERNAME getenv("USER") -#define PIDFILE "/home/%s/.bootstrap_server.pid" /* %s represents the unser's name */ - +#define DEFAULT_PORT 33445 +#define DEFAULT_PID_FILE "bootstrap_server.pid" +#define DEFAULT_KEYS_FILE "bootstrap_server.keys" + +/* Server info struct */ +struct server_info_s { + int valid; + IP_Port conn; + uint8_t bs_pk[32]; +}; + +/* This is the struct configure_server() uses to return its data to */ +struct server_conf_s { + int err; + int port; + char pid_file[512]; + char keys_file[512]; + struct server_info_s info[32]; +}; + +int b16_to_key(char b16_string[], uint8_t *bs_pubkey) { + + int i; + unsigned int num1 = 0, num2 = 0; + + for(i = 0; i < 32; ++i) + { + sscanf(&b16_string[i*2], "%1X", &num1); + sscanf(&b16_string[i*2+1], "%1X", &num2); + num1 = num1 << 4; + bs_pubkey[i] = bs_pubkey[i] | num1; + bs_pubkey[i] = bs_pubkey[i] | num2; + } + return 0; +} + +/* This unction connects to all specified servers +and connect to them. +returns 1 if the connection to the DHT is up +returns -1 if all attempts failed +*/ +int connect_to_servers(struct server_info_s *info) +{ + int i; + int c; + + IP_Port ip_port; + uint8_t data[MAX_UDP_PACKET_SIZE]; + uint32_t length; + + for(i = 0; i < 32; ++i) { + if(info[i].valid) { + /* Actual bootstrapping code goes here */ + //puts("Calling DHT_bootstrap"); + DHT_bootstrap(info[i].conn, info[i].bs_pk); + } + } + + /* Check if we're connected to the DHT */ + for(c = 0; c != 100; ++c) { + usleep(10000); + if(DHT_isconnected()) { + //puts("Connected"); + return 1; + break; + } + if(DHT_isconnected() == 0 && c == 99) { + //puts("Not connected"); + return -1; + break; + } + + doDHT(); + + while(receivepacket(&ip_port, data, &length) != -1) + { + DHT_handlepacket(data, length, ip_port); + } + } + + /* This probably never happens */ + return 0; +} + +void manage_keys(char *keys_file) +{ + const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; + uint8_t keys[KEYS_SIZE]; + + /* TODO: stat the file before trying to open it. We aren't cave people! */ + FILE *keysf = fopen(keys_file, "r"); + if (keysf != NULL) { + /* if file was opened successfully -- load keys */ + size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keysf); + if (read_size != KEYS_SIZE) { + printf("Error while reading the key file\nExiting.\n"); + exit(1); + } else { + printf("Keys loaded successfully\n"); + } + load_keys(keys); + + } else { + /* otherwise save new keys */ + /* Silly work-around to ignore any errors coming from new_keys() */ + new_keys(); + save_keys(keys); + keysf = fopen(keys_file, "w"); + if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keysf) != KEYS_SIZE) { + printf("Error while writing the key file.\nExiting.\n"); + exit(1); + } else { + printf("Keys saved successfully\n"); + } + } + + fclose(keysf); +} + +/* This reads the configuration file, and returns a struct server_conf_s with: + *an error number: + *-1 = file wasn't read, for whatever reason + *-2 = no bootstrap servers found + *the port + *the location of the keys file + *the location of the PID file + *the list of bootstrap servers +*/ +struct server_conf_s configure_server(char *cfg_file) +{ + config_t cfg; + config_setting_t *server_list; + + /* This one will be strcpy'd into the pid_file array in server_conf */ + const char *pid_file_tmp; + const char *keys_file_tmp; + + /* Remote bootstrap server variables */ + int bs_port; + const char *bs_ip; + const char *bs_pk; + + /* The big struct */ + static struct server_conf_s server_conf; + + /* Set both to their default values. If there's an error + with opening/reading the config file, we return right away */ + server_conf.port = DEFAULT_PORT; + strcpy(server_conf.pid_file, DEFAULT_PID_FILE); + strcpy(server_conf.keys_file, DEFAULT_KEYS_FILE); + + config_init(&cfg); + + /* Read the file. If there is an error, report it and exit. */ + if(! config_read_file(&cfg, cfg_file)) + { + fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), + config_error_line(&cfg), config_error_text(&cfg)); + config_destroy(&cfg); + server_conf.err = -1; + return server_conf; + } + + /* Get the port to listen on */ + if(config_lookup_int(&cfg, "port", &server_conf.port)) { + //printf("Port: %d\n", port); + } else { + fprintf(stderr, "No 'port' setting in configuration file.\n"); + } + + /* Get PID file location */ + if(config_lookup_string(&cfg, "pid_file", &pid_file_tmp)) { + //printf("PID file: %s\n", pid_file_tmp); + strcpy(server_conf.pid_file, pid_file_tmp); + } else { + fprintf(stderr, "No 'pid_file' setting in configuration file.\n"); + } + + /* Get keys file location */ + if(config_lookup_string(&cfg, "keys_file", &keys_file_tmp)) { + //printf("Keys file: %s\n", keys_file_tmp); + strcpy(server_conf.keys_file, keys_file_tmp); + } else { + fprintf(stderr, "No 'keys_file' setting in configuration file.\n"); + } + + /* Get all the servers in the list */ + server_list = config_lookup(&cfg, "bootstrap_servers"); + if(server_list != NULL) { + int count = config_setting_length(server_list); + int i; + + char tmp_ip[30]; /* IP */ + char tmp_pk[64]; /* bs_pk */ + for(i = 0; i < count; ++i) { + config_setting_t *server = config_setting_get_elem(server_list, i); + /* Get a pointer on the key aray */ + uint8_t *bs_pk_p = server_conf.info[i].bs_pk; + + /* Only output the record if all of the expected fields are present. */ + if(!(config_setting_lookup_string(server, "ip", &bs_ip) + && config_setting_lookup_int(server, "port", &bs_port) + && config_setting_lookup_string(server, "bs_pk", &bs_pk))) + continue; + + /* Converting all that stuff into usable formats and storing + it away in the server_info struct */ + server_conf.info[i].valid = 1; + + if(resolve_addr(strcpy(tmp_ip, bs_ip)) == -1) { + server_conf.info[i].valid = 0; + printf("bootstrap_server %d: Invalid IP\n", i); + } + + if(strlen(bs_pk) != 64) { + server_conf.info[i].valid = 0; + printf("bootstrap_server %d: Invalid public key\n", i); + } + + if(!bs_port) { + server_conf.info[i].valid = 0; + printf("bootstrap_server %d: Invalid port\n", i); + } + + server_conf.info[i].conn.ip.i = resolve_addr(strcpy(tmp_ip, bs_ip)); + server_conf.info[i].conn.port = htons(bs_port); + b16_to_key(strcpy(tmp_pk, bs_pk), bs_pk_p); + } + + /* Check if at least one server entry is valid */ + for(i = 0; i < 32; ++i) { + if(server_conf.info[i].valid) + break; + else + server_conf.err = -2; + } + + } else { + server_conf.err = -2; + } + + config_destroy(&cfg); + return server_conf; +} + int main(int argc, char *argv[]) { - - char pidfloc[512]; /* Location of the soon-to-be PID file */ + pid_t pid, sid; /* Process- and Session-ID */ - + struct server_conf_s server_conf; + FILE *pidf; /* The PID file */ - - /* Assemble PID file location an try to open the file */ - sprintf(pidfloc, PIDFILE, USERNAME); - pidf = fopen(pidfloc, "w"); - - /* Generate new keypair */ - new_keys(); - + + if(argc < 2) { + printf("Please specify a configuration file.\n"); + exit(EXIT_FAILURE); + } + + /* Read the config file */ + server_conf = configure_server(argv[1]); + + printf("PID file: %s\n", server_conf.pid_file); + printf("Key file: %s\n", server_conf.keys_file); + + if(server_conf.err == -1) + printf("Config file not read.\n"); + + if(server_conf.err == -2) + printf("No valid servers in list.\n"); + + /* Open PID file for writing - if an error happens, + it will be caught down the line */ + pidf = fopen(server_conf.pid_file, "w"); + + /* Manage the keys */ + /* for now, just ignore any errors after this call. */ + int tmperr = errno; + manage_keys(server_conf.keys_file); + errno = tmperr; + /* Public key */ - uint32_t i; - + int i; printf("\nPublic Key: "); - for(i = 0; i < 32; i++) + for(i = 0; i < 32; ++i) { uint8_t ln, hn; ln = 0x0F & self_public_key[i]; @@ -53,84 +308,95 @@ int main(int argc, char *argv[]) { printf("%X%X", hn, ln); } printf("\n"); - + /* initialize networking bind to ip 0.0.0.0:PORT */ IP ip; ip.i = 0; - init_networking(ip, PORT); - + init_networking(ip, server_conf.port); + + /* Bootstrap the DHT + This one throws odd errors, too. Ignore. I assume they come + from somewhere in the core. */ + tmperr = errno; + connect_to_servers(server_conf.info); + errno = tmperr; + + if(!DHT_isconnected()) { + puts("Could not establish DHT connection. Check server settings.\n"); + exit(EXIT_FAILURE); + } else { + printf("Connected to DHT successfully.\n"); + } + /* If there's been an error, exit before forking off */ if (errno != 0) { perror("Error"); printf("Error(s) occured during start-up. Exiting.\n"); exit(EXIT_FAILURE); } - -// /* Assemble the location of the PID file */ -// sprintf(pidfloc, PIDFILE, USERNAME); -// pidf = fopen(pidfloc, "w"); -// /* Check if we can actually open the file */ -// if(pidf == NULL) { -// printf("Couldn't open PID-File %s for writing.\n", pidfloc); -// exit(EXIT_FAILURE); -// } - - /* Fork off the parent process */ + + /* Things that make the daemon work come past here. + There should be nothing here but the daemon code and + the main loop. */ + + /* Fork off from the parent process */ pid = fork(); if (pid < 0) { printf("Forking failed.\n"); exit(EXIT_FAILURE); } - + /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) { printf("Forked successfully: %d\n", pid); - + /* Write the PID file */ fprintf(pidf, "%d\n", pid); fclose(pidf); - + /* Exit parent */ exit(EXIT_SUCCESS); } - + /* Change the file mode mask */ umask(0); - + /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { printf("SID creation failure.\n"); exit(EXIT_FAILURE); } - + /* Change the current working directory */ if ((chdir("/")) < 0) { exit(EXIT_FAILURE); } - + /* Go quiet */ - close(STDIN_FILENO); close(STDOUT_FILENO); + close(STDIN_FILENO); close(STDERR_FILENO); - + + /* Main loop */ IP_Port ip_port; uint8_t data[MAX_UDP_PACKET_SIZE]; uint32_t length; - - /* Main loop */ - while(1) { + + while(1) + { doDHT(); - while(receivepacket(&ip_port, data, &length) != -1) { + + while(receivepacket(&ip_port, data, &length) != -1) + { DHT_handlepacket(data, length, ip_port); friendreq_handlepacket(data, length, ip_port); } - c_sleep(1); + usleep(10000); } - + shutdown_networking(); exit(EXIT_SUCCESS); } - diff --git a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh new file mode 100755 index 00000000..936bc808 --- /dev/null +++ b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh @@ -0,0 +1,109 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: DHT_bootstrap_daemon +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the Tox bootstrapping server +# Description: Use this piece of junk to start the Tox +# bootstrap server. +### END INIT INFO + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="ProjectTox bootstrap server daemon" +NAME=DHT_bootstrap_daemon +CFG=/home/$USER/server.cfg +DAEMON=/home/$USER/$NAME +DAEMON_ARGS="$CFG" +PIDFILE=/home/$USER/.$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +#[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + sleep 1 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --exec $DAEMON + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + + restart) #|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2 + exit 3 + ;; +esac diff --git a/other/bootstrap_serverdaemon/initscript.sh b/other/bootstrap_serverdaemon/initscript.sh deleted file mode 100644 index aa4b3e77..00000000 --- a/other/bootstrap_serverdaemon/initscript.sh +++ /dev/null @@ -1,109 +0,0 @@ -#! /bin/sh -### BEGIN INIT INFO -# Provides: bootstrap_server -# Required-Start: $remote_fs $syslog -# Required-Stop: $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start the Tox bootstrapping server -# Description: Use this piece of junk to start the Tox -# bootstrap server. -### END INIT INFO - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC="ProjectTox bootstrap server daemon" -NAME=bootstrap_server -DAEMON=/home/$USER/$NAME -DAEMON_ARGS="" -PIDFILE=/home/$USER/.$NAME.pid -SCRIPTNAME=/etc/init.d/$NAME - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Load the VERBOSE setting and other rcS variables -. /lib/init/vars.sh - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.2-14) to ensure that this file is present -# and status_of_proc is working. -. /lib/lsb/init-functions - -# -# Function that starts the daemon/service -# -do_start() -{ - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ - || return 1 - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ - $DAEMON_ARGS \ - || return 2 - sleep 1 -} - -# -# Function that stops the daemon/service -# -do_stop() -{ - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --exec $DAEMON - RETVAL="$?" - [ "$RETVAL" = 2 ] && return 2 - - start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON - [ "$?" = 2 ] && return 2 - # Many daemons don't delete their pidfiles when they exit. - rm -f $PIDFILE - return "$RETVAL" -} - -case "$1" in - start) - [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" - do_start - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - stop) - [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" - do_stop - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - status) - status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? - ;; - - restart) #|force-reload) - log_daemon_msg "Restarting $DESC" "$NAME" - do_stop - case "$?" in - 0|1) - do_start - case "$?" in - 0) log_end_msg 0 ;; - 1) log_end_msg 1 ;; # Old process is still running - *) log_end_msg 1 ;; # Failed to start - esac - ;; - *) - # Failed to stop - log_end_msg 1 - ;; - esac - ;; - *) - echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2 - exit 3 - ;; -esac - diff --git a/other/bootstrap_serverdaemon/server.cfg b/other/bootstrap_serverdaemon/server.cfg new file mode 100644 index 00000000..8ef516ca --- /dev/null +++ b/other/bootstrap_serverdaemon/server.cfg @@ -0,0 +1,30 @@ +// ProjectTox bootstrap server configuration file + +// The port used by bootstrap_server to listen on +port = 33445; + +// The key file +// make sure that the user who runs the server +// does have permissions to read it/write to it +keys_file = "/home/tom/.bootstrap_server.keys" + +// The PID file written to by bootstrap_server, +// make sure that the user who runs the server +// does have permissions to write to it +pid_file = "/home/tom/.bootstrap_server.pid"; + +// The info of the node bootstap_server will +// bootstrap itself from. +bootstrap_servers = ( + { // Server 1 + ip = "198.46.136.167"; + port = 33445; + bs_pk = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854"; +// } + }, + { // Server 2 + ip = "192.81.133.111"; + port = 33445; + bs_pk = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858"; + } +);