1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-14 05:03:03 +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:
Jfreegman 2016-09-22 14:09:07 -04:00
parent d2b572ede1
commit 38ec96e96a
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
4 changed files with 124 additions and 45 deletions

View File

@ -37,6 +37,7 @@
extern struct arg_opts arg_opts;
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
/* URL that we get the JSON encoded nodes list from. */
#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 */
#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 {
char ip4[IP_MAX_SIZE + 1];
bool have_ip4;
@ -90,7 +99,7 @@ struct Node {
};
static struct DHT_Nodes {
struct Node list[MAXNODES];
struct Node list[MAX_NODES];
size_t count;
uint64_t last_updated;
} Nodes;
@ -101,7 +110,6 @@ static struct DHT_Nodes {
*/
#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.
* This will be the case if the file is empty, has an invalid format,
* 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;
}
last_scan_val += LAST_SCAN_JSON_KEY_LEN;
long long int last_scan = strtoll(last_scan_val, NULL, 10);
Nodes.last_updated = last_scan;
long long int last_scan = strtoll(last_scan_val + LAST_SCAN_JSON_KEY_LEN, NULL, 10);
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;
}
@ -158,6 +172,8 @@ static int curl_fetch_nodes_JSON(struct Recv_Curl_Data *recv_data)
return -1;
}
int err = -1;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
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) {
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);
if (ret != CURLE_OK) {
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);
if (ret != CURLE_OK) {
fprintf(stderr, "Failed to set TLS cipher list (libcurl error %d)", ret);
return -1;
goto on_exit;
}
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) {
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.
@ -401,15 +422,8 @@ static int extract_node(const char *line, struct Node *node)
return 0;
}
/* Load the DHT nodeslist to memory from json encoded nodes file obtained at NODES_LIST_URL.
* TODO: Parse json using a proper library?
*
* 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)
/* Loads the DHT nodeslist to memory from json encoded nodes file. */
void *load_nodeslist_thread(void *data)
{
char nodes_path[PATH_MAX];
get_nodeslist_path(nodes_path, sizeof(nodes_path));
@ -418,10 +432,12 @@ int load_DHT_nodeslist(void)
if (!file_exists(nodes_path)) {
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) {
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);
@ -434,45 +450,103 @@ int load_DHT_nodeslist(void)
if (fgets(line, sizeof(line), fp) == NULL) {
fclose(fp);
return -2;
fprintf(stderr, "nodeslist load error: file empty.\n");
goto on_exit;
}
size_t idx = 0;
const char *line_start = line;
while ((line_start = strstr(line_start + 1, IPV4_JSON_KEY)) && Nodes.count < MAXNODES) {
size_t idx = Nodes.count;
while ((line_start = strstr(line_start + 1, IPV4_JSON_KEY))) {
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) {
++Nodes.count;
}
pthread_mutex_unlock(&thread_data.lock);
}
/* 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.
*/
if (Nodes.count == 0) {
if (idx == 0) {
const char *s = "{\"last_scan\":0}";
rewind(fp);
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
fclose(fp);
return -3;
fprintf(stderr, "nodeslist load error: List did not contain any valid entries.\n");
goto on_exit;
}
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;
}
/* Connects to NUM_BOOTSTRAP_NODES random DHT nodes listed in the DHTnodes file. */
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;
}
size_t i;
pthread_mutex_lock(&thread_data.lock);
for (i = 0; i < NUM_BOOTSTRAP_NODES; ++i) {
TOX_ERR_BOOTSTRAP err;
struct Node *node = &Nodes.list[rand() % Nodes.count];
const char *addr = node->have_ip4 ? node->ip4 : node->ip6;
@ -480,6 +554,7 @@ static void DHT_bootstrap(Tox *m)
continue;
}
TOX_ERR_BOOTSTRAP err;
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
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);
}
}
pthread_mutex_unlock(&thread_data.lock);
}
/* Manages connection to the Tox DHT network. */

View File

@ -26,13 +26,16 @@
/* Manages connection to the Tox DHT network. */
void do_tox_connection(Tox *m);
/* Load the DHT nodeslist to memory from json encoded nodes file obtained at NODES_LIST_URL.
* TODO: Parse json using a proper library?
/* 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 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.
* 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);

View File

@ -33,7 +33,7 @@
#include "curl_util.h"
extern struct arg_opts arg_opts;
extern struct Winthread Winthread;;
extern struct Winthread Winthread;
#define NAMESERVER_API_PATH "api"
#define SERVER_KEY_SIZE 32
@ -53,8 +53,8 @@ static struct thread_data {
char id_bin[TOX_ADDRESS_SIZE];
char addr[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
bool busy;
bool disabled;
volatile bool busy;
} t_data;
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 (!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
lookup_error(self, "Name server domain not found.");

View File

@ -1140,12 +1140,6 @@ int main(int argc, char **argv)
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
if (init_xtra(DnD_callback) == -1)
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)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
#ifdef AUDIO
av = init_audio(prompt, m);
@ -1202,6 +1195,12 @@ int main(int argc, char **argv)
if (init_mplex_away_timer(m) == -1)
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);
print_init_messages(prompt);
pthread_mutex_unlock(&Winthread.lock);