2021-01-02 13:10:00 -05:00
# include "ssb.connections.h"
# include "ssb.h"
# include <uv.h>
# include <sqlite3.h>
# include <malloc.h>
# 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 ;
sqlite3 * db ;
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 )
{
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 ] ;
2021-01-02 13:10:00 -05:00
if ( tf_ssb_connection_get_host ( connection ) & &
* tf_ssb_connection_get_host ( connection ) & &
tf_ssb_connection_get_port ( connection ) & &
2021-10-10 17:51:38 -04:00
tf_ssb_connection_get_id ( connection , key , sizeof ( key ) ) )
{
2021-01-02 13:10:00 -05:00
tf_ssb_connections_store ( connections , tf_ssb_connection_get_host ( connection ) , tf_ssb_connection_get_port ( connection ) , key ) ;
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 :
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 ;
2021-10-10 17:51:38 -04:00
if ( sqlite3_prepare ( connections - > 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-01-02 13:10:00 -05:00
if ( sqlite3_bind_int ( statement , 1 , 60000 ) = = SQLITE_OK & &
2021-10-10 17:51:38 -04:00
sqlite3_step ( statement ) = = SQLITE_ROW )
{
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
{
2021-01-02 13:10:00 -05:00
printf ( " prepare: %s \n " , sqlite3_errmsg ( connections - > db ) ) ;
}
return result ;
}
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
{
2021-01-02 13:10:00 -05:00
char host [ 256 ] ;
int port ;
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_connections_get_next_connection ( connections , host , sizeof ( host ) , & port , key , sizeof ( key ) ) )
{
2021-10-24 15:23:21 -04:00
uint8_t key_bin [ k_id_bin_len ] ;
2021-10-10 17:51:38 -04:00
if ( tf_ssb_id_str_to_bin ( key_bin , key ) )
{
2021-01-02 13:10:00 -05:00
tf_ssb_connect ( connections - > ssb , host , port , key_bin ) ;
}
}
}
}
tf_ssb_connections_t * tf_ssb_connections_create ( tf_ssb_t * ssb )
{
tf_ssb_connections_t * connections = malloc ( sizeof ( tf_ssb_connections_t ) ) ;
memset ( connections , 0 , sizeof ( * connections ) ) ;
connections - > ssb = ssb ;
connections - > db = tf_ssb_get_db ( 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 ;
free ( connections ) ;
}
void tf_ssb_connections_destroy ( tf_ssb_connections_t * connections )
{
uv_close ( ( uv_handle_t * ) & connections - > timer , _tf_ssb_connections_on_handle_close ) ;
}
void tf_ssb_connections_store ( tf_ssb_connections_t * connections , const char * host , int port , const char * key )
{
sqlite3_stmt * statement ;
2021-10-10 17:51:38 -04:00
if ( sqlite3_prepare ( connections - > db , " INSERT INTO connections (host, port, key) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING " , - 1 , & statement , NULL ) = = SQLITE_OK )
{
2021-01-02 13:10:00 -05:00
if ( sqlite3_bind_text ( statement , 1 , host , - 1 , NULL ) = = SQLITE_OK & &
sqlite3_bind_int ( statement , 2 , port ) = = SQLITE_OK & &
2021-10-10 17:51:38 -04:00
sqlite3_bind_text ( statement , 3 , key , - 1 , NULL ) = = SQLITE_OK )
{
2021-01-02 13:10:00 -05:00
int r = sqlite3_step ( statement ) ;
2021-10-10 17:51:38 -04:00
if ( r ! = SQLITE_DONE )
{
2021-01-02 13:10:00 -05:00
printf ( " tf_ssb_connections_store: %d, %s. \n " , r , sqlite3_errmsg ( connections - > db ) ) ;
}
}
sqlite3_finalize ( statement ) ;
}
}
void tf_ssb_connections_set_attempted ( tf_ssb_connections_t * connections , const char * host , int port , const char * key )
{
sqlite3_stmt * statement ;
2021-10-10 17:51:38 -04:00
if ( sqlite3_prepare ( connections - > db , " UPDATE connections SET last_attempt = strftime('%s', 'now') WHERE host = $1 AND port = $2 AND key = $3 " , - 1 , & statement , NULL ) = = SQLITE_OK )
{
2021-01-02 13:10:00 -05:00
if ( sqlite3_bind_text ( statement , 1 , host , - 1 , NULL ) = = SQLITE_OK & &
sqlite3_bind_int ( statement , 2 , port ) = = SQLITE_OK & &
2021-10-10 17:51:38 -04:00
sqlite3_bind_text ( statement , 3 , key , - 1 , NULL ) = = SQLITE_OK )
{
if ( sqlite3_step ( statement ) ! = SQLITE_DONE )
{
2021-01-02 13:10:00 -05:00
printf ( " tf_ssb_connections_set_attempted: %s. \n " , sqlite3_errmsg ( connections - > db ) ) ;
}
}
sqlite3_finalize ( statement ) ;
}
}
void tf_ssb_connections_set_succeeded ( tf_ssb_connections_t * connections , const char * host , int port , const char * key )
{
sqlite3_stmt * statement ;
2021-10-10 17:51:38 -04:00
if ( sqlite3_prepare ( connections - > db , " UPDATE connections SET last_success = strftime('%s', 'now') WHERE host = $1 AND port = $2 AND key = $3 " , - 1 , & statement , NULL ) = = SQLITE_OK )
{
2021-01-02 13:10:00 -05:00
if ( sqlite3_bind_text ( statement , 1 , host , - 1 , NULL ) = = SQLITE_OK & &
sqlite3_bind_int ( statement , 2 , port ) = = SQLITE_OK & &
2021-10-10 17:51:38 -04:00
sqlite3_bind_text ( statement , 3 , key , - 1 , NULL ) = = SQLITE_OK )
{
if ( sqlite3_step ( statement ) ! = SQLITE_DONE )
{
2021-01-02 13:10:00 -05:00
printf ( " tf_ssb_connections_set_succeeded: %s. \n " , sqlite3_errmsg ( connections - > db ) ) ;
}
}
sqlite3_finalize ( statement ) ;
}
}