Support using a seeds host for bootstrapping connections.

This commit is contained in:
Cory McWilliams 2024-08-07 21:03:39 -04:00
parent 1788a02338
commit 8d277f029d
2 changed files with 77 additions and 0 deletions

View File

@ -64,6 +64,11 @@ const k_global_settings = {
: undefined,
description: 'Blobs older than this will be automatically deleted.',
},
seeds_host: {
type: 'string',
default_value: '',
description: 'Hostname for seed connections.',
},
};
let gGlobalSettings = {

View File

@ -8,6 +8,7 @@
#include "trace.h"
#include "util.js.h"
#include "ares.h"
#include "quickjs.h"
#include "sodium/crypto_auth.h"
#include "sodium/crypto_box.h"
@ -20,6 +21,10 @@
#include "sqlite3.h"
#include "uv.h"
#if !defined(_WIN32)
#include <arpa/nameser.h>
#endif
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
@ -256,6 +261,7 @@ typedef struct _tf_ssb_t
uv_thread_t thread_self;
bool is_room;
char* room_name;
char seeds_host[256];
tf_ssb_timer_t** timers;
int timers_count;
@ -351,6 +357,7 @@ static JSClassID _connection_class_id;
static int s_connection_index;
static int s_tunnel_index;
static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broadcast);
static void _tf_ssb_connection_client_send_hello(tf_ssb_connection_t* connection);
static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char* reason);
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason);
@ -358,6 +365,7 @@ static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value);
static void _tf_ssb_connection_on_close(uv_handle_t* handle);
static void _tf_ssb_nonce_inc(uint8_t* nonce);
static void _tf_ssb_notify_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection);
static bool _tf_ssb_parse_broadcast(const char* in_broadcast, tf_ssb_broadcast_t* out_broadcast);
static void _tf_ssb_start_update_settings(tf_ssb_t* ssb);
static void _tf_ssb_update_settings(tf_ssb_t* ssb);
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size);
@ -2892,6 +2900,59 @@ static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, s
}
}
typedef struct _seeds_t
{
char** seeds;
int seeds_count;
} seeds_t;
static void _tf_ssb_update_seed_callback(void* arg, ares_status_t status, size_t timeouts, const ares_dns_record_t* record)
{
seeds_t* seeds = arg;
for (int i = 0; i < (int)ares_dns_record_rr_cnt(record, ARES_SECTION_ANSWER); i++)
{
const ares_dns_rr_t* rr = ares_dns_record_rr_get_const(record, ARES_SECTION_ANSWER, i);
size_t len = 0;
const unsigned char* str = ares_dns_rr_get_bin(rr, ARES_RR_TXT_DATA, &len);
seeds->seeds = tf_resize_vec(seeds->seeds, sizeof(char*) * (seeds->seeds_count + 1));
seeds->seeds[seeds->seeds_count++] = tf_strdup((const char*)str);
}
}
static void _tf_ssb_update_seeds_work(tf_ssb_t* ssb, void* user_data)
{
if (ares_library_init(0) == ARES_SUCCESS)
{
ares_channel channel;
struct ares_options options = { .evsys = ARES_EVSYS_DEFAULT };
if (ares_init_options(&channel, &options, ARES_OPT_EVENT_THREAD) == ARES_SUCCESS)
{
if (ares_query_dnsrec(channel, ssb->seeds_host, ARES_CLASS_IN, ARES_REC_TYPE_TXT, _tf_ssb_update_seed_callback, user_data, NULL) == ARES_SUCCESS)
{
ares_queue_wait_empty(channel, -1);
}
ares_destroy(channel);
}
ares_library_cleanup();
}
}
static void _tf_ssb_update_seeds_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
seeds_t* seeds = user_data;
for (int i = 0; i < seeds->seeds_count; i++)
{
tf_ssb_broadcast_t broadcast = { 0 };
if (_tf_ssb_parse_broadcast(seeds->seeds[i], &broadcast))
{
_tf_ssb_add_broadcast(ssb, &broadcast);
}
tf_free(seeds->seeds[i]);
}
tf_free(seeds->seeds);
tf_free(seeds);
}
static void _tf_ssb_broadcast_timer(uv_timer_t* timer)
{
tf_ssb_t* ssb = timer->data;
@ -2908,6 +2969,14 @@ static void _tf_ssb_broadcast_timer(uv_timer_t* timer)
}
uv_free_interface_addresses(info, count);
}
seeds_t* seeds = tf_malloc(sizeof(seeds_t));
*seeds = (seeds_t) { 0 };
if (*ssb->seeds_host)
{
tf_ssb_run_work(ssb, _tf_ssb_update_seeds_work, _tf_ssb_update_seeds_after_work, seeds);
}
}
int tf_ssb_server_open(tf_ssb_t* ssb, int port)
@ -3924,6 +3993,7 @@ void tf_ssb_set_room_name(tf_ssb_t* ssb, const char* room_name)
typedef struct _update_settings_t
{
bool is_room;
char seeds_host[256];
char room_name[1024];
} update_settings_t;
@ -3981,6 +4051,7 @@ static void _tf_ssb_update_settings_work(tf_ssb_t* ssb, void* user_data)
update_settings_t* update = user_data;
update->is_room = _get_global_setting_bool(ssb, "room", true);
_get_global_setting_string(ssb, "room_name", update->room_name, sizeof(update->room_name));
_get_global_setting_string(ssb, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
}
static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void* user_data)
@ -3988,6 +4059,7 @@ static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void*
update_settings_t* update = user_data;
tf_ssb_set_is_room(ssb, update->is_room);
tf_ssb_set_room_name(ssb, update->room_name);
snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host);
_tf_ssb_start_update_settings(ssb);
tf_free(update);
}