2021-01-02 13:10:00 -05:00
# include "ssb.connections.h"
2023-03-07 12:50:17 -05:00
# include "log.h"
2022-06-04 13:04:51 -04:00
# include "mem.h"
2021-01-02 13:10:00 -05:00
# include "ssb.h"
2023-05-21 17:36:51 -04:00
# include "sqlite3.h"
2024-10-08 12:19:44 -04:00
# include "uv.h"
2021-01-02 13:10:00 -05:00
# include <string.h>
# if !defined(_countof)
# define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
# endif
typedef struct _tf_ssb_connections_t
{
tf_ssb_t * ssb ;
uv_timer_t timer ;
} tf_ssb_connections_t ;
static void _tf_ssb_connections_changed_callback ( tf_ssb_t * ssb , tf_ssb_change_t change , tf_ssb_connection_t * connection , void * user_data )
{
2024-10-02 20:43:51 -04:00
if ( ! connection )
{
return ;
}
2021-01-02 13:10:00 -05:00
tf_ssb_connections_t * connections = user_data ;
2021-10-10 17:51:38 -04:00
switch ( change )
{
2021-01-02 13:10:00 -05:00
case k_tf_ssb_change_create :
{
2021-10-24 15:23:21 -04:00
char key [ k_id_base64_len ] ;
2024-02-15 18:35:01 -05:00
if ( tf_ssb_connection_get_host ( connection ) & & * tf_ssb_connection_get_host ( connection ) & & tf_ssb_connection_get_port ( connection ) & &
2024-02-17 14:22:02 -05:00
tf_ssb_connection_get_id ( connection , key , sizeof ( key ) ) )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
tf_ssb_connections_set_attempted ( connections , tf_ssb_connection_get_host ( connection ) , tf_ssb_connection_get_port ( connection ) , key ) ;
}
}
break ;
case k_tf_ssb_change_connect :
{
2021-10-24 15:23:21 -04:00
char key [ k_id_base64_len ] ;
2021-10-10 17:51:38 -04:00
if ( tf_ssb_connection_get_id ( connection , key , sizeof ( key ) ) )
{
2021-01-02 13:10:00 -05:00
tf_ssb_connections_set_succeeded ( connections , tf_ssb_connection_get_host ( connection ) , tf_ssb_connection_get_port ( connection ) , key ) ;
}
}
break ;
case k_tf_ssb_change_remove :
2024-05-02 19:02:23 -04:00
case k_tf_ssb_change_update :
2021-01-02 13:10:00 -05:00
break ;
}
}
static bool _tf_ssb_connections_get_next_connection ( tf_ssb_connections_t * connections , char * host , size_t host_size , int * port , char * key , size_t key_size )
{
bool result = false ;
sqlite3_stmt * statement ;
2023-06-14 20:27:49 -04:00
sqlite3 * db = tf_ssb_acquire_db_reader ( connections - > ssb ) ;
2024-02-17 14:22:02 -05:00
if ( sqlite3_prepare ( db , " SELECT host, port, key FROM connections WHERE last_attempt IS NULL OR (strftime('%s', 'now') - last_attempt > ?1) ORDER BY last_attempt LIMIT 1 " , - 1 ,
& statement , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2024-02-15 18:35:01 -05:00
if ( sqlite3_bind_int ( statement , 1 , 60000 ) = = SQLITE_OK & & sqlite3_step ( statement ) = = SQLITE_ROW )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
snprintf ( host , host_size , " %s " , sqlite3_column_text ( statement , 0 ) ) ;
* port = sqlite3_column_int ( statement , 1 ) ;
snprintf ( key , key_size , " %s " , sqlite3_column_text ( statement , 2 ) ) ;
result = true ;
}
sqlite3_finalize ( statement ) ;
2021-10-10 17:51:38 -04:00
}
else
{
2023-06-14 20:27:49 -04:00
tf_printf ( " prepare: %s \n " , sqlite3_errmsg ( db ) ) ;
2021-01-02 13:10:00 -05:00
}
2023-06-14 20:27:49 -04:00
tf_ssb_release_db_reader ( connections - > ssb , db ) ;
2021-01-02 13:10:00 -05:00
return result ;
}
2023-10-09 21:11:32 -04:00
typedef struct _tf_ssb_connections_get_next_t
{
tf_ssb_connections_t * connections ;
bool ready ;
char host [ 256 ] ;
int port ;
char key [ k_id_base64_len ] ;
} tf_ssb_connections_get_next_t ;
2024-05-08 21:00:37 -04:00
static void _tf_ssb_connections_get_next_work ( tf_ssb_t * ssb , void * user_data )
2023-10-09 21:11:32 -04:00
{
2024-05-08 21:00:37 -04:00
tf_ssb_connections_get_next_t * next = user_data ;
2024-05-16 12:41:48 -04:00
if ( tf_ssb_is_shutting_down ( ssb ) )
{
return ;
}
2023-10-09 21:11:32 -04:00
next - > ready = _tf_ssb_connections_get_next_connection ( next - > connections , next - > host , sizeof ( next - > host ) , & next - > port , next - > key , sizeof ( next - > key ) ) ;
}
2024-05-08 21:00:37 -04:00
static void _tf_ssb_connections_get_next_after_work ( tf_ssb_t * ssb , int status , void * user_data )
2023-10-09 21:11:32 -04:00
{
2024-05-08 21:00:37 -04:00
tf_ssb_connections_get_next_t * next = user_data ;
2023-10-09 21:11:32 -04:00
if ( next - > ready )
{
uint8_t key_bin [ k_id_bin_len ] ;
if ( tf_ssb_id_str_to_bin ( key_bin , next - > key ) )
{
2024-10-06 11:14:37 -04:00
tf_ssb_connect ( ssb , next - > host , next - > port , key_bin , 0 ) ;
2023-10-09 21:11:32 -04:00
}
}
tf_free ( next ) ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connections_timer ( uv_timer_t * timer )
{
tf_ssb_connections_t * connections = timer - > data ;
tf_ssb_connection_t * active [ 4 ] ;
int count = tf_ssb_get_connections ( connections - > ssb , active , _countof ( active ) ) ;
2022-05-16 18:30:14 -04:00
if ( count < ( int ) _countof ( active ) )
2021-10-10 17:51:38 -04:00
{
2023-10-09 21:11:32 -04:00
tf_ssb_connections_get_next_t * next = tf_malloc ( sizeof ( tf_ssb_connections_get_next_t ) ) ;
2024-05-08 21:00:37 -04:00
* next = ( tf_ssb_connections_get_next_t ) {
2023-10-09 21:11:32 -04:00
. connections = connections ,
} ;
2024-05-08 21:00:37 -04:00
tf_ssb_run_work ( connections - > ssb , _tf_ssb_connections_get_next_work , _tf_ssb_connections_get_next_after_work , next ) ;
2021-01-02 13:10:00 -05:00
}
}
tf_ssb_connections_t * tf_ssb_connections_create ( tf_ssb_t * ssb )
{
2022-06-04 13:04:51 -04:00
tf_ssb_connections_t * connections = tf_malloc ( sizeof ( tf_ssb_connections_t ) ) ;
2021-01-02 13:10:00 -05:00
memset ( connections , 0 , sizeof ( * connections ) ) ;
connections - > ssb = ssb ;
2021-09-06 13:50:38 -04:00
tf_ssb_add_connections_changed_callback ( ssb , _tf_ssb_connections_changed_callback , NULL , connections ) ;
2021-01-02 13:10:00 -05:00
uv_loop_t * loop = tf_ssb_get_loop ( ssb ) ;
connections - > timer . data = connections ;
uv_timer_init ( loop , & connections - > timer ) ;
uv_timer_start ( & connections - > timer , _tf_ssb_connections_timer , 2000 , 2000 ) ;
uv_unref ( ( uv_handle_t * ) & connections - > timer ) ;
return connections ;
}
static void _tf_ssb_connections_on_handle_close ( uv_handle_t * handle )
{
tf_ssb_connections_t * connections = handle - > data ;
handle - > data = NULL ;
2022-06-04 13:04:51 -04:00
tf_free ( connections ) ;
2021-01-02 13:10:00 -05:00
}
void tf_ssb_connections_destroy ( tf_ssb_connections_t * connections )
{
uv_close ( ( uv_handle_t * ) & connections - > timer , _tf_ssb_connections_on_handle_close ) ;
}
2023-10-09 21:11:32 -04:00
typedef struct _tf_ssb_connections_update_t
2021-01-02 13:10:00 -05:00
{
2023-10-09 21:11:32 -04:00
char host [ 256 ] ;
int port ;
char key [ k_id_base64_len ] ;
bool attempted ;
bool succeeded ;
} tf_ssb_connections_update_t ;
2024-05-08 21:00:37 -04:00
static void _tf_ssb_connections_update_work ( tf_ssb_t * ssb , void * user_data )
2023-10-09 21:11:32 -04:00
{
2024-05-08 21:00:37 -04:00
tf_ssb_connections_update_t * update = user_data ;
2024-05-16 12:41:48 -04:00
if ( tf_ssb_is_shutting_down ( ssb ) )
{
return ;
}
2021-01-02 13:10:00 -05:00
sqlite3_stmt * statement ;
2024-05-08 21:00:37 -04:00
sqlite3 * db = tf_ssb_acquire_db_writer ( ssb ) ;
2023-10-09 21:11:32 -04:00
if ( update - > attempted )
2021-10-10 17:51:38 -04:00
{
2024-02-17 14:22:02 -05:00
if ( sqlite3_prepare ( db , " UPDATE connections SET last_attempt = strftime('%s', 'now') WHERE host = ?1 AND port = ?2 AND key = ?3 " , - 1 , & statement , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2024-02-15 18:35:01 -05:00
if ( sqlite3_bind_text ( statement , 1 , update - > host , - 1 , NULL ) = = SQLITE_OK & & sqlite3_bind_int ( statement , 2 , update - > port ) = = SQLITE_OK & &
2024-02-17 14:22:02 -05:00
sqlite3_bind_text ( statement , 3 , update - > key , - 1 , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2023-10-09 21:11:32 -04:00
if ( sqlite3_step ( statement ) ! = SQLITE_DONE )
{
tf_printf ( " tf_ssb_connections_set_attempted: %s. \n " , sqlite3_errmsg ( db ) ) ;
}
2021-01-02 13:10:00 -05:00
}
2023-10-09 21:11:32 -04:00
sqlite3_finalize ( statement ) ;
2021-01-02 13:10:00 -05:00
}
}
2023-10-09 21:11:32 -04:00
else if ( update - > succeeded )
2021-10-10 17:51:38 -04:00
{
2024-02-17 14:22:02 -05:00
if ( sqlite3_prepare ( db , " UPDATE connections SET last_success = strftime('%s', 'now') WHERE host = ?1 AND port = ?2 AND key = ?3 " , - 1 , & statement , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2024-02-15 18:35:01 -05:00
if ( sqlite3_bind_text ( statement , 1 , update - > host , - 1 , NULL ) = = SQLITE_OK & & sqlite3_bind_int ( statement , 2 , update - > port ) = = SQLITE_OK & &
2024-02-17 14:22:02 -05:00
sqlite3_bind_text ( statement , 3 , update - > key , - 1 , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2023-10-09 21:11:32 -04:00
if ( sqlite3_step ( statement ) ! = SQLITE_DONE )
{
tf_printf ( " tf_ssb_connections_set_succeeded: %s. \n " , sqlite3_errmsg ( db ) ) ;
}
2021-01-02 13:10:00 -05:00
}
2023-10-09 21:11:32 -04:00
sqlite3_finalize ( statement ) ;
2021-01-02 13:10:00 -05:00
}
}
2023-10-09 21:11:32 -04:00
else
2021-10-10 17:51:38 -04:00
{
2023-10-23 21:27:35 -04:00
if ( sqlite3_prepare ( db , " INSERT INTO connections (host, port, key) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING " , - 1 , & statement , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2024-02-15 18:35:01 -05:00
if ( sqlite3_bind_text ( statement , 1 , update - > host , - 1 , NULL ) = = SQLITE_OK & & sqlite3_bind_int ( statement , 2 , update - > port ) = = SQLITE_OK & &
2024-02-17 14:22:02 -05:00
sqlite3_bind_text ( statement , 3 , update - > key , - 1 , NULL ) = = SQLITE_OK )
2021-10-10 17:51:38 -04:00
{
2023-10-09 21:11:32 -04:00
int r = sqlite3_step ( statement ) ;
if ( r ! = SQLITE_DONE )
{
tf_printf ( " tf_ssb_connections_store: %d, %s. \n " , r , sqlite3_errmsg ( db ) ) ;
}
2021-01-02 13:10:00 -05:00
}
2023-10-09 21:11:32 -04:00
sqlite3_finalize ( statement ) ;
2021-01-02 13:10:00 -05:00
}
}
2024-05-08 21:00:37 -04:00
tf_ssb_release_db_writer ( ssb , db ) ;
2023-10-09 21:11:32 -04:00
}
2024-05-08 21:00:37 -04:00
static void _tf_ssb_connections_update_after_work ( tf_ssb_t * ssb , int status , void * user_data )
2023-10-09 21:11:32 -04:00
{
2024-05-08 21:00:37 -04:00
tf_free ( user_data ) ;
2023-10-09 21:11:32 -04:00
}
static void _tf_ssb_connections_queue_update ( tf_ssb_connections_t * connections , tf_ssb_connections_update_t * update )
{
2024-05-08 21:00:37 -04:00
tf_ssb_run_work ( connections - > ssb , _tf_ssb_connections_update_work , _tf_ssb_connections_update_after_work , update ) ;
2023-10-09 21:11:32 -04:00
}
void tf_ssb_connections_store ( tf_ssb_connections_t * connections , const char * host , int port , const char * key )
{
tf_ssb_connections_update_t * update = tf_malloc ( sizeof ( tf_ssb_connections_update_t ) ) ;
2024-02-15 18:35:01 -05:00
* update = ( tf_ssb_connections_update_t ) {
2023-10-09 21:11:32 -04:00
. port = port ,
} ;
snprintf ( update - > host , sizeof ( update - > host ) , " %s " , host ) ;
snprintf ( update - > key , sizeof ( update - > key ) , " %s " , key ) ;
_tf_ssb_connections_queue_update ( connections , update ) ;
}
void tf_ssb_connections_set_attempted ( tf_ssb_connections_t * connections , const char * host , int port , const char * key )
{
tf_ssb_connections_update_t * update = tf_malloc ( sizeof ( tf_ssb_connections_update_t ) ) ;
2024-02-15 18:35:01 -05:00
* update = ( tf_ssb_connections_update_t ) {
2023-10-09 21:11:32 -04:00
. port = port ,
. attempted = true ,
} ;
snprintf ( update - > host , sizeof ( update - > host ) , " %s " , host ) ;
snprintf ( update - > key , sizeof ( update - > key ) , " %s " , key ) ;
_tf_ssb_connections_queue_update ( connections , update ) ;
}
void tf_ssb_connections_set_succeeded ( tf_ssb_connections_t * connections , const char * host , int port , const char * key )
{
tf_ssb_connections_update_t * update = tf_malloc ( sizeof ( tf_ssb_connections_update_t ) ) ;
2024-02-15 18:35:01 -05:00
* update = ( tf_ssb_connections_update_t ) {
2023-10-09 21:11:32 -04:00
. port = port ,
. succeeded = true ,
} ;
snprintf ( update - > host , sizeof ( update - > host ) , " %s " , host ) ;
snprintf ( update - > key , sizeof ( update - > key ) , " %s " , key ) ;
_tf_ssb_connections_queue_update ( connections , update ) ;
2021-01-02 13:10:00 -05:00
}
2024-10-06 11:14:37 -04:00
static void _tf_ssb_connections_sync_broadcast_visit (
const char * host , const struct sockaddr_in * addr , tf_ssb_broadcast_origin_t origin , tf_ssb_connection_t * tunnel , const uint8_t * pub , void * user_data )
{
tf_ssb_t * ssb = user_data ;
if ( tunnel )
{
char target_id [ k_id_base64_len ] = { 0 } ;
if ( tf_ssb_id_bin_to_str ( target_id , sizeof ( target_id ) , pub ) )
{
char portal_id [ k_id_base64_len ] = { 0 } ;
if ( tf_ssb_connection_get_id ( tunnel , portal_id , sizeof ( portal_id ) ) )
{
tf_ssb_tunnel_create ( ssb , portal_id , target_id , k_tf_ssb_connect_flag_one_shot ) ;
}
}
}
else
{
tf_ssb_connect ( ssb , host , ntohs ( addr - > sin_port ) , pub , k_tf_ssb_connect_flag_one_shot ) ;
}
}
typedef struct _tf_ssb_connections_get_all_work_t
{
char * * connections ;
int connections_count ;
} tf_ssb_connections_get_all_work_t ;
static void _tf_ssb_connections_get_all_work ( tf_ssb_t * ssb , void * user_data )
{
tf_ssb_connections_get_all_work_t * work = user_data ;
sqlite3_stmt * statement ;
sqlite3 * db = tf_ssb_acquire_db_reader ( ssb ) ;
if ( sqlite3_prepare ( db , " SELECT host, port, key FROM connections ORDER BY last_attempt " , - 1 , & statement , NULL ) = = SQLITE_OK )
{
while ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
const char * host = ( const char * ) sqlite3_column_text ( statement , 0 ) ;
int port = sqlite3_column_int ( statement , 1 ) ;
const char * key = ( const char * ) sqlite3_column_text ( statement , 2 ) ;
char connection [ 1024 ] = { 0 } ;
2024-10-06 11:50:49 -04:00
snprintf ( connection , sizeof ( connection ) , " net:%s:%d~shs:%s " , host , port , * key = = ' @ ' ? key + 1 : key ) ;
2024-10-06 11:14:37 -04:00
char * dot = strrchr ( connection , ' . ' ) ;
if ( dot & & strcmp ( dot , " .ed25519 " ) = = 0 )
{
* dot = ' \0 ' ;
}
work - > connections = tf_resize_vec ( work - > connections , sizeof ( char * ) * ( work - > connections_count + 1 ) ) ;
work - > connections [ work - > connections_count + + ] = tf_strdup ( connection ) ;
}
sqlite3_finalize ( statement ) ;
}
else
{
tf_printf ( " prepare: %s \n " , sqlite3_errmsg ( db ) ) ;
}
tf_ssb_release_db_reader ( ssb , db ) ;
}
static void _tf_ssb_connections_get_all_after_work ( tf_ssb_t * ssb , int status , void * user_data )
{
tf_ssb_connections_get_all_work_t * work = user_data ;
for ( int i = 0 ; i < work - > connections_count ; i + + )
{
tf_ssb_connect_str ( ssb , work - > connections [ i ] , k_tf_ssb_connect_flag_one_shot ) ;
tf_free ( work - > connections [ i ] ) ;
}
tf_free ( work - > connections ) ;
tf_free ( work ) ;
}
void tf_ssb_connections_sync_start ( tf_ssb_connections_t * connections )
{
tf_ssb_connections_get_all_work_t * work = tf_malloc ( sizeof ( tf_ssb_connections_get_all_work_t ) ) ;
* work = ( tf_ssb_connections_get_all_work_t ) { 0 } ;
tf_ssb_run_work ( connections - > ssb , _tf_ssb_connections_get_all_work , _tf_ssb_connections_get_all_after_work , work ) ;
tf_ssb_visit_broadcasts ( connections - > ssb , _tf_ssb_connections_sync_broadcast_visit , connections - > ssb ) ;
}