mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-22 20:43:02 +01:00
Thread nodeslist loading
This is necessary because DNS/http lookups block, and can do so for a very long time
This commit is contained in:
parent
d2b572ede1
commit
38ec96e96a
137
src/bootstrap.c
137
src/bootstrap.c
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
extern struct arg_opts arg_opts;
|
extern struct arg_opts arg_opts;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
/* URL that we get the JSON encoded nodes list from. */
|
/* URL that we get the JSON encoded nodes list from. */
|
||||||
#define NODES_LIST_URL "https://nodes.tox.chat/json"
|
#define NODES_LIST_URL "https://nodes.tox.chat/json"
|
||||||
@ -77,7 +78,15 @@ extern struct user_settings *user_settings;
|
|||||||
/* Maximum allowable size of the nodes list */
|
/* Maximum allowable size of the nodes list */
|
||||||
#define MAX_NODELIST_SIZE (MAX_RECV_CURL_DATA_SIZE)
|
#define MAX_NODELIST_SIZE (MAX_RECV_CURL_DATA_SIZE)
|
||||||
|
|
||||||
#define MAXNODES 50
|
|
||||||
|
struct Thread_Data {
|
||||||
|
pthread_t tid;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
volatile bool active;
|
||||||
|
} thread_data;
|
||||||
|
|
||||||
|
#define MAX_NODES 50
|
||||||
struct Node {
|
struct Node {
|
||||||
char ip4[IP_MAX_SIZE + 1];
|
char ip4[IP_MAX_SIZE + 1];
|
||||||
bool have_ip4;
|
bool have_ip4;
|
||||||
@ -90,7 +99,7 @@ struct Node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct DHT_Nodes {
|
static struct DHT_Nodes {
|
||||||
struct Node list[MAXNODES];
|
struct Node list[MAX_NODES];
|
||||||
size_t count;
|
size_t count;
|
||||||
uint64_t last_updated;
|
uint64_t last_updated;
|
||||||
} Nodes;
|
} Nodes;
|
||||||
@ -101,7 +110,6 @@ static struct DHT_Nodes {
|
|||||||
*/
|
*/
|
||||||
#define NODE_IS_OFFLINE(last_scan, last_ping) ((last_ping + NODE_OFFLINE_TIMOUT) <= (last_ping))
|
#define NODE_IS_OFFLINE(last_scan, last_ping) ((last_ping + NODE_OFFLINE_TIMOUT) <= (last_ping))
|
||||||
|
|
||||||
|
|
||||||
/* Return true if nodeslist pointed to by fp needs to be updated.
|
/* Return true if nodeslist pointed to by fp needs to be updated.
|
||||||
* This will be the case if the file is empty, has an invalid format,
|
* This will be the case if the file is empty, has an invalid format,
|
||||||
* or if the file is older than the given timeout.
|
* or if the file is older than the given timeout.
|
||||||
@ -134,11 +142,17 @@ static bool nodeslist_needs_update(const char *nodes_path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_scan_val += LAST_SCAN_JSON_KEY_LEN;
|
long long int last_scan = strtoll(last_scan_val + LAST_SCAN_JSON_KEY_LEN, NULL, 10);
|
||||||
long long int last_scan = strtoll(last_scan_val, NULL, 10);
|
|
||||||
Nodes.last_updated = last_scan;
|
|
||||||
|
|
||||||
if (timed_out(last_scan, user_settings->nodeslist_update_freq * 24 * 60 * 60)) {
|
pthread_mutex_lock(&thread_data.lock);
|
||||||
|
Nodes.last_updated = last_scan;
|
||||||
|
pthread_mutex_unlock(&thread_data.lock);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
bool is_timeout = timed_out(last_scan, user_settings->nodeslist_update_freq * 24 * 60 * 60);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
if (is_timeout) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +172,8 @@ static int curl_fetch_nodes_JSON(struct Recv_Curl_Data *recv_data)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int err = -1;
|
||||||
|
|
||||||
struct curl_slist *headers = NULL;
|
struct curl_slist *headers = NULL;
|
||||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
headers = curl_slist_append(headers, "charsets: utf-8");
|
headers = curl_slist_append(headers, "charsets: utf-8");
|
||||||
@ -173,21 +189,21 @@ static int curl_fetch_nodes_JSON(struct Recv_Curl_Data *recv_data)
|
|||||||
|
|
||||||
if (proxy_ret != 0) {
|
if (proxy_ret != 0) {
|
||||||
fprintf(stderr, "set_curl_proxy() failed with error %d\n", proxy_ret);
|
fprintf(stderr, "set_curl_proxy() failed with error %d\n", proxy_ret);
|
||||||
return -1;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = curl_easy_setopt(c_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
int ret = curl_easy_setopt(c_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
||||||
|
|
||||||
if (ret != CURLE_OK) {
|
if (ret != CURLE_OK) {
|
||||||
fprintf(stderr, "TLSv1.2 could not be set (libcurl error %d)", ret);
|
fprintf(stderr, "TLSv1.2 could not be set (libcurl error %d)", ret);
|
||||||
return -1;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = curl_easy_setopt(c_handle, CURLOPT_SSL_CIPHER_LIST, TLS_CIPHER_SUITE_LIST);
|
ret = curl_easy_setopt(c_handle, CURLOPT_SSL_CIPHER_LIST, TLS_CIPHER_SUITE_LIST);
|
||||||
|
|
||||||
if (ret != CURLE_OK) {
|
if (ret != CURLE_OK) {
|
||||||
fprintf(stderr, "Failed to set TLS cipher list (libcurl error %d)", ret);
|
fprintf(stderr, "Failed to set TLS cipher list (libcurl error %d)", ret);
|
||||||
return -1;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = curl_easy_perform(c_handle);
|
ret = curl_easy_perform(c_handle);
|
||||||
@ -201,11 +217,16 @@ static int curl_fetch_nodes_JSON(struct Recv_Curl_Data *recv_data)
|
|||||||
|
|
||||||
if (ret != CURLE_OK) {
|
if (ret != CURLE_OK) {
|
||||||
fprintf(stderr, "HTTPS lookup error (libcurl error %d)\n", ret);
|
fprintf(stderr, "HTTPS lookup error (libcurl error %d)\n", ret);
|
||||||
return -1;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
err = 0;
|
||||||
|
|
||||||
|
on_exit:
|
||||||
|
curl_slist_free_all(headers);
|
||||||
|
curl_easy_cleanup(c_handle);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempts to update the DHT nodeslist.
|
/* Attempts to update the DHT nodeslist.
|
||||||
@ -401,15 +422,8 @@ static int extract_node(const char *line, struct Node *node)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the DHT nodeslist to memory from json encoded nodes file obtained at NODES_LIST_URL.
|
/* Loads the DHT nodeslist to memory from json encoded nodes file. */
|
||||||
* TODO: Parse json using a proper library?
|
void *load_nodeslist_thread(void *data)
|
||||||
*
|
|
||||||
* Return 0 on success.
|
|
||||||
* Return -1 if nodeslist file cannot be opened or created.
|
|
||||||
* Return -2 if nodeslist file cannot be parsed.
|
|
||||||
* Return -3 if nodeslist file does not contain any valid node entries.
|
|
||||||
*/
|
|
||||||
int load_DHT_nodeslist(void)
|
|
||||||
{
|
{
|
||||||
char nodes_path[PATH_MAX];
|
char nodes_path[PATH_MAX];
|
||||||
get_nodeslist_path(nodes_path, sizeof(nodes_path));
|
get_nodeslist_path(nodes_path, sizeof(nodes_path));
|
||||||
@ -418,10 +432,12 @@ int load_DHT_nodeslist(void)
|
|||||||
|
|
||||||
if (!file_exists(nodes_path)) {
|
if (!file_exists(nodes_path)) {
|
||||||
if ((fp = fopen(nodes_path, "w+")) == NULL) {
|
if ((fp = fopen(nodes_path, "w+")) == NULL) {
|
||||||
return -1;
|
fprintf(stderr, "nodeslist load error: failed to create file '%s'\n", nodes_path);
|
||||||
|
goto on_exit;
|
||||||
}
|
}
|
||||||
} else if ((fp = fopen(nodes_path, "r+")) == NULL) {
|
} else if ((fp = fopen(nodes_path, "r+")) == NULL) {
|
||||||
return -1;
|
fprintf(stderr, "nodeslist load error: failed to open file '%s'\n", nodes_path);
|
||||||
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
int update_err = update_DHT_nodeslist(nodes_path);
|
int update_err = update_DHT_nodeslist(nodes_path);
|
||||||
@ -434,45 +450,103 @@ int load_DHT_nodeslist(void)
|
|||||||
|
|
||||||
if (fgets(line, sizeof(line), fp) == NULL) {
|
if (fgets(line, sizeof(line), fp) == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -2;
|
fprintf(stderr, "nodeslist load error: file empty.\n");
|
||||||
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
const char *line_start = line;
|
const char *line_start = line;
|
||||||
|
|
||||||
while ((line_start = strstr(line_start + 1, IPV4_JSON_KEY)) && Nodes.count < MAXNODES) {
|
while ((line_start = strstr(line_start + 1, IPV4_JSON_KEY))) {
|
||||||
size_t idx = Nodes.count;
|
pthread_mutex_lock(&thread_data.lock);
|
||||||
|
idx = Nodes.count;
|
||||||
|
|
||||||
|
if (idx >= MAX_NODES) {
|
||||||
|
pthread_mutex_unlock(&thread_data.lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (extract_node(line_start, &Nodes.list[idx]) == 0) {
|
if (extract_node(line_start, &Nodes.list[idx]) == 0) {
|
||||||
++Nodes.count;
|
++Nodes.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&thread_data.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If nodeslist does not contain any valid entries we set the last_scan value
|
/* If nodeslist does not contain any valid entries we set the last_scan value
|
||||||
* to 0 so that it will fetch a new list the next time this function is called.
|
* to 0 so that it will fetch a new list the next time this function is called.
|
||||||
*/
|
*/
|
||||||
if (Nodes.count == 0) {
|
if (idx == 0) {
|
||||||
const char *s = "{\"last_scan\":0}";
|
const char *s = "{\"last_scan\":0}";
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
|
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -3;
|
fprintf(stderr, "nodeslist load error: List did not contain any valid entries.\n");
|
||||||
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
on_exit:
|
||||||
|
thread_data.active = false;
|
||||||
|
pthread_attr_destroy(&thread_data.attr);
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates a new thread that will load the DHT nodeslist to memory
|
||||||
|
* from json encoded nodes file obtained at NODES_LIST_URL. Only one
|
||||||
|
* thread may run at a time.
|
||||||
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 if a thread is already active.
|
||||||
|
* Return -2 if mutex fails to init.
|
||||||
|
* Return -3 if pthread attribute fails to init.
|
||||||
|
* Return -4 if pthread fails to set detached state.
|
||||||
|
* Return -5 if thread creation fails.
|
||||||
|
*/
|
||||||
|
int load_DHT_nodeslist(void)
|
||||||
|
{
|
||||||
|
if (thread_data.active) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_mutex_init(&thread_data.lock, NULL) != 0) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_attr_init(&thread_data.attr) != 0) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_attr_setdetachstate(&thread_data.attr, PTHREAD_CREATE_DETACHED) != 0) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_data.active = true;
|
||||||
|
if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
|
||||||
|
thread_data.active = false;
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connects to NUM_BOOTSTRAP_NODES random DHT nodes listed in the DHTnodes file. */
|
/* Connects to NUM_BOOTSTRAP_NODES random DHT nodes listed in the DHTnodes file. */
|
||||||
static void DHT_bootstrap(Tox *m)
|
static void DHT_bootstrap(Tox *m)
|
||||||
{
|
{
|
||||||
if (Nodes.count == 0) {
|
pthread_mutex_lock(&thread_data.lock);
|
||||||
|
size_t num_nodes = Nodes.count;
|
||||||
|
pthread_mutex_unlock(&thread_data.lock);
|
||||||
|
|
||||||
|
if (num_nodes == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&thread_data.lock);
|
||||||
|
|
||||||
for (i = 0; i < NUM_BOOTSTRAP_NODES; ++i) {
|
for (i = 0; i < NUM_BOOTSTRAP_NODES; ++i) {
|
||||||
TOX_ERR_BOOTSTRAP err;
|
|
||||||
struct Node *node = &Nodes.list[rand() % Nodes.count];
|
struct Node *node = &Nodes.list[rand() % Nodes.count];
|
||||||
const char *addr = node->have_ip4 ? node->ip4 : node->ip6;
|
const char *addr = node->have_ip4 ? node->ip4 : node->ip6;
|
||||||
|
|
||||||
@ -480,6 +554,7 @@ static void DHT_bootstrap(Tox *m)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOX_ERR_BOOTSTRAP err;
|
||||||
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
|
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_BOOTSTRAP_OK) {
|
if (err != TOX_ERR_BOOTSTRAP_OK) {
|
||||||
@ -492,6 +567,8 @@ static void DHT_bootstrap(Tox *m)
|
|||||||
fprintf(stderr, "Failed to add TCP relay %s:%d\n", addr, node->port);
|
fprintf(stderr, "Failed to add TCP relay %s:%d\n", addr, node->port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&thread_data.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Manages connection to the Tox DHT network. */
|
/* Manages connection to the Tox DHT network. */
|
||||||
|
@ -26,13 +26,16 @@
|
|||||||
/* Manages connection to the Tox DHT network. */
|
/* Manages connection to the Tox DHT network. */
|
||||||
void do_tox_connection(Tox *m);
|
void do_tox_connection(Tox *m);
|
||||||
|
|
||||||
/* Load the DHT nodeslist to memory from json encoded nodes file obtained at NODES_LIST_URL.
|
/* Creates a new thread that will load the DHT nodeslist to memory
|
||||||
* TODO: Parse json using a proper library?
|
* from json encoded nodes file obtained at NODES_LIST_URL. Only one
|
||||||
|
* thread may run at a time.
|
||||||
*
|
*
|
||||||
* Return 0 on success.
|
* Return 0 on success.
|
||||||
* Return -1 if nodeslist file cannot be opened or created.
|
* Return -1 if a thread is already active.
|
||||||
* Return -2 if nodeslist file cannot be parsed.
|
* Return -2 if mutex fails to init.
|
||||||
* Return -3 if nodeslist file does not contain any valid node entries.
|
* Return -3 if pthread attribute fails to init.
|
||||||
|
* Return -4 if pthread fails to set detached state.
|
||||||
|
* Return -5 if thread creation fails.
|
||||||
*/
|
*/
|
||||||
int load_DHT_nodeslist(void);
|
int load_DHT_nodeslist(void);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include "curl_util.h"
|
#include "curl_util.h"
|
||||||
|
|
||||||
extern struct arg_opts arg_opts;
|
extern struct arg_opts arg_opts;
|
||||||
extern struct Winthread Winthread;;
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
#define NAMESERVER_API_PATH "api"
|
#define NAMESERVER_API_PATH "api"
|
||||||
#define SERVER_KEY_SIZE 32
|
#define SERVER_KEY_SIZE 32
|
||||||
@ -53,8 +53,8 @@ static struct thread_data {
|
|||||||
char id_bin[TOX_ADDRESS_SIZE];
|
char id_bin[TOX_ADDRESS_SIZE];
|
||||||
char addr[MAX_STR_SIZE];
|
char addr[MAX_STR_SIZE];
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
bool busy;
|
|
||||||
bool disabled;
|
bool disabled;
|
||||||
|
volatile bool busy;
|
||||||
} t_data;
|
} t_data;
|
||||||
|
|
||||||
static struct lookup_thread {
|
static struct lookup_thread {
|
||||||
@ -234,7 +234,7 @@ void *lookup_thread_func(void *data)
|
|||||||
|
|
||||||
if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
|
if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
|
||||||
if (!strcasecmp(input_domain, "utox.org"))
|
if (!strcasecmp(input_domain, "utox.org"))
|
||||||
lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic");
|
lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic.");
|
||||||
else
|
else
|
||||||
lookup_error(self, "Name server domain not found.");
|
lookup_error(self, "Name server domain not found.");
|
||||||
|
|
||||||
|
13
src/toxic.c
13
src/toxic.c
@ -1140,12 +1140,6 @@ int main(int argc, char **argv)
|
|||||||
queue_init_message("Name lookup server list does not contain any valid entries.");
|
queue_init_message("Name lookup server list does not contain any valid entries.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int nodeslist_ret = load_DHT_nodeslist();
|
|
||||||
|
|
||||||
if (nodeslist_ret != 0) {
|
|
||||||
queue_init_message("DHT nodeslist failed to load (error %d)", nodeslist_ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
if (init_xtra(DnD_callback) == -1)
|
if (init_xtra(DnD_callback) == -1)
|
||||||
queue_init_message("X failed to initialize");
|
queue_init_message("X failed to initialize");
|
||||||
@ -1173,7 +1167,6 @@ int main(int argc, char **argv)
|
|||||||
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
|
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
|
||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
av = init_audio(prompt, m);
|
av = init_audio(prompt, m);
|
||||||
@ -1202,6 +1195,12 @@ int main(int argc, char **argv)
|
|||||||
if (init_mplex_away_timer(m) == -1)
|
if (init_mplex_away_timer(m) == -1)
|
||||||
queue_init_message("Failed to init mplex auto-away.");
|
queue_init_message("Failed to init mplex auto-away.");
|
||||||
|
|
||||||
|
int nodeslist_ret = load_DHT_nodeslist();
|
||||||
|
|
||||||
|
if (nodeslist_ret != 0) {
|
||||||
|
queue_init_message("DHT nodeslist failed to load (error %d)", nodeslist_ret);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
print_init_messages(prompt);
|
print_init_messages(prompt);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user