int main(int argc, char *argv[]) { openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON); if (argc < 2) { syslog(LOG_ERR, "Please specify a path to a configuration file as the first argument. Exiting.\n"); return 1; } char *cfg_file_path = argv[1]; char *pid_file_path, *keys_file_path; int port; int enable_ipv6; int enable_lan_discovery; if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery)) { 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; } // not (1 <= port <= 65535) if (port < 1 || port > 65535) { syslog(LOG_ERR, "Invalid port: %d, must be 1 <= port <= 65535. Exiting.\n", port); return 1; } // Check if the PID file exists if (fopen(pid_file_path, "r")) { syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists. Exiting.\n", pid_file_path); return 1; } IP ip; ip_init(&ip, enable_ipv6); DHT *dht = new_DHT(new_net_crypto(new_networking(ip, port))); 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_lan_discovery) { LANdiscovery_init(dht); } 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; } if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) { syslog(LOG_DEBUG, "List of bootstrap servers read successfully\n"); } else { syslog(LOG_ERR, "Couldn't read list of bootstrap servers in %s. Exiting.\n", cfg_file_path); return 1; } print_public_key(dht->c->self_public_key); // Write the PID file FILE *pidf = fopen(pid_file_path, "w"); if (pidf == NULL) { syslog(LOG_ERR, "Can'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 pid_t pid = fork(); if (pid < 0) { syslog(LOG_ERR, "Forking failed. Exiting.\n"); return 1; } if (pid > 0) { syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid); return 0; } // Change the file mode mask umask(0); fprintf(pidf, "%d\n", pid); fclose(pidf); // 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; uint16_t htons_port = htons(port); int waiting_for_dht_connection = 1; 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(); } networking_poll(dht->net); if (waiting_for_dht_connection && DHT_isconnected(dht)) { syslog(LOG_DEBUG, "Connected to other bootstrap server successfully.\n"); waiting_for_dht_connection = 0; } sleep; } return 1; }
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_public_key, 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; }