2021-01-02 13:10:00 -05:00
# include "ssb.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.connections.h"
2021-08-22 15:34:28 -04:00
# include "ssb.db.h"
2022-11-16 20:36:24 -05:00
# include "ssb.rpc.h"
2021-01-02 13:10:00 -05:00
# include "trace.h"
2022-07-09 11:13:35 -04:00
# include "util.js.h"
2021-01-02 13:10:00 -05:00
2024-08-07 21:03:39 -04:00
# include "ares.h"
2023-05-21 17:36:51 -04:00
# include "quickjs.h"
# include "sodium/crypto_auth.h"
# include "sodium/crypto_box.h"
# include "sodium/crypto_hash_sha256.h"
# include "sodium/crypto_scalarmult.h"
# include "sodium/crypto_scalarmult_curve25519.h"
# include "sodium/crypto_secretbox.h"
# include "sodium/crypto_sign.h"
# include "sodium/utils.h"
# include "sqlite3.h"
# include "uv.h"
2024-08-07 21:03:39 -04:00
# if !defined(_WIN32)
# include <arpa/nameser.h>
# endif
2021-01-02 13:10:00 -05:00
# include <assert.h>
# include <stdbool.h>
# include <stdio.h>
# include <string.h>
# include <time.h>
2021-12-21 14:06:44 -05:00
# if !defined(_countof)
# define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
# endif
2022-11-02 19:34:44 -04:00
# define GREEN "\e[1;32m"
# define MAGENTA "\e[1;35m"
# define CYAN "\e[1;36m"
# define RESET "\e[0m"
2023-04-19 19:05:59 -04:00
# define PRE_CALLBACK(ssb, cb) uint64_t pre_callback_hrtime_ns = _tf_ssb_callback_pre(ssb)
# define POST_CALLBACK(ssb, cb) _tf_ssb_callback_post(ssb, cb, pre_callback_hrtime_ns)
2021-10-24 15:23:21 -04:00
static_assert ( k_id_base64_len = = sodium_base64_ENCODED_LEN ( 9 + crypto_box_PUBLICKEYBYTES , sodium_base64_VARIANT_ORIGINAL ) , " k_id_base64_len " ) ;
static_assert ( k_id_bin_len = = crypto_box_PUBLICKEYBYTES , " k_id_bin_len " ) ;
static_assert ( k_blob_id_len = = ( sodium_base64_ENCODED_LEN ( crypto_hash_sha256_BYTES , sodium_base64_VARIANT_ORIGINAL ) + 8 ) , " k_blob_id_len " ) ;
2021-01-02 13:10:00 -05:00
2024-03-02 15:01:09 -05:00
const char * k_ssb_network_string = " d4a1cb88a66f02f8db635ce26441cc5dac1b08420ceaac230839b755845a9ffb " ;
2021-01-02 13:10:00 -05:00
2024-02-15 18:35:01 -05:00
const char * k_ssb_type_names [ ] = {
2023-11-08 19:28:34 -05:00
" binary " ,
" utf8 " ,
" json " ,
" unknown " ,
} ;
2024-02-15 18:35:01 -05:00
typedef enum
{
2021-01-02 13:10:00 -05:00
k_tf_ssb_state_invalid ,
k_tf_ssb_state_connected ,
k_tf_ssb_state_sent_hello ,
k_tf_ssb_state_sent_identity ,
k_tf_ssb_state_verified ,
k_tf_ssb_state_server_wait_hello ,
k_tf_ssb_state_server_wait_client_identity ,
k_tf_ssb_state_server_verified ,
k_tf_ssb_state_closing ,
} tf_ssb_state_t ;
2024-02-15 18:35:01 -05:00
enum
{
2021-09-06 13:50:38 -04:00
k_connections_changed_callbacks_max = 8 ,
2023-01-14 08:27:19 -05:00
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024 ,
2023-08-20 14:36:46 -04:00
k_debug_close_message_count = 256 ,
k_debug_close_connection_count = 32 ,
2021-01-02 13:10:00 -05:00
} ;
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t ;
typedef struct _tf_ssb_connection_t tf_ssb_connection_t ;
typedef struct _tf_ssb_request_t tf_ssb_request_t ;
2023-01-22 15:37:19 -05:00
typedef struct _tf_ssb_debug_message_t
{
bool outgoing ;
int flags ;
int32_t request_number ;
2023-08-20 14:36:46 -04:00
time_t timestamp ;
2023-01-22 15:37:19 -05:00
size_t size ;
uint8_t data [ ] ;
} tf_ssb_debug_message_t ;
typedef struct _tf_ssb_debug_close_t
{
char id [ k_id_base64_len ] ;
char tunnel [ k_id_base64_len ] ;
char reason [ 128 ] ;
tf_ssb_debug_message_t * messages [ k_debug_close_message_count ] ;
} tf_ssb_debug_close_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_request_t
{
2024-05-02 19:02:23 -04:00
char name [ 256 ] ;
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_t * callback ;
2022-11-02 19:34:44 -04:00
tf_ssb_callback_cleanup_t * cleanup ;
2021-01-02 13:10:00 -05:00
void * user_data ;
2022-11-06 21:57:29 -05:00
tf_ssb_connection_t * dependent_connection ;
2024-01-10 20:38:30 -05:00
int32_t request_number ;
2021-01-02 13:10:00 -05:00
} tf_ssb_request_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_broadcast_t
{
2021-01-02 13:10:00 -05:00
tf_ssb_broadcast_t * next ;
time_t ctime ;
time_t mtime ;
char host [ 256 ] ;
struct sockaddr_in addr ;
2022-11-02 19:34:44 -04:00
tf_ssb_connection_t * tunnel_connection ;
2021-01-02 13:10:00 -05:00
uint8_t pub [ crypto_sign_PUBLICKEYBYTES ] ;
} tf_ssb_broadcast_t ;
typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_rpc_callback_node_t
{
2021-01-02 13:10:00 -05:00
const char * * name ;
2023-02-03 10:06:18 -05:00
const char * flattened_name ;
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_t * callback ;
2021-11-07 17:28:58 -05:00
tf_ssb_callback_cleanup_t * cleanup ;
2021-01-02 13:10:00 -05:00
void * user_data ;
tf_ssb_rpc_callback_node_t * next ;
} tf_ssb_rpc_callback_node_t ;
2021-11-07 17:28:58 -05:00
typedef struct _tf_ssb_connections_changed_callback_node_t tf_ssb_connections_changed_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_connections_changed_callback_node_t
{
2021-11-07 17:28:58 -05:00
tf_ssb_connections_changed_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
void * user_data ;
tf_ssb_connections_changed_callback_node_t * next ;
} tf_ssb_connections_changed_callback_node_t ;
2021-11-10 19:05:07 -05:00
typedef struct _tf_ssb_message_added_callback_node_t tf_ssb_message_added_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_message_added_callback_node_t
{
2021-11-10 19:05:07 -05:00
tf_ssb_message_added_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
void * user_data ;
tf_ssb_message_added_callback_node_t * next ;
} tf_ssb_message_added_callback_node_t ;
2021-09-06 13:50:38 -04:00
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_blob_want_added_callback_node_t
{
2021-11-07 17:28:58 -05:00
tf_ssb_blob_want_added_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
2021-09-06 13:50:38 -04:00
void * user_data ;
tf_ssb_blob_want_added_callback_node_t * next ;
} tf_ssb_blob_want_added_callback_node_t ;
2021-11-07 17:28:58 -05:00
typedef struct _tf_ssb_broadcasts_changed_callback_node_t tf_ssb_broadcasts_changed_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_broadcasts_changed_callback_node_t
{
2021-11-07 17:28:58 -05:00
tf_ssb_broadcasts_changed_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
void * user_data ;
tf_ssb_broadcasts_changed_callback_node_t * next ;
} tf_ssb_broadcasts_changed_callback_node_t ;
2023-02-28 20:36:26 -05:00
typedef struct _tf_thread_work_time_t
{
int64_t thread_id ;
uint64_t hrtime ;
} tf_thread_work_time_t ;
2024-01-27 08:48:16 -05:00
typedef struct _tf_ssb_timer_t
{
tf_ssb_t * ssb ;
uv_timer_t timer ;
void ( * callback ) ( tf_ssb_t * ssb , void * user_data ) ;
void * user_data ;
} tf_ssb_timer_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_t
{
2021-01-02 13:10:00 -05:00
bool own_context ;
JSRuntime * runtime ;
JSContext * context ;
tf_trace_t * trace ;
2023-02-07 20:29:44 -05:00
const char * db_path ;
uv_mutex_t db_readers_lock ;
2023-06-14 20:27:49 -04:00
uv_mutex_t db_writer_lock ;
sqlite3 * db_writer ;
2023-02-07 20:29:44 -05:00
sqlite3 * * db_readers ;
int db_readers_count ;
2021-01-02 13:10:00 -05:00
uv_loop_t own_loop ;
uv_loop_t * loop ;
uv_udp_t broadcast_listener ;
uv_udp_t broadcast_sender ;
2022-01-19 22:35:03 -05:00
uv_timer_t broadcast_cleanup_timer ;
2021-01-02 13:10:00 -05:00
uv_timer_t broadcast_timer ;
2021-12-21 14:06:44 -05:00
uv_timer_t trace_timer ;
2021-01-02 13:10:00 -05:00
uv_tcp_t server ;
2024-03-02 15:01:09 -05:00
uint8_t network_key [ 32 ] ;
2021-01-02 13:10:00 -05:00
uint8_t pub [ crypto_sign_PUBLICKEYBYTES ] ;
uint8_t priv [ crypto_sign_SECRETKEYBYTES ] ;
2022-12-31 13:59:29 -05:00
bool verbose ;
2024-01-09 21:41:28 -05:00
bool store_debug_messages ;
2024-02-06 12:42:17 -05:00
bool shutting_down ;
2022-12-31 13:59:29 -05:00
2022-02-05 15:18:58 -05:00
int messages_stored ;
2023-01-18 17:52:54 -05:00
int blobs_stored ;
2022-02-05 15:18:58 -05:00
int rpc_in ;
int rpc_out ;
2021-01-02 13:10:00 -05:00
tf_ssb_connection_t * connections ;
2022-01-12 20:08:17 -05:00
int connections_count ;
2024-02-06 12:42:17 -05:00
int connection_ref_count ;
2022-07-09 18:00:33 -04:00
int request_count ;
2021-01-02 13:10:00 -05:00
tf_ssb_connections_t * connections_tracker ;
tf_ssb_broadcast_t * broadcasts ;
2022-01-12 20:08:17 -05:00
int broadcasts_count ;
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_node_t * rpc ;
2022-01-12 20:08:17 -05:00
int rpc_count ;
2021-11-07 17:28:58 -05:00
tf_ssb_connections_changed_callback_node_t * connections_changed ;
2022-01-12 20:08:17 -05:00
int connections_changed_count ;
2021-11-10 19:05:07 -05:00
tf_ssb_message_added_callback_node_t * message_added ;
2022-01-12 20:08:17 -05:00
int message_added_count ;
2021-09-06 13:50:38 -04:00
tf_ssb_blob_want_added_callback_node_t * blob_want_added ;
2022-01-12 20:08:17 -05:00
int blob_want_added_count ;
2021-11-07 17:28:58 -05:00
tf_ssb_broadcasts_changed_callback_node_t * broadcasts_changed ;
2022-01-12 20:08:17 -05:00
int broadcasts_changed_count ;
2023-01-22 15:37:19 -05:00
tf_ssb_debug_close_t debug_close [ k_debug_close_connection_count ] ;
2023-02-28 20:36:26 -05:00
2023-08-16 20:01:59 -04:00
int32_t thread_busy_count ;
int32_t thread_busy_max ;
2023-04-19 19:05:59 -04:00
void ( * hitch_callback ) ( const char * name , uint64_t duration , void * user_data ) ;
void * hitch_user_data ;
2023-07-19 21:02:50 -04:00
tf_ssb_store_queue_t store_queue ;
2023-08-02 20:30:48 -04:00
int ref_count ;
2023-10-08 10:25:22 -04:00
uv_thread_t thread_self ;
2023-10-11 11:44:40 -04:00
bool is_room ;
char * room_name ;
2024-08-07 21:03:39 -04:00
char seeds_host [ 256 ] ;
2024-01-27 08:48:16 -05:00
tf_ssb_timer_t * * timers ;
int timers_count ;
2021-01-02 13:10:00 -05:00
} tf_ssb_t ;
2023-01-08 12:45:15 -05:00
typedef struct _tf_ssb_connection_message_request_t
{
int32_t request_number ;
2024-01-10 20:38:30 -05:00
char author [ k_id_base64_len ] ;
2023-01-08 12:45:15 -05:00
bool keys ;
} tf_ssb_connection_message_request_t ;
2023-01-16 21:17:29 -05:00
typedef struct _tf_ssb_connection_scheduled_t
{
tf_ssb_scheduled_callback_t * callback ;
void * user_data ;
} tf_ssb_connection_scheduled_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_connection_t
{
2021-01-02 13:10:00 -05:00
tf_ssb_t * ssb ;
uv_tcp_t tcp ;
uv_connect_t connect ;
2022-01-22 15:13:14 -05:00
uv_async_t async ;
2023-10-08 11:14:42 -04:00
bool closing ;
2021-01-02 13:10:00 -05:00
2022-11-02 19:34:44 -04:00
tf_ssb_connection_t * tunnel_connection ;
int32_t tunnel_request_number ;
2023-01-04 19:52:23 -05:00
tf_ssb_blob_wants_t blob_wants ;
2023-01-08 15:01:35 -05:00
bool sent_clock ;
int32_t ebt_request_number ;
2023-01-04 19:52:23 -05:00
2021-09-06 13:50:38 -04:00
JSValue object ;
2022-11-02 19:34:44 -04:00
char name [ 32 ] ;
2021-01-02 13:10:00 -05:00
char host [ 256 ] ;
int port ;
tf_ssb_state_t state ;
2023-01-07 19:25:38 -05:00
bool is_attendant ;
int32_t attendant_request_number ;
2021-01-02 13:10:00 -05:00
uint8_t epub [ crypto_box_PUBLICKEYBYTES ] ;
uint8_t epriv [ crypto_box_SECRETKEYBYTES ] ;
uint8_t serverpub [ crypto_box_PUBLICKEYBYTES ] ;
uint8_t serverepub [ crypto_box_PUBLICKEYBYTES ] ;
uint8_t detached_signature_A [ crypto_sign_BYTES ] ;
uint8_t s_to_c_box_key [ crypto_hash_sha256_BYTES ] ;
uint8_t c_to_s_box_key [ crypto_hash_sha256_BYTES ] ;
2023-01-01 19:58:15 -05:00
uint8_t recv_buffer [ 128 * 1024 ] ;
2021-01-02 13:10:00 -05:00
size_t recv_size ;
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] ;
uint8_t send_nonce [ crypto_secretbox_NONCEBYTES ] ;
uint16_t body_len ;
uint8_t body_auth_tag [ 16 ] ;
uint8_t rpc_recv_buffer [ 8 * 1024 * 1024 ] ;
uint8_t pad ;
size_t rpc_recv_size ;
2023-01-14 08:27:19 -05:00
uint8_t box_stream_buf [ 16 + k_tf_ssb_rpc_message_body_length_max ] ;
uint8_t secretbox_buf [ k_tf_ssb_rpc_message_body_length_max ] ;
2021-01-02 13:10:00 -05:00
uint32_t send_request_number ;
tf_ssb_connection_t * next ;
tf_ssb_request_t * requests ;
2022-07-11 21:51:15 -04:00
int requests_count ;
2022-01-25 20:15:04 -05:00
const char * destroy_reason ;
2023-01-08 12:45:15 -05:00
tf_ssb_connection_message_request_t * message_requests ;
int message_requests_count ;
2023-01-16 21:17:29 -05:00
tf_ssb_connection_scheduled_t * scheduled ;
int scheduled_count ;
2023-01-22 15:37:19 -05:00
tf_ssb_debug_message_t * debug_messages [ k_debug_close_message_count ] ;
2023-10-08 11:14:42 -04:00
int ref_count ;
2024-05-22 19:53:33 -04:00
int read_back_pressure ;
2024-06-02 12:38:12 -04:00
int active_write_count ;
2021-01-02 13:10:00 -05:00
} tf_ssb_connection_t ;
2021-09-06 13:50:38 -04:00
static JSClassID _connection_class_id ;
2022-11-02 19:34:44 -04:00
static int s_connection_index ;
static int s_tunnel_index ;
2021-09-06 13:50:38 -04:00
2024-08-07 21:03:39 -04:00
static void _tf_ssb_add_broadcast ( tf_ssb_t * ssb , const tf_ssb_broadcast_t * broadcast ) ;
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_client_send_hello ( tf_ssb_connection_t * connection ) ;
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_close ( tf_ssb_connection_t * connection , const char * reason ) ;
2024-05-02 19:02:23 -04:00
static void _tf_ssb_connection_destroy ( tf_ssb_connection_t * connection , const char * reason ) ;
2021-09-06 13:50:38 -04:00
static void _tf_ssb_connection_finalizer ( JSRuntime * runtime , JSValue value ) ;
2024-05-02 19:02:23 -04:00
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 ) ;
2024-08-07 21:03:39 -04:00
static bool _tf_ssb_parse_broadcast ( const char * in_broadcast , tf_ssb_broadcast_t * out_broadcast ) ;
2024-01-27 09:44:17 -05:00
static void _tf_ssb_start_update_settings ( tf_ssb_t * ssb ) ;
2024-05-02 19:02:23 -04:00
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 ) ;
2021-01-02 13:10:00 -05:00
2023-01-22 15:37:19 -05:00
static void _tf_ssb_add_debug_close ( tf_ssb_t * ssb , tf_ssb_connection_t * connection , const char * reason )
{
2024-01-09 21:41:28 -05:00
if ( ! ssb - > store_debug_messages )
{
return ;
}
2023-01-22 15:37:19 -05:00
for ( int i = 0 ; i < k_debug_close_message_count ; i + + )
{
tf_free ( ssb - > debug_close [ k_debug_close_connection_count - 1 ] . messages [ i ] ) ;
}
for ( int i = k_debug_close_connection_count - 1 ; i > 0 ; i - - )
{
ssb - > debug_close [ i ] = ssb - > debug_close [ i - 1 ] ;
}
2023-03-17 18:57:18 -04:00
2023-01-22 15:37:19 -05:00
tf_ssb_id_bin_to_str ( ssb - > debug_close [ 0 ] . id , sizeof ( ssb - > debug_close [ 0 ] . id ) , connection - > serverpub ) ;
if ( connection - > tunnel_connection )
{
tf_ssb_id_bin_to_str ( ssb - > debug_close [ 0 ] . tunnel , sizeof ( ssb - > debug_close [ 0 ] . tunnel ) , connection - > tunnel_connection - > serverpub ) ;
}
else
{
memset ( ssb - > debug_close [ 0 ] . tunnel , 0 , sizeof ( ssb - > debug_close [ 0 ] . tunnel ) ) ;
}
memcpy ( ssb - > debug_close [ 0 ] . messages , connection - > debug_messages , sizeof ( connection - > debug_messages ) ) ;
memset ( connection - > debug_messages , 0 , sizeof ( connection - > debug_messages ) ) ;
snprintf ( ssb - > debug_close [ 0 ] . reason , sizeof ( ssb - > debug_close [ 0 ] . reason ) , " %s " , reason ) ;
}
static void _tf_ssb_connection_add_debug_message ( tf_ssb_connection_t * connection , bool outgoing , int flags , int32_t request_number , const uint8_t * data , size_t size )
{
2024-01-09 21:41:28 -05:00
if ( ! connection - > ssb - > store_debug_messages )
{
return ;
}
2023-01-22 15:37:19 -05:00
if ( connection - > debug_messages [ k_debug_close_message_count - 1 ] )
{
tf_free ( connection - > debug_messages [ k_debug_close_message_count - 1 ] ) ;
}
for ( int i = k_debug_close_message_count - 1 ; i > 0 ; i - - )
{
connection - > debug_messages [ i ] = connection - > debug_messages [ i - 1 ] ;
}
tf_ssb_debug_message_t * message = tf_malloc ( sizeof ( tf_ssb_debug_message_t ) + size ) ;
2024-02-15 18:35:01 -05:00
* message = ( tf_ssb_debug_message_t ) {
2023-01-22 15:37:19 -05:00
. outgoing = outgoing ,
. flags = flags ,
. request_number = request_number ,
2023-08-20 14:36:46 -04:00
. timestamp = time ( NULL ) ,
2023-01-22 15:37:19 -05:00
. size = size ,
} ;
memcpy ( message + 1 , data , size ) ;
connection - > debug_messages [ 0 ] = message ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_send_close ( tf_ssb_connection_t * connection )
{
uint8_t message_enc [ 34 ] ;
uint8_t nonce1 [ crypto_secretbox_NONCEBYTES ] ;
memcpy ( nonce1 , connection - > send_nonce , sizeof ( nonce1 ) ) ;
_tf_ssb_nonce_inc ( connection - > send_nonce ) ;
uint8_t header [ 18 ] = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_easy ( message_enc , header , sizeof ( header ) , nonce1 , connection - > c_to_s_box_key ) = = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_write ( connection , message_enc , sizeof ( message_enc ) ) ;
2021-10-10 17:51:38 -04:00
}
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " crypto_secretbox_easy close message " ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_connection_close ( tf_ssb_connection_t * connection , const char * reason )
{
2021-10-10 17:51:38 -04:00
if ( connection - > state = = k_tf_ssb_state_closing )
{
2021-01-02 13:10:00 -05:00
return ;
2021-10-10 17:51:38 -04:00
}
2024-02-15 18:35:01 -05:00
else if ( connection - > state = = k_tf_ssb_state_verified | | connection - > state = = k_tf_ssb_state_server_verified )
2021-10-10 17:51:38 -04:00
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Connection %s %p is closing: %s. \n " , connection - > name , connection , reason ) ;
2023-01-22 15:37:19 -05:00
_tf_ssb_add_debug_close ( connection - > ssb , connection , reason ) ;
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_closing ;
_tf_ssb_connection_send_close ( connection ) ;
2021-10-10 17:51:38 -04:00
}
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , reason ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_connection_on_tcp_alloc ( uv_handle_t * handle , size_t suggested_size , uv_buf_t * buf )
{
tf_ssb_connection_t * connection = handle - > data ;
size_t malloc_size = sizeof ( connection - > recv_buffer ) - connection - > recv_size ;
2022-06-04 13:04:51 -04:00
buf - > base = malloc_size ? tf_malloc ( malloc_size ) : NULL ;
2021-01-02 13:10:00 -05:00
buf - > len = malloc_size ;
}
static void _tf_ssb_connection_on_write ( uv_write_t * req , int status )
{
2024-06-02 12:38:12 -04:00
tf_ssb_connection_t * connection = req - > data ;
tf_ssb_connection_adjust_write_count ( connection , - 1 ) ;
2022-02-27 14:38:48 -05:00
if ( status )
{
2022-11-13 17:30:09 -05:00
char buffer [ 256 ] ;
snprintf ( buffer , sizeof ( buffer ) , " write failed asynchronously: %s " , uv_strerror ( status ) ) ;
_tf_ssb_connection_close ( connection , buffer ) ;
2022-02-27 14:38:48 -05:00
}
2022-06-04 13:04:51 -04:00
tf_free ( req ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_write ( tf_ssb_connection_t * connection , void * data , size_t size )
{
2022-11-02 19:34:44 -04:00
if ( connection - > tcp . data )
2022-01-19 23:01:45 -05:00
{
2022-11-02 19:34:44 -04:00
uv_write_t * write = tf_malloc ( sizeof ( uv_write_t ) + size ) ;
* write = ( uv_write_t ) { . data = connection } ;
memcpy ( write + 1 , data , size ) ;
2024-06-02 12:38:12 -04:00
tf_ssb_connection_adjust_write_count ( connection , 1 ) ;
2022-11-02 19:34:44 -04:00
int result = uv_write ( write , ( uv_stream_t * ) & connection - > tcp , & ( uv_buf_t ) { . base = ( char * ) ( write + 1 ) , . len = size } , 1 , _tf_ssb_connection_on_write ) ;
if ( result )
{
2024-06-02 12:38:12 -04:00
tf_ssb_connection_adjust_write_count ( connection , - 1 ) ;
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_close ( connection , " write failed " ) ;
tf_free ( write ) ;
}
}
else if ( connection - > tunnel_connection )
{
2024-05-02 20:10:56 -04:00
tf_ssb_connection_rpc_send (
connection - > tunnel_connection , k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream , - connection - > tunnel_request_number , NULL , data , size , NULL , NULL , NULL ) ;
2022-01-19 23:01:45 -05:00
}
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_connection_send_identity ( tf_ssb_connection_t * connection , uint8_t * hmac , uint8_t * pubkey )
{
memcpy ( connection - > serverepub , pubkey , sizeof ( connection - > serverepub ) ) ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256_verify ( hmac , connection - > serverepub , 32 , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " invalid server hello " ) ;
return ;
}
uint8_t shared_secret_ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_ab , connection - > epriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_ab as client " ) ;
return ;
}
uint8_t servercurvepub [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_pk_to_curve25519 ( servercurvepub , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute key to curve25519 as client " ) ;
return ;
}
uint8_t shared_secret_aB [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_aB , connection - > epriv , servercurvepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_aB as client " ) ;
return ;
}
uint8_t hash [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
2024-03-02 15:01:09 -05:00
uint8_t msg [ sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > serverpub ) + crypto_hash_sha256_BYTES ] ;
memcpy ( msg , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > serverpub ) , hash , sizeof ( hash ) ) ;
2021-01-02 13:10:00 -05:00
unsigned long long siglen ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_detached ( connection - > detached_signature_A , & siglen , msg , sizeof ( msg ) , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute detached_signature_A as client " ) ;
return ;
}
uint8_t tosend [ crypto_sign_BYTES + sizeof ( connection - > ssb - > pub ) ] ;
memcpy ( tosend , connection - > detached_signature_A , sizeof ( connection - > detached_signature_A ) ) ;
memcpy ( tosend + sizeof ( connection - > detached_signature_A ) , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] = { 0 } ;
2024-03-02 15:01:09 -05:00
uint8_t tohash [ sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) ] ;
memcpy ( tohash , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
2021-01-02 13:10:00 -05:00
uint8_t hash2 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash2 , tohash , sizeof ( tohash ) ) ;
uint8_t c [ crypto_secretbox_MACBYTES + sizeof ( tosend ) ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_easy ( c , tosend , sizeof ( tosend ) , nonce , hash2 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to create initial secretbox as client " ) ;
return ;
}
static_assert ( sizeof ( c ) = = 112 , " client send size " ) ;
_tf_ssb_write ( connection , c , sizeof ( c ) ) ;
connection - > state = k_tf_ssb_state_sent_identity ;
}
static void _tf_ssb_nonce_inc ( uint8_t * nonce )
{
int i = 23 ;
2021-10-10 17:51:38 -04:00
while ( + + nonce [ i ] = = 0 & & i > 0 )
{
2021-01-02 13:10:00 -05:00
i - - ;
}
}
static void _tf_ssb_connection_box_stream_send ( tf_ssb_connection_t * connection , const uint8_t * message , size_t size )
{
2023-08-12 15:57:00 -04:00
const size_t k_send_max = 4096 ;
2023-01-14 08:27:19 -05:00
for ( size_t offset = 0 ; offset < size ; offset + = k_send_max )
{
size_t send_size = size - offset > k_send_max ? k_send_max : size - offset ;
uint8_t * message_enc = tf_malloc ( send_size + 34 ) ;
2021-01-02 13:10:00 -05:00
2023-01-14 08:27:19 -05:00
uint8_t nonce1 [ crypto_secretbox_NONCEBYTES ] ;
memcpy ( nonce1 , connection - > send_nonce , sizeof ( nonce1 ) ) ;
_tf_ssb_nonce_inc ( connection - > send_nonce ) ;
uint8_t nonce2 [ crypto_secretbox_NONCEBYTES ] ;
memcpy ( nonce2 , connection - > send_nonce , sizeof ( nonce2 ) ) ;
_tf_ssb_nonce_inc ( connection - > send_nonce ) ;
2021-01-02 13:10:00 -05:00
2023-01-14 08:27:19 -05:00
if ( crypto_secretbox_easy ( message_enc + 34 - 16 , message + offset , send_size , nonce2 , connection - > c_to_s_box_key ) ! = 0 )
{
_tf_ssb_connection_close ( connection , " unable to secretbox message " ) ;
tf_free ( message_enc ) ;
return ;
}
2021-01-02 13:10:00 -05:00
2023-01-14 08:27:19 -05:00
uint8_t header [ 18 ] ;
* ( uint16_t * ) header = htons ( ( uint16_t ) send_size ) ;
memcpy ( header + sizeof ( uint16_t ) , message_enc + 34 - 16 , 16 ) ;
if ( crypto_secretbox_easy ( message_enc , header , sizeof ( header ) , nonce1 , connection - > c_to_s_box_key ) ! = 0 )
{
_tf_ssb_connection_close ( connection , " unable to secretbox header " ) ;
tf_free ( message_enc ) ;
return ;
}
2023-01-13 19:55:51 -05:00
2023-01-14 08:27:19 -05:00
_tf_ssb_write ( connection , message_enc , send_size + 34 ) ;
2022-06-04 13:04:51 -04:00
tf_free ( message_enc ) ;
2021-01-02 13:10:00 -05:00
}
}
2024-06-02 12:38:12 -04:00
static void _tf_ssb_connection_dispatch_scheduled ( tf_ssb_connection_t * connection )
{
2024-06-03 12:36:34 -04:00
while ( ( connection - > active_write_count = = 0 | | connection - > closing ) & & connection - > scheduled_count & & connection - > scheduled )
2024-06-02 12:38:12 -04:00
{
tf_ssb_connection_scheduled_t scheduled = connection - > scheduled [ 0 ] ;
memmove ( connection - > scheduled , connection - > scheduled + 1 , sizeof ( tf_ssb_connection_scheduled_t ) * ( connection - > scheduled_count - 1 ) ) ;
connection - > scheduled_count - - ;
tf_trace_begin ( connection - > ssb - > trace , " scheduled callback " ) ;
scheduled . callback ( connection , scheduled . user_data ) ;
tf_trace_end ( connection - > ssb - > trace ) ;
}
}
2023-01-16 21:17:29 -05:00
void tf_ssb_connection_schedule_idle ( tf_ssb_connection_t * connection , tf_ssb_scheduled_callback_t * callback , void * user_data )
{
connection - > scheduled = tf_resize_vec ( connection - > scheduled , sizeof ( tf_ssb_connection_scheduled_t ) * ( connection - > scheduled_count + 1 ) ) ;
2024-02-15 18:35:01 -05:00
connection - > scheduled [ connection - > scheduled_count + + ] = ( tf_ssb_connection_scheduled_t ) {
2023-01-16 21:17:29 -05:00
. callback = callback ,
. user_data = user_data ,
} ;
2024-06-02 12:38:12 -04:00
_tf_ssb_connection_dispatch_scheduled ( connection ) ;
2023-01-16 21:17:29 -05:00
}
2022-07-11 21:51:15 -04:00
static int _request_compare ( const void * a , const void * b )
{
int32_t ai = * ( const int32_t * ) a ;
const tf_ssb_request_t * br = ( const tf_ssb_request_t * ) b ;
return ai < br - > request_number ? - 1 : br - > request_number < ai ? 1 : 0 ;
}
2021-01-02 13:10:00 -05:00
static bool _tf_ssb_connection_get_request_callback ( tf_ssb_connection_t * connection , int32_t request_number , tf_ssb_rpc_callback_t * * out_callback , void * * out_user_data )
{
2022-07-11 21:51:15 -04:00
if ( ! connection - > requests )
{
return false ;
}
tf_ssb_request_t * request = bsearch ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) ;
if ( request )
2021-10-10 17:51:38 -04:00
{
2022-07-11 21:51:15 -04:00
if ( out_callback )
2021-10-10 17:51:38 -04:00
{
2022-07-11 21:51:15 -04:00
* out_callback = request - > callback ;
}
if ( out_user_data )
{
* out_user_data = request - > user_data ;
2021-01-02 13:10:00 -05:00
}
2022-07-11 21:51:15 -04:00
return true ;
2021-01-02 13:10:00 -05:00
}
2022-07-11 21:51:15 -04:00
return false ;
2021-01-02 13:10:00 -05:00
}
2024-05-02 20:10:56 -04:00
void tf_ssb_connection_add_request ( tf_ssb_connection_t * connection , int32_t request_number , const char * name , tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup ,
void * user_data , tf_ssb_connection_t * dependent_connection )
2021-01-02 13:10:00 -05:00
{
2024-02-15 18:35:01 -05:00
tf_ssb_request_t * existing =
2024-02-17 14:22:02 -05:00
connection - > requests_count ? bsearch ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) : NULL ;
2023-08-20 15:55:59 -04:00
if ( existing )
{
assert ( ! existing - > callback ) ;
assert ( ! existing - > cleanup ) ;
assert ( ! existing - > user_data ) ;
assert ( ! existing - > dependent_connection ) ;
existing - > callback = callback ;
existing - > cleanup = cleanup ;
existing - > user_data = user_data ;
existing - > dependent_connection = dependent_connection ;
2022-07-11 21:51:15 -04:00
}
2023-08-20 15:55:59 -04:00
else
{
tf_ssb_connection_remove_request ( connection , request_number ) ;
2024-02-15 18:35:01 -05:00
tf_ssb_request_t request = {
2023-08-20 15:55:59 -04:00
. request_number = request_number ,
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. dependent_connection = dependent_connection ,
} ;
2024-05-02 19:02:23 -04:00
snprintf ( request . name , sizeof ( request . name ) , " %s " , name ) ;
2023-08-20 15:55:59 -04:00
int index = tf_util_insert_index ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) ;
connection - > requests = tf_resize_vec ( connection - > requests , sizeof ( tf_ssb_request_t ) * ( connection - > requests_count + 1 ) ) ;
if ( connection - > requests_count - index )
{
memmove ( connection - > requests + index + 1 , connection - > requests + index , sizeof ( tf_ssb_request_t ) * ( connection - > requests_count - index ) ) ;
}
connection - > requests [ index ] = request ;
connection - > requests_count + + ;
2022-07-11 21:51:15 -04:00
2023-08-20 15:55:59 -04:00
connection - > ssb - > request_count + + ;
}
2024-05-02 19:02:23 -04:00
_tf_ssb_notify_connections_changed ( connection - > ssb , k_tf_ssb_change_update , connection ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-08 12:45:15 -05:00
static int _message_request_compare ( const void * a , const void * b )
{
const char * author = a ;
const tf_ssb_connection_message_request_t * rb = b ;
return strcmp ( author , rb - > author ) ;
}
void tf_ssb_connection_add_new_message_request ( tf_ssb_connection_t * connection , const char * author , int32_t request_number , bool keys )
{
2024-02-15 18:35:01 -05:00
int index =
2024-02-17 14:22:02 -05:00
tf_util_insert_index ( author , connection - > message_requests , connection - > message_requests_count , sizeof ( tf_ssb_connection_message_request_t ) , _message_request_compare ) ;
2023-01-08 12:45:15 -05:00
if ( index < connection - > message_requests_count & & strcmp ( author , connection - > message_requests [ index ] . author ) = = 0 )
{
2023-01-08 15:01:35 -05:00
connection - > message_requests [ index ] . request_number = request_number ;
connection - > message_requests [ index ] . keys = keys ;
2023-01-08 12:45:15 -05:00
return ;
}
connection - > message_requests = tf_resize_vec ( connection - > message_requests , sizeof ( tf_ssb_connection_message_request_t ) * ( connection - > message_requests_count + 1 ) ) ;
if ( connection - > message_requests_count - index )
{
2024-02-15 18:35:01 -05:00
memmove ( connection - > message_requests + index + 1 , connection - > message_requests + index ,
2024-02-17 14:22:02 -05:00
sizeof ( tf_ssb_connection_message_request_t ) * ( connection - > message_requests_count - index ) ) ;
2023-01-08 12:45:15 -05:00
}
2024-02-15 18:35:01 -05:00
connection - > message_requests [ index ] = ( tf_ssb_connection_message_request_t ) {
2023-01-08 12:45:15 -05:00
. request_number = request_number ,
. keys = keys ,
} ;
snprintf ( connection - > message_requests [ index ] . author , sizeof ( connection - > message_requests [ index ] . author ) , " %s " , author ) ;
connection - > message_requests_count + + ;
}
2023-01-08 15:01:35 -05:00
void tf_ssb_connection_remove_new_message_request ( tf_ssb_connection_t * connection , const char * author )
{
2024-02-15 18:35:01 -05:00
int index =
2024-02-17 14:22:02 -05:00
tf_util_insert_index ( author , connection - > message_requests , connection - > message_requests_count , sizeof ( tf_ssb_connection_message_request_t ) , _message_request_compare ) ;
2023-01-08 15:01:35 -05:00
if ( index < connection - > message_requests_count & & strcmp ( author , connection - > message_requests [ index ] . author ) = = 0 )
{
2024-02-15 18:35:01 -05:00
memmove ( connection - > message_requests + index , connection - > message_requests + index + 1 ,
2024-02-17 14:22:02 -05:00
sizeof ( tf_ssb_connection_message_request_t ) * ( connection - > message_requests_count - index - 1 ) ) ;
2023-01-08 15:01:35 -05:00
connection - > message_requests_count - - ;
}
}
2023-01-18 18:43:49 -05:00
void tf_ssb_connection_remove_request ( tf_ssb_connection_t * connection , int32_t request_number )
2021-01-02 13:10:00 -05:00
{
2024-02-15 18:35:01 -05:00
tf_ssb_request_t * request =
2024-02-17 14:22:02 -05:00
connection - > requests_count ? bsearch ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) : NULL ;
2022-07-11 21:51:15 -04:00
if ( request )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
if ( request - > cleanup )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
request - > cleanup ( connection - > ssb , request - > user_data ) ;
2021-01-02 13:10:00 -05:00
}
2022-07-11 21:51:15 -04:00
int index = request - connection - > requests ;
memmove ( request , request + 1 , sizeof ( tf_ssb_request_t ) * ( connection - > requests_count - index - 1 ) ) ;
connection - > requests_count - - ;
connection - > requests = tf_resize_vec ( connection - > requests , sizeof ( tf_ssb_request_t ) * connection - > requests_count ) ;
connection - > ssb - > request_count - - ;
2024-05-02 19:02:23 -04:00
_tf_ssb_notify_connections_changed ( connection - > ssb , k_tf_ssb_change_update , connection ) ;
2021-01-02 13:10:00 -05:00
}
}
2024-05-02 20:10:56 -04:00
void tf_ssb_connection_rpc_send ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const char * new_request_name , const uint8_t * message , size_t size ,
tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2021-01-02 13:10:00 -05:00
{
2022-01-22 17:26:39 -05:00
if ( ! connection )
{
2023-02-14 21:34:46 -05:00
if ( cleanup )
{
cleanup ( NULL , user_data ) ;
}
2022-01-22 17:26:39 -05:00
return ;
}
2023-08-20 15:55:59 -04:00
if ( flags & k_ssb_rpc_flag_new_request )
{
assert ( request_number > 0 ) ;
assert ( ! _tf_ssb_connection_get_request_callback ( connection , request_number , NULL , NULL ) ) ;
2024-05-02 19:02:23 -04:00
assert ( new_request_name ) ;
2023-08-20 15:55:59 -04:00
}
else if ( ! _tf_ssb_connection_get_request_callback ( connection , request_number , NULL , NULL ) )
{
2024-05-08 21:00:37 -04:00
if ( flags & k_ssb_rpc_flag_binary )
{
tf_printf ( " Dropping message with no active request (%d): (%zd bytes). \n " , request_number , size ) ;
}
else
{
tf_printf ( " Dropping message with no active request (%d): %.*s \n " , request_number , ( int ) size , message ) ;
}
2023-08-20 15:55:59 -04:00
return ;
}
2022-06-04 13:04:51 -04:00
uint8_t * combined = tf_malloc ( 9 + size ) ;
2023-08-20 15:55:59 -04:00
* combined = flags & k_ssb_rpc_mask_send ;
2021-01-02 13:10:00 -05:00
uint32_t u32size = htonl ( ( uint32_t ) size ) ;
memcpy ( combined + 1 , & u32size , sizeof ( u32size ) ) ;
uint32_t rn = htonl ( ( uint32_t ) request_number ) ;
memcpy ( combined + 1 + sizeof ( uint32_t ) , & rn , sizeof ( rn ) ) ;
memcpy ( combined + 1 + 2 * sizeof ( uint32_t ) , message , size ) ;
2022-12-31 13:59:29 -05:00
if ( connection - > ssb - > verbose )
{
2024-02-17 14:22:02 -05:00
tf_printf ( MAGENTA " %s RPC SEND " RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] %.*s \n " , connection - > name , ( flags & k_ssb_rpc_flag_end_error ) ? " true " : " false " ,
( flags & k_ssb_rpc_flag_stream ) ? " true " : " false " , k_ssb_type_names [ flags & k_ssb_rpc_mask_type ] , request_number , size ,
( flags & k_ssb_rpc_mask_type ) = = k_ssb_rpc_flag_binary ? 0 : ( int ) size , message ) ;
2022-12-31 13:59:29 -05:00
}
2023-08-20 15:55:59 -04:00
_tf_ssb_connection_add_debug_message ( connection , true , flags & k_ssb_rpc_mask_send , request_number , message , size ) ;
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_box_stream_send ( connection , combined , 1 + 2 * sizeof ( uint32_t ) + size ) ;
2022-06-04 13:04:51 -04:00
tf_free ( combined ) ;
2022-02-05 15:18:58 -05:00
connection - > ssb - > rpc_out + + ;
2024-05-02 19:37:38 -04:00
if ( ( flags & k_ssb_rpc_flag_end_error ) | | ( request_number < 0 & & ! ( flags & k_ssb_rpc_flag_stream ) ) )
2023-02-14 21:34:46 -05:00
{
2023-08-20 15:55:59 -04:00
tf_ssb_connection_remove_request ( connection , request_number ) ;
2023-02-14 21:34:46 -05:00
}
2023-08-20 15:55:59 -04:00
else if ( flags & k_ssb_rpc_flag_new_request )
2023-02-14 21:34:46 -05:00
{
2024-05-02 19:02:23 -04:00
tf_ssb_connection_add_request ( connection , request_number , new_request_name , callback , cleanup , user_data , NULL ) ;
2023-02-14 21:34:46 -05:00
}
2021-01-02 13:10:00 -05:00
}
2024-05-02 20:10:56 -04:00
void tf_ssb_connection_rpc_send_json ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const char * new_request_name , JSValue message ,
tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2023-01-07 19:25:38 -05:00
{
JSContext * context = connection - > ssb - > context ;
JSValue json = JS_JSONStringify ( context , message , JS_NULL , JS_NULL ) ;
size_t size = 0 ;
const char * json_string = JS_ToCStringLen ( context , & size , json ) ;
2024-05-02 20:10:56 -04:00
tf_ssb_connection_rpc_send (
connection , k_ssb_rpc_flag_json | ( flags & ~ k_ssb_rpc_mask_type ) , request_number , new_request_name , ( const uint8_t * ) json_string , size , callback , cleanup , user_data ) ;
2023-01-07 19:25:38 -05:00
JS_FreeCString ( context , json_string ) ;
JS_FreeValue ( context , json ) ;
}
void tf_ssb_connection_rpc_send_error ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const char * error )
{
JSContext * context = connection - > ssb - > context ;
JSValue message = JS_NewObject ( context ) ;
2023-02-18 16:00:39 -05:00
const char * stack = tf_util_backtrace_string ( ) ;
2023-01-07 19:25:38 -05:00
JS_SetPropertyStr ( context , message , " name " , JS_NewString ( context , " Error " ) ) ;
2023-08-04 23:10:24 -04:00
JS_SetPropertyStr ( context , message , " stack " , JS_NewString ( context , stack ? stack : " stack unavailable " ) ) ;
2023-01-07 19:25:38 -05:00
JS_SetPropertyStr ( context , message , " message " , JS_NewString ( context , error ) ) ;
2024-02-15 18:35:01 -05:00
tf_ssb_connection_rpc_send_json (
2024-05-02 19:02:23 -04:00
connection , ( ( flags & k_ssb_rpc_flag_stream ) ? ( k_ssb_rpc_flag_stream ) : 0 ) | k_ssb_rpc_flag_end_error , request_number , NULL , message , NULL , NULL , NULL ) ;
2023-01-07 19:25:38 -05:00
JS_FreeValue ( context , message ) ;
2023-02-18 16:00:39 -05:00
tf_free ( ( void * ) stack ) ;
2023-01-07 19:25:38 -05:00
}
2023-05-23 18:16:07 -04:00
void tf_ssb_connection_rpc_send_error_method_not_allowed ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const char * name )
2023-01-07 19:25:38 -05:00
{
2023-05-23 18:16:07 -04:00
char buffer [ 1024 ] ;
snprintf ( buffer , sizeof ( buffer ) , " method '%s' is not in list of allowed methods " , name ) ;
tf_ssb_connection_rpc_send_error ( connection , flags , request_number , buffer ) ;
2023-01-07 19:25:38 -05:00
}
2022-02-09 22:58:33 -05:00
static int _utf8_len ( uint8_t ch )
{
2024-02-15 18:35:01 -05:00
static const uint8_t k_length [ ] = { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 2 , 2 , 3 , 4 } ;
2022-02-09 22:58:33 -05:00
return k_length [ ( ch & 0xf0 ) > > 4 ] ;
}
static uint32_t _utf8_decode ( uint32_t c )
{
if ( c > 0x7f )
{
uint32_t mask = ( c < = 0x00efbfbf ) ? 0x000f0000 : 0x003f0000 ;
2024-02-15 18:35:01 -05:00
c = ( ( c & 0x07000000 ) > > 6 ) | ( ( c & mask ) > > 4 ) | ( ( c & 0x00003f00 ) > > 2 ) | ( c & 0x0000003f ) ;
2022-02-09 22:58:33 -05:00
}
return c ;
}
static const uint8_t * _utf8_to_cp ( const uint8_t * ch , uint32_t * out_cp )
{
int len = _utf8_len ( * ch ) ;
int actual_len = 0 ;
uint32_t encoding = 0 ;
for ( int i = 0 ; i < len & & ch [ i ] ; i + + , actual_len + + )
{
encoding = ( encoding < < 8 ) | ch [ i ] ;
}
* out_cp = _utf8_decode ( encoding ) ;
return ch + actual_len ;
}
2022-02-10 21:44:27 -05:00
static uint32_t _cp_to_utf16 ( uint32_t cp , uint16_t * out_h , uint16_t * out_l )
{
if ( cp < 0x10000 )
{
* out_h = 0 ;
* out_l = cp & 0xffff ;
return cp ;
}
else
{
uint32_t t = cp - 0x10000 ;
uint32_t h = ( ( t < < 12 ) > > 22 ) + 0xd800 ;
uint32_t l = ( ( t < < 22 ) > > 22 ) + 0xdc00 ;
* out_h = h & 0xffff ;
* out_l = l & 0xffff ;
return ( h < < 16 ) | ( l & 0xffff ) ;
}
}
2021-01-02 13:10:00 -05:00
void tf_ssb_calculate_message_id ( JSContext * context , JSValue message , char * out_id , size_t out_id_size )
{
JSValue idval = JS_JSONStringify ( context , message , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
size_t len = 0 ;
const char * messagestr = JS_ToCStringLen ( context , & len , idval ) ;
2023-01-13 19:55:51 -05:00
if ( ! messagestr )
{
memset ( out_id , 0 , out_id_size ) ;
JS_FreeValue ( context , idval ) ;
return ;
}
2022-02-09 22:58:33 -05:00
2022-06-04 13:04:51 -04:00
char * latin1 = tf_strdup ( messagestr ) ;
2022-02-09 22:58:33 -05:00
uint8_t * write_pos = ( uint8_t * ) latin1 ;
const uint8_t * p = ( const uint8_t * ) messagestr ;
while ( p & & * p )
{
uint32_t cp = 0 ;
p = _utf8_to_cp ( p , & cp ) ;
2022-02-10 21:44:27 -05:00
uint16_t h = 0 ;
uint16_t l = 0 ;
_cp_to_utf16 ( cp , & h , & l ) ;
if ( h )
{
* write_pos + + = h & 0xff ;
}
if ( l )
{
* write_pos + + = l & 0xff ;
}
2022-02-09 22:58:33 -05:00
}
size_t latin1_len = write_pos - ( uint8_t * ) latin1 ;
* write_pos + + = ' \0 ' ;
2021-01-02 13:10:00 -05:00
uint8_t id [ crypto_hash_sha256_BYTES ] ;
2022-02-09 22:58:33 -05:00
crypto_hash_sha256 ( id , ( uint8_t * ) latin1 , latin1_len ) ;
2021-01-02 13:10:00 -05:00
char id_base64 [ k_id_base64_len ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( id , sizeof ( id ) , id_base64 , sizeof ( id_base64 ) ) ;
2021-01-02 13:10:00 -05:00
snprintf ( out_id , out_id_size , " %%%s.sha256 " , id_base64 ) ;
2022-06-04 13:04:51 -04:00
tf_free ( latin1 ) ;
2021-01-02 13:10:00 -05:00
JS_FreeCString ( context , messagestr ) ;
JS_FreeValue ( context , idval ) ;
}
2022-02-09 22:58:33 -05:00
static bool _tf_ssb_verify_and_strip_signature_internal ( JSContext * context , JSValue val , char * out_id , size_t out_id_size , char * out_signature , size_t out_signature_size )
2021-01-02 13:10:00 -05:00
{
JSValue signature = JS_GetPropertyStr ( context , val , " signature " ) ;
2023-01-13 19:55:51 -05:00
if ( JS_IsUndefined ( signature ) )
{
memset ( out_signature , 0 , out_signature_size ) ;
return false ;
}
2021-01-02 13:10:00 -05:00
const char * str = JS_ToCString ( context , signature ) ;
2023-01-13 19:55:51 -05:00
if ( ! str )
{
JS_FreeValue ( context , signature ) ;
memset ( out_signature , 0 , out_signature_size ) ;
return false ;
}
bool verified = false ;
tf_ssb_calculate_message_id ( context , val , out_id , out_id_size ) ;
2021-01-02 13:10:00 -05:00
JSAtom sigatom = JS_NewAtom ( context , " signature " ) ;
JS_DeleteProperty ( context , val , sigatom , 0 ) ;
JS_FreeAtom ( context , sigatom ) ;
2021-10-10 17:51:38 -04:00
if ( out_signature )
{
2021-01-02 13:10:00 -05:00
memset ( out_signature , 0 , out_signature_size ) ;
strncpy ( out_signature , str , out_signature_size - 1 ) ;
}
JSValue sigval = JS_JSONStringify ( context , val , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
const char * sigstr = JS_ToCString ( context , sigval ) ;
const char * sigkind = strstr ( str , " .sig.ed25519 " ) ;
JSValue authorval = JS_GetPropertyStr ( context , val , " author " ) ;
const char * author = JS_ToCString ( context , authorval ) ;
const char * author_id = author & & * author = = ' @ ' ? author + 1 : author ;
const char * type = strstr ( author_id , " .ed25519 " ) ;
uint8_t publickey [ crypto_box_PUBLICKEYBYTES ] ;
2023-02-13 22:15:24 -05:00
int r = tf_base64_decode ( author_id , type - author_id , publickey , sizeof ( publickey ) ) ;
2021-10-10 17:51:38 -04:00
if ( r ! = - 1 )
{
2021-01-02 13:10:00 -05:00
uint8_t binsig [ crypto_sign_BYTES ] ;
2023-02-13 22:15:24 -05:00
r = tf_base64_decode ( str , sigkind - str , binsig , sizeof ( binsig ) ) ;
2021-10-10 17:51:38 -04:00
if ( r ! = - 1 )
{
2021-01-02 13:10:00 -05:00
r = crypto_sign_verify_detached ( binsig , ( const uint8_t * ) sigstr , strlen ( sigstr ) , publickey ) ;
verified = r = = 0 ;
2021-10-10 17:51:38 -04:00
if ( ! verified )
{
2024-02-15 18:35:01 -05:00
// tf_printf("crypto_sign_verify_detached fail (r=%d)\n", r);
2023-05-09 21:47:20 -04:00
if ( false )
2021-12-27 17:00:37 -05:00
{
2023-03-07 12:50:17 -05:00
tf_printf ( " val=[%.*s] \n " , ( int ) strlen ( sigstr ) , sigstr ) ;
tf_printf ( " sig=%.*s \n " , ( int ) ( sigkind - str ) , str ) ;
tf_printf ( " public key=%.*s \n " , ( int ) ( type - author_id ) , author_id ) ;
2021-12-27 17:00:37 -05:00
}
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2023-03-07 12:50:17 -05:00
tf_printf ( " base64 decode sig fail [%.*s] \n " , ( int ) ( sigkind - str ) , str ) ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2023-03-07 12:50:17 -05:00
tf_printf ( " base64 decode author[%.*s] fail (%d) \n " , ( int ) ( type - author_id ) , author_id , r ) ;
2021-01-02 13:10:00 -05:00
}
JS_FreeCString ( context , author ) ;
JS_FreeCString ( context , sigstr ) ;
JS_FreeCString ( context , str ) ;
JS_FreeValue ( context , sigval ) ;
JS_FreeValue ( context , authorval ) ;
2022-02-02 21:38:05 -05:00
if ( verified )
{
JS_FreeValue ( context , signature ) ;
}
else
{
JS_SetPropertyStr ( context , val , " signature " , signature ) ;
}
2021-01-02 13:10:00 -05:00
return verified ;
}
2024-03-13 19:40:09 -04:00
bool tf_ssb_verify_and_strip_signature ( JSContext * context , JSValue val , char * out_id , size_t out_id_size , char * out_signature , size_t out_signature_size , int * out_flags )
2022-02-02 21:00:05 -05:00
{
2024-05-11 08:48:50 -04:00
JSValue reordered = JS_NewObject ( context ) ;
JS_SetPropertyStr ( context , reordered , " previous " , JS_GetPropertyStr ( context , val , " previous " ) ) ;
JS_SetPropertyStr ( context , reordered , " author " , JS_GetPropertyStr ( context , val , " author " ) ) ;
JS_SetPropertyStr ( context , reordered , " sequence " , JS_GetPropertyStr ( context , val , " sequence " ) ) ;
JS_SetPropertyStr ( context , reordered , " timestamp " , JS_GetPropertyStr ( context , val , " timestamp " ) ) ;
JS_SetPropertyStr ( context , reordered , " hash " , JS_GetPropertyStr ( context , val , " hash " ) ) ;
JS_SetPropertyStr ( context , reordered , " content " , JS_GetPropertyStr ( context , val , " content " ) ) ;
JS_SetPropertyStr ( context , reordered , " signature " , JS_GetPropertyStr ( context , val , " signature " ) ) ;
bool result = _tf_ssb_verify_and_strip_signature_internal ( context , reordered , out_id , out_id_size , out_signature , out_signature_size ) ;
JS_FreeValue ( context , reordered ) ;
if ( result )
2022-02-02 21:00:05 -05:00
{
2024-03-13 19:40:09 -04:00
if ( out_flags )
2022-02-02 21:00:05 -05:00
{
2024-03-13 19:40:09 -04:00
* out_flags = 0 ;
2022-02-02 21:00:05 -05:00
}
return true ;
}
2024-05-11 08:48:50 -04:00
reordered = JS_NewObject ( context ) ;
JS_SetPropertyStr ( context , reordered , " previous " , JS_GetPropertyStr ( context , val , " previous " ) ) ;
JS_SetPropertyStr ( context , reordered , " sequence " , JS_GetPropertyStr ( context , val , " sequence " ) ) ;
JS_SetPropertyStr ( context , reordered , " author " , JS_GetPropertyStr ( context , val , " author " ) ) ;
JS_SetPropertyStr ( context , reordered , " timestamp " , JS_GetPropertyStr ( context , val , " timestamp " ) ) ;
JS_SetPropertyStr ( context , reordered , " hash " , JS_GetPropertyStr ( context , val , " hash " ) ) ;
JS_SetPropertyStr ( context , reordered , " content " , JS_GetPropertyStr ( context , val , " content " ) ) ;
JS_SetPropertyStr ( context , reordered , " signature " , JS_GetPropertyStr ( context , val , " signature " ) ) ;
result = _tf_ssb_verify_and_strip_signature_internal ( context , reordered , out_id , out_id_size , out_signature , out_signature_size ) ;
JS_FreeValue ( context , reordered ) ;
if ( result )
2022-02-02 21:00:05 -05:00
{
2024-05-11 08:48:50 -04:00
if ( out_flags )
2022-02-02 21:00:05 -05:00
{
2024-05-11 08:48:50 -04:00
* out_flags = k_tf_ssb_message_flag_sequence_before_author ;
2022-02-02 21:00:05 -05:00
}
2024-05-11 08:48:50 -04:00
return true ;
2022-02-02 21:00:05 -05:00
}
2024-05-11 08:48:50 -04:00
2022-02-02 21:00:05 -05:00
return false ;
}
2023-01-07 19:44:36 -05:00
void tf_ssb_close_all ( tf_ssb_t * ssb )
{
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
_tf_ssb_connection_close ( connection , " tf_ssb_close_all " ) ;
}
}
2021-01-02 13:10:00 -05:00
void tf_ssb_send_close ( tf_ssb_t * ssb )
{
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_send_close ( connection ) ;
}
}
bool tf_ssb_id_bin_to_str ( char * str , size_t str_size , const uint8_t * bin )
{
char buffer [ k_id_base64_len - 9 ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( bin , crypto_sign_PUBLICKEYBYTES , buffer , sizeof ( buffer ) ) ;
2021-01-02 13:10:00 -05:00
return snprintf ( str , str_size , " @%s.ed25519 " , buffer ) < ( int ) str_size ;
}
bool tf_ssb_id_str_to_bin ( uint8_t * bin , const char * str )
{
const char * author_id = str & & * str = = ' @ ' ? str + 1 : str ;
2023-08-25 16:57:55 -04:00
const char * type = str ? strstr ( str , " .ed25519 " ) : NULL ;
return author_id & & type ? tf_base64_decode ( author_id , type - author_id , bin , crypto_box_PUBLICKEYBYTES ) ! = 0 : false ;
2021-01-02 13:10:00 -05:00
}
2023-04-19 19:05:59 -04:00
static uint64_t _tf_ssb_callback_pre ( tf_ssb_t * ssb )
{
return uv_hrtime ( ) ;
}
static void _tf_ssb_callback_post ( tf_ssb_t * ssb , void * callback , uint64_t pre )
{
if ( ssb - > hitch_callback )
{
uint64_t post = uv_hrtime ( ) ;
const char * name = tf_util_function_to_string ( callback ) ;
ssb - > hitch_callback ( name , post - pre , ssb - > hitch_user_data ) ;
tf_free ( ( void * ) name ) ;
}
}
2021-11-07 17:28:58 -05:00
static void _tf_ssb_notify_connections_changed ( tf_ssb_t * ssb , tf_ssb_change_t change , tf_ssb_connection_t * connection )
{
2021-12-27 17:28:27 -05:00
tf_ssb_connections_changed_callback_node_t * next = NULL ;
for ( tf_ssb_connections_changed_callback_node_t * node = ssb - > connections_changed ; node ; node = next )
2021-11-07 17:28:58 -05:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " connections_changed " ) ;
2023-04-19 19:05:59 -04:00
PRE_CALLBACK ( ssb , node - > callback ) ;
2021-11-07 17:28:58 -05:00
node - > callback ( ssb , change , connection , node - > user_data ) ;
2023-04-19 19:05:59 -04:00
POST_CALLBACK ( ssb , node - > callback ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-11-07 17:28:58 -05:00
}
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_verify_identity ( tf_ssb_connection_t * connection , const uint8_t * message , size_t len )
{
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] = { 0 } ;
uint8_t shared_secret_ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_ab , connection - > epriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_ab " ) ;
return ;
}
uint8_t servercurvepub [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_pk_to_curve25519 ( servercurvepub , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
uint8_t shared_secret_aB [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_aB , connection - > epriv , servercurvepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_aB " ) ;
return ;
}
uint8_t clientcurvepriv [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_sk_to_curve25519 ( clientcurvepriv , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
uint8_t shared_secret_Ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_Ab , clientcurvepriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_Ab " ) ;
return ;
}
2024-03-02 15:01:09 -05:00
uint8_t tohash [ sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) + sizeof ( shared_secret_Ab ) ] ;
memcpy ( tohash , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) , shared_secret_Ab , sizeof ( shared_secret_Ab ) ) ;
2021-01-02 13:10:00 -05:00
uint8_t hash2 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash2 , tohash , sizeof ( tohash ) ) ;
uint8_t hash3a [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3a , hash2 , sizeof ( hash2 ) ) ;
memcpy ( hash3a + crypto_hash_sha256_BYTES , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
crypto_hash_sha256 ( connection - > s_to_c_box_key , hash3a , sizeof ( hash3a ) ) ;
uint8_t hash3b [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3b , hash2 , sizeof ( hash2 ) ) ;
memcpy ( hash3b + crypto_hash_sha256_BYTES , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
crypto_hash_sha256 ( connection - > c_to_s_box_key , hash3b , sizeof ( hash3b ) ) ;
uint8_t m [ 80 ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_open_easy ( m , message , len , nonce , hash2 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to open initial secret box as client " ) ;
return ;
}
uint8_t hash3 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash3 , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
2024-03-02 15:01:09 -05:00
uint8_t msg [ sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > detached_signature_A ) + sizeof ( connection - > ssb - > pub ) + sizeof ( hash3 ) ] ;
memcpy ( msg , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) , connection - > detached_signature_A , sizeof ( connection - > detached_signature_A ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > detached_signature_A ) , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > detached_signature_A ) + sizeof ( connection - > ssb - > pub ) , hash3 , sizeof ( hash3 ) ) ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_verify_detached ( m , msg , sizeof ( msg ) , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to verify server identity " ) ;
return ;
}
uint8_t nonce2 [ crypto_auth_hmacsha512256_BYTES ] ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256 ( nonce2 , connection - > epub , sizeof ( connection - > epub ) , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute client recv nonce " ) ;
return ;
}
memcpy ( connection - > nonce , nonce2 , sizeof ( connection - > nonce ) ) ;
uint8_t nonce3 [ crypto_auth_hmacsha512256_BYTES ] ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256 ( nonce3 , connection - > serverepub , sizeof ( connection - > serverepub ) , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute client send nonce " ) ;
return ;
}
memcpy ( connection - > send_nonce , nonce3 , sizeof ( connection - > send_nonce ) ) ;
char fullid [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( fullid , sizeof ( fullid ) , connection - > serverpub ) ;
2021-09-06 17:21:51 -04:00
JSContext * context = connection - > ssb - > context ;
JS_SetPropertyStr ( context , connection - > object , " id " , JS_NewString ( context , fullid ) ) ;
2021-12-27 14:52:42 -05:00
JS_SetPropertyStr ( context , connection - > object , " is_client " , JS_TRUE ) ;
2021-09-06 17:21:51 -04:00
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_verified ;
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_connections_changed ( connection - > ssb , k_tf_ssb_change_connect , connection ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-07 19:25:38 -05:00
bool tf_ssb_connection_is_client ( tf_ssb_connection_t * connection )
{
return connection - > state = = k_tf_ssb_state_verified ;
}
2023-01-16 21:17:29 -05:00
bool tf_ssb_connection_is_connected ( tf_ssb_connection_t * connection )
{
2024-02-15 18:35:01 -05:00
return connection - > state = = k_tf_ssb_state_verified | | connection - > state = = k_tf_ssb_state_server_verified ;
2023-01-16 21:17:29 -05:00
}
2021-01-02 13:10:00 -05:00
const char * tf_ssb_connection_get_host ( tf_ssb_connection_t * connection )
{
return connection - > host ;
}
int tf_ssb_connection_get_port ( tf_ssb_connection_t * connection )
{
return connection - > port ;
}
bool tf_ssb_connection_get_id ( tf_ssb_connection_t * connection , char * out_id , size_t out_id_size )
{
2024-02-15 18:35:01 -05:00
return connection & & memcmp ( connection - > serverpub , ( uint8_t [ k_id_bin_len ] ) { 0 } , k_id_bin_len ) ! = 0 & & tf_ssb_id_bin_to_str ( out_id , out_id_size , connection - > serverpub ) ;
2021-01-02 13:10:00 -05:00
}
2023-08-25 14:22:09 -04:00
tf_ssb_connection_t * tf_ssb_connection_get_tunnel ( tf_ssb_connection_t * connection )
{
return connection ? connection - > tunnel_connection : NULL ;
}
2022-11-02 19:34:44 -04:00
static bool _tf_ssb_is_already_connected ( tf_ssb_t * ssb , uint8_t * id , tf_ssb_connection_t * ignore_connection )
2021-01-19 21:01:14 -05:00
{
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2022-11-02 19:34:44 -04:00
if ( ! ignore_connection | | connection ! = ignore_connection )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
if ( memcmp ( connection - > serverpub , id , k_id_bin_len ) = = 0 )
{
return true ;
}
else if ( memcmp ( ssb - > pub , id , k_id_bin_len ) = = 0 )
{
return true ;
}
2021-01-19 21:01:14 -05:00
}
}
return false ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_verify_client_identity ( tf_ssb_connection_t * connection , const uint8_t * message , size_t len )
{
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] = { 0 } ;
/*
* * shared_secret_ab = nacl_scalarmult (
* * server_ephemeral_sk ,
* * client_ephemeral_pk
* * )
*/
uint8_t shared_secret_ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_ab , connection - > epriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_ab " ) ;
return ;
}
/*
* * shared_secret_aB = nacl_scalarmult (
* * sk_to_curve25519 ( server_longterm_sk ) ,
* * client_ephemeral_pk
* * )
*/
uint8_t curvepriv [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_sk_to_curve25519 ( curvepriv , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
static_assert ( sizeof ( connection - > ssb - > priv ) = = crypto_sign_ed25519_SECRETKEYBYTES , " size " ) ;
uint8_t shared_secret_aB [ crypto_scalarmult_curve25519_SCALARBYTES ] = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult ( shared_secret_aB , curvepriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_aB " ) ;
return ;
}
2024-03-02 15:01:09 -05:00
static_assert ( sizeof ( connection - > ssb - > network_key ) = = crypto_auth_KEYBYTES , " network key size " ) ;
uint8_t tohash [ sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) ] ;
memcpy ( tohash , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( tohash + sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
2021-01-02 13:10:00 -05:00
uint8_t hash2 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash2 , tohash , sizeof ( tohash ) ) ;
/*
* * msg3_plaintext = assert_nacl_secretbox_open (
* * ciphertext : msg3 ,
* * nonce : 24 _bytes_of_zeros ,
* * key : sha256 (
* * concat (
* * network_identifier ,
* * shared_secret_ab ,
* * shared_secret_aB
* * )
* * )
* * )
*/
uint8_t m [ 96 ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_open_easy ( m , message , len , nonce , hash2 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to open initial secret box as server " ) ;
return ;
}
uint8_t * detached_signature_A = m ;
2022-11-02 19:34:44 -04:00
if ( _tf_ssb_is_already_connected ( connection - > ssb , m + 64 , connection ) )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
char id_base64 [ k_id_base64_len ] = { 0 } ;
tf_ssb_id_bin_to_str ( id_base64 , sizeof ( id_base64 ) , m + 64 ) ;
char reason [ 256 ] ;
snprintf ( reason , sizeof ( reason ) , " already connected: %s \n " , id_base64 ) ;
_tf_ssb_connection_close ( connection , reason ) ;
2021-01-19 21:01:14 -05:00
return ;
}
2021-01-02 13:10:00 -05:00
memcpy ( connection - > serverpub , m + 64 , sizeof ( connection - > serverpub ) ) ;
uint8_t hash3 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash3 , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
2024-03-02 15:01:09 -05:00
uint8_t msg [ sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > ssb - > pub ) + sizeof ( hash3 ) ] ;
memcpy ( msg , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
memcpy ( msg + sizeof ( connection - > ssb - > network_key ) + sizeof ( connection - > ssb - > pub ) , hash3 , sizeof ( hash3 ) ) ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_verify_detached ( detached_signature_A , msg , sizeof ( msg ) , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to verify client identity " ) ;
return ;
}
uint8_t nonce2 [ crypto_auth_hmacsha512256_BYTES ] ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256 ( nonce2 , connection - > epub , sizeof ( connection - > epub ) , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute initial recv nonce as server " ) ;
return ;
}
memcpy ( connection - > nonce , nonce2 , sizeof ( connection - > nonce ) ) ;
uint8_t nonce3 [ crypto_auth_hmacsha512256_BYTES ] ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256 ( nonce3 , connection - > serverepub , sizeof ( connection - > serverepub ) , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute initial send nonce as server " ) ;
return ;
}
memcpy ( connection - > send_nonce , nonce3 , sizeof ( connection - > send_nonce ) ) ;
int detached_signature_A_size = 64 ;
2024-03-02 15:01:09 -05:00
uint8_t sign_b [ sizeof ( connection - > ssb - > network_key ) + detached_signature_A_size + sizeof ( connection - > serverpub ) + sizeof ( hash3 ) ] ;
memcpy ( sign_b , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( sign_b + sizeof ( connection - > ssb - > network_key ) , detached_signature_A , detached_signature_A_size ) ;
memcpy ( sign_b + sizeof ( connection - > ssb - > network_key ) + detached_signature_A_size , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
memcpy ( sign_b + sizeof ( connection - > ssb - > network_key ) + detached_signature_A_size + sizeof ( connection - > serverpub ) , hash3 , sizeof ( hash3 ) ) ;
2021-01-02 13:10:00 -05:00
uint8_t detached_signature_B [ crypto_sign_BYTES ] ;
unsigned long long siglen ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_detached ( detached_signature_B , & siglen , sign_b , sizeof ( sign_b ) , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute detached_signature_B as server " ) ;
return ;
}
uint8_t clientcurvepub [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_pk_to_curve25519 ( clientcurvepub , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
uint8_t shared_secret_Ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_Ab , connection - > epriv , clientcurvepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_Ab as server " ) ;
return ;
}
2024-03-02 15:01:09 -05:00
uint8_t key_buf [ sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) + sizeof ( shared_secret_Ab ) ] ;
memcpy ( key_buf , connection - > ssb - > network_key , sizeof ( connection - > ssb - > network_key ) ) ;
memcpy ( key_buf + sizeof ( connection - > ssb - > network_key ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( key_buf + sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
memcpy ( key_buf + sizeof ( connection - > ssb - > network_key ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) , shared_secret_Ab , sizeof ( shared_secret_Ab ) ) ;
2021-01-02 13:10:00 -05:00
uint8_t key_hash [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( key_hash , key_buf , sizeof ( key_buf ) ) ;
uint8_t hash3a [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3a , key_hash , sizeof ( key_hash ) ) ;
memcpy ( hash3a + crypto_hash_sha256_BYTES , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
crypto_hash_sha256 ( connection - > s_to_c_box_key , hash3a , sizeof ( hash3a ) ) ;
uint8_t hash3b [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3b , key_hash , sizeof ( key_hash ) ) ;
memcpy ( hash3b + crypto_hash_sha256_BYTES , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
crypto_hash_sha256 ( connection - > c_to_s_box_key , hash3b , sizeof ( hash3b ) ) ;
uint8_t c [ crypto_secretbox_MACBYTES + sizeof ( detached_signature_B ) ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_easy ( c , detached_signature_B , sizeof ( detached_signature_B ) , nonce , key_hash ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to create initial secret box as server " ) ;
return ;
}
static_assert ( sizeof ( c ) = = 80 , " server send size " ) ;
_tf_ssb_write ( connection , c , sizeof ( c ) ) ;
2021-09-06 17:21:51 -04:00
char fullid [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( fullid , sizeof ( fullid ) , connection - > serverpub ) ;
JSContext * context = connection - > ssb - > context ;
JS_SetPropertyStr ( context , connection - > object , " id " , JS_NewString ( context , fullid ) ) ;
2021-12-27 14:52:42 -05:00
JS_SetPropertyStr ( context , connection - > object , " is_client " , JS_FALSE ) ;
2021-09-06 17:21:51 -04:00
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_server_verified ;
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_connections_changed ( connection - > ssb , k_tf_ssb_change_connect , connection ) ;
2021-01-02 13:10:00 -05:00
}
static bool _tf_ssb_connection_recv_pop ( tf_ssb_connection_t * connection , uint8_t * buffer , size_t size )
{
2023-01-01 17:42:31 -05:00
if ( size > = sizeof ( connection - > recv_buffer ) )
{
char message [ 256 ] ;
snprintf ( message , sizeof ( message ) , " Trying to pop a message (%zd) larger than the connection's receive buffer (%zd). " , size , sizeof ( connection - > recv_buffer ) ) ;
_tf_ssb_connection_close ( connection , message ) ;
}
2021-10-10 17:51:38 -04:00
if ( connection - > recv_size < size )
{
2021-01-02 13:10:00 -05:00
return false ;
}
memcpy ( buffer , connection - > recv_buffer , size ) ;
2021-10-10 17:51:38 -04:00
if ( connection - > recv_size - size )
{
2021-01-02 13:10:00 -05:00
memmove ( connection - > recv_buffer , connection - > recv_buffer + size , connection - > recv_size - size ) ;
}
connection - > recv_size - = size ;
return true ;
}
static bool _tf_ssb_name_equals ( JSContext * context , JSValue object , const char * * match )
{
bool result = true ;
JSValue name = JS_GetPropertyStr ( context , object , " name " ) ;
2021-10-10 17:51:38 -04:00
if ( JS_IsArray ( context , name ) )
{
2022-07-09 11:13:35 -04:00
int length = tf_util_get_length ( context , name ) ;
for ( int i = 0 ; i < length ; i + + )
2021-10-10 17:51:38 -04:00
{
2022-07-09 11:13:35 -04:00
if ( ! match [ i ] )
2021-10-10 17:51:38 -04:00
{
2022-07-09 11:13:35 -04:00
result = false ;
break ;
2021-01-02 13:10:00 -05:00
}
2022-07-09 11:13:35 -04:00
JSValue element = JS_GetPropertyUint32 ( context , name , i ) ;
const char * str = JS_ToCString ( context , element ) ;
if ( ! str | | strcmp ( str , match [ i ] ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
result = false ;
}
2022-07-09 11:13:35 -04:00
JS_FreeCString ( context , str ) ;
JS_FreeValue ( context , element ) ;
}
if ( result & & match [ length ] )
{
result = false ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
2022-11-11 21:00:49 -05:00
else if ( JS_IsString ( name ) )
{
/* Manifest is traditionally sent as not an array for some reason. */
const char * str = JS_ToCString ( context , name ) ;
result = str & & match [ 0 ] & & strcmp ( str , match [ 0 ] ) = = 0 & & ! match [ 1 ] ;
JS_FreeCString ( context , str ) ;
}
2021-10-10 17:51:38 -04:00
else
{
2021-01-02 13:10:00 -05:00
result = false ;
}
JS_FreeValue ( context , name ) ;
return result ;
}
2023-05-23 18:16:07 -04:00
static void _tf_ssb_name_to_string ( JSContext * context , JSValue object , char * buffer , size_t size )
{
JSValue name = JS_GetPropertyStr ( context , object , " name " ) ;
JSValue json_val = JS_JSONStringify ( context , name , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
const char * value = JS_ToCString ( context , json_val ) ;
snprintf ( buffer , size , " %s " , value ) ;
JS_FreeCString ( context , value ) ;
JS_FreeValue ( context , json_val ) ;
JS_FreeValue ( context , name ) ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_rpc_recv ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const uint8_t * message , size_t size )
{
2022-02-05 15:18:58 -05:00
connection - > ssb - > rpc_in + + ;
2023-01-22 15:37:19 -05:00
_tf_ssb_connection_add_debug_message ( connection , false , flags , request_number , message , size ) ;
2023-08-20 15:55:59 -04:00
bool close_connection = false ;
2022-11-02 19:34:44 -04:00
if ( size = = 0 )
{
2023-01-10 20:43:35 -05:00
_tf_ssb_connection_close ( connection , " rpc recv zero " ) ;
2022-11-02 19:34:44 -04:00
return ;
}
else if ( flags & k_ssb_rpc_flag_json )
2021-10-10 17:51:38 -04:00
{
2022-02-05 22:28:29 -05:00
char id [ k_id_base64_len ] = " " ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , connection - > serverpub ) ;
2022-12-31 13:59:29 -05:00
if ( connection - > ssb - > verbose )
{
2024-02-17 14:22:02 -05:00
tf_printf ( CYAN " %s RPC RECV " RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] %.*s \n " , connection - > name , ( flags & k_ssb_rpc_flag_end_error ) ? " true " : " false " ,
( flags & k_ssb_rpc_flag_stream ) ? " true " : " false " , k_ssb_type_names [ flags & k_ssb_rpc_mask_type ] , request_number , size , ( int ) size , message ) ;
2022-12-31 13:59:29 -05:00
}
2021-01-02 13:10:00 -05:00
JSContext * context = connection - > ssb - > context ;
JSValue val = JS_ParseJSON ( context , ( const char * ) message , size , NULL ) ;
2021-12-22 14:57:34 -05:00
if ( ! JS_IsUndefined ( val ) )
2021-10-10 17:51:38 -04:00
{
2023-08-20 15:55:59 -04:00
tf_ssb_rpc_callback_t * callback = NULL ;
void * user_data = NULL ;
if ( _tf_ssb_connection_get_request_callback ( connection , - request_number , & callback , & user_data ) )
2021-10-10 17:51:38 -04:00
{
2023-08-20 15:55:59 -04:00
if ( callback )
{
char buffer [ 64 ] ;
snprintf ( buffer , sizeof ( buffer ) , " request %d " , request_number ) ;
tf_trace_begin ( connection - > ssb - > trace , buffer ) ;
PRE_CALLBACK ( connection - > ssb , callback ) ;
callback ( connection , flags , request_number , val , message , size , user_data ) ;
POST_CALLBACK ( connection - > ssb , callback ) ;
tf_trace_end ( connection - > ssb - > trace ) ;
2024-05-02 19:37:38 -04:00
if ( ! ( flags & k_ssb_rpc_flag_stream ) )
{
tf_ssb_connection_remove_request ( connection , - request_number ) ;
}
2023-08-20 15:55:59 -04:00
}
}
else if ( JS_IsObject ( val ) )
{
bool found = false ;
2024-05-02 19:02:23 -04:00
char namebuf [ 256 ] = " " ;
JSValue name = JS_GetPropertyStr ( context , val , " name " ) ;
if ( JS_IsArray ( context , name ) )
{
int length = tf_util_get_length ( context , name ) ;
int offset = 0 ;
for ( int i = 0 ; i < length ; i + + )
{
JSValue part = JS_GetPropertyUint32 ( context , name , i ) ;
const char * part_str = JS_ToCString ( context , part ) ;
offset + = snprintf ( namebuf + offset , sizeof ( namebuf ) - offset , " %s%s " , i = = 0 ? " " : " . " , part_str ) ;
JS_FreeCString ( context , part_str ) ;
JS_FreeValue ( context , part ) ;
}
}
else if ( JS_IsString ( name ) )
{
const char * part_str = JS_ToCString ( context , name ) ;
snprintf ( namebuf , sizeof ( namebuf ) , " %s " , part_str ) ;
JS_FreeCString ( context , part_str ) ;
}
JS_FreeValue ( context , name ) ;
2021-12-22 14:57:34 -05:00
for ( tf_ssb_rpc_callback_node_t * it = connection - > ssb - > rpc ; it ; it = it - > next )
2021-10-10 17:51:38 -04:00
{
2021-12-22 14:57:34 -05:00
if ( _tf_ssb_name_equals ( context , val , it - > name ) )
{
2024-05-02 19:59:54 -04:00
tf_ssb_connection_add_request ( connection , - request_number , namebuf , NULL , NULL , NULL , NULL ) ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( connection - > ssb - > trace , it - > flattened_name ) ;
2023-04-19 19:05:59 -04:00
PRE_CALLBACK ( connection - > ssb , it - > callback ) ;
2023-01-22 18:34:32 -05:00
it - > callback ( connection , flags , request_number , val , message , size , it - > user_data ) ;
2023-04-19 19:05:59 -04:00
POST_CALLBACK ( connection - > ssb , it - > callback ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( connection - > ssb - > trace ) ;
2021-12-22 14:57:34 -05:00
found = true ;
break ;
}
2021-01-02 13:10:00 -05:00
}
2023-09-09 10:28:06 -04:00
if ( ! found & & ! _tf_ssb_name_equals ( context , val , ( const char * [ ] ) { " Error " , NULL } ) )
2021-10-10 17:51:38 -04:00
{
2024-05-20 12:39:21 -04:00
tf_ssb_connection_add_request ( connection , - request_number , namebuf , NULL , NULL , NULL , NULL ) ;
2023-05-23 18:16:07 -04:00
char buffer [ 256 ] ;
_tf_ssb_name_to_string ( context , val , buffer , sizeof ( buffer ) ) ;
tf_ssb_connection_rpc_send_error_method_not_allowed ( connection , flags , - request_number , buffer ) ;
2021-01-02 13:10:00 -05:00
}
}
}
2021-12-22 14:57:34 -05:00
else
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Failed to parse %.*s \n " , ( int ) size , message ) ;
2023-08-20 15:55:59 -04:00
close_connection = true ;
2021-12-22 14:57:34 -05:00
}
2021-01-02 13:10:00 -05:00
JS_FreeValue ( context , val ) ;
2021-10-10 17:51:38 -04:00
}
else if ( ( flags & k_ssb_rpc_mask_type ) = = k_ssb_rpc_flag_binary )
{
2022-12-31 13:59:29 -05:00
if ( connection - > ssb - > verbose )
{
2024-02-17 14:22:02 -05:00
tf_printf ( CYAN " %s RPC RECV " RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] \n " , connection - > name , ( flags & k_ssb_rpc_flag_end_error ) ? " true " : " false " ,
( flags & k_ssb_rpc_flag_stream ) ? " true " : " false " , k_ssb_type_names [ flags & k_ssb_rpc_mask_type ] , request_number , size ) ;
2022-12-31 13:59:29 -05:00
}
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_t * callback = NULL ;
void * user_data = NULL ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_get_request_callback ( connection , - request_number , & callback , & user_data ) )
{
if ( callback )
{
2023-02-03 10:06:18 -05:00
char buffer [ 64 ] ;
snprintf ( buffer , sizeof ( buffer ) , " request %d " , request_number ) ;
tf_trace_begin ( connection - > ssb - > trace , buffer ) ;
2023-04-19 19:05:59 -04:00
PRE_CALLBACK ( connection - > ssb , callback ) ;
2021-01-02 13:10:00 -05:00
callback ( connection , flags , request_number , JS_UNDEFINED , message , size , user_data ) ;
2023-04-19 19:05:59 -04:00
POST_CALLBACK ( connection - > ssb , callback ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( connection - > ssb - > trace ) ;
2021-01-02 13:10:00 -05:00
}
}
}
2023-08-20 15:55:59 -04:00
if ( close_connection )
2021-10-10 17:51:38 -04:00
{
2023-08-20 15:55:59 -04:00
tf_ssb_connection_close ( connection ) ;
2021-01-02 13:10:00 -05:00
}
}
static void _tf_ssb_connection_rpc_recv_push ( tf_ssb_connection_t * connection , const uint8_t * data , size_t size )
{
2023-01-13 19:55:51 -05:00
size_t size_left = size ;
size_t size_processed = 0 ;
while ( size_left > 0 )
2021-10-10 17:51:38 -04:00
{
2024-02-15 18:35:01 -05:00
size_t copy_size =
2024-02-17 14:22:02 -05:00
( connection - > rpc_recv_size + size_left > sizeof ( connection - > rpc_recv_buffer ) ) ? sizeof ( connection - > rpc_recv_buffer ) - connection - > rpc_recv_size : size_left ;
2023-01-13 19:55:51 -05:00
if ( copy_size = = 0 )
2021-10-10 17:51:38 -04:00
{
2023-01-13 19:55:51 -05:00
_tf_ssb_connection_close ( connection , " recv buffer overflow " ) ;
return ;
2021-10-10 17:51:38 -04:00
}
2023-01-13 19:55:51 -05:00
memcpy ( connection - > rpc_recv_buffer + connection - > rpc_recv_size , data + size_processed , copy_size ) ;
connection - > rpc_recv_size + = copy_size ;
size_processed + = copy_size ;
size_left - = copy_size ;
while ( connection - > rpc_recv_size > = 9 )
2021-10-10 17:51:38 -04:00
{
2023-01-13 19:55:51 -05:00
uint8_t flags = * connection - > rpc_recv_buffer ;
uint32_t body_len ;
int32_t request_number ;
memcpy ( & body_len , connection - > rpc_recv_buffer + 1 , sizeof ( body_len ) ) ;
body_len = htonl ( body_len ) ;
memcpy ( & request_number , connection - > rpc_recv_buffer + 1 + sizeof ( body_len ) , sizeof ( request_number ) ) ;
request_number = htonl ( request_number ) ;
size_t rpc_size = 9 + body_len ;
if ( connection - > rpc_recv_size > = rpc_size )
{
uint8_t * end = & connection - > rpc_recv_buffer [ 9 + body_len ] ;
uint8_t tmp = * end ;
* end = ' \0 ' ;
_tf_ssb_connection_rpc_recv ( connection , flags , request_number , connection - > rpc_recv_buffer + 9 , body_len ) ;
* end = tmp ;
memmove ( connection - > rpc_recv_buffer , connection - > rpc_recv_buffer + rpc_size , connection - > rpc_recv_size - rpc_size ) ;
connection - > rpc_recv_size - = rpc_size ;
}
else
{
/* Wait for more body. */
break ;
}
2021-01-02 13:10:00 -05:00
}
}
}
static bool _tf_ssb_connection_box_stream_recv ( tf_ssb_connection_t * connection )
{
2021-10-10 17:51:38 -04:00
if ( ! connection - > body_len )
{
2021-01-02 13:10:00 -05:00
uint8_t header_enc [ 34 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , header_enc , sizeof ( header_enc ) ) )
{
2021-01-02 13:10:00 -05:00
uint8_t header [ 18 ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_open_easy ( header , header_enc , sizeof ( header_enc ) , connection - > nonce , connection - > s_to_c_box_key ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to open header secret box " ) ;
return false ;
}
_tf_ssb_nonce_inc ( connection - > nonce ) ;
connection - > body_len = htons ( * ( uint16_t * ) header ) ;
memcpy ( connection - > body_auth_tag , header + sizeof ( uint16_t ) , sizeof ( connection - > body_auth_tag ) ) ;
2021-10-10 17:51:38 -04:00
if ( ! connection - > body_len )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " empty body, graceful close " ) ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
return false ;
}
}
2021-10-10 17:51:38 -04:00
if ( connection - > body_len )
{
2023-01-14 08:27:19 -05:00
memcpy ( connection - > box_stream_buf , connection - > body_auth_tag , sizeof ( connection - > body_auth_tag ) ) ;
if ( _tf_ssb_connection_recv_pop ( connection , connection - > box_stream_buf + 16 , connection - > body_len ) )
2021-10-10 17:51:38 -04:00
{
2024-02-17 14:22:02 -05:00
if ( crypto_secretbox_open_easy ( connection - > secretbox_buf , connection - > box_stream_buf , 16 + connection - > body_len , connection - > nonce , connection - > s_to_c_box_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to open secret box " ) ;
return false ;
}
_tf_ssb_nonce_inc ( connection - > nonce ) ;
2023-01-14 08:27:19 -05:00
_tf_ssb_connection_rpc_recv_push ( connection , connection - > secretbox_buf , connection - > body_len ) ;
2021-01-02 13:10:00 -05:00
connection - > body_len = 0 ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
return false ;
}
}
return true ;
}
2024-06-16 07:51:06 -04:00
JSValue tf_ssb_sign_message ( tf_ssb_t * ssb , const char * author , const uint8_t * private_key , JSValue message , const char * previous_id , int64_t previous_sequence )
2021-01-02 13:10:00 -05:00
{
2024-06-16 07:51:06 -04:00
char actual_previous_id [ crypto_hash_sha256_BYTES * 2 ] ;
int64_t actual_previous_sequence = 0 ;
bool have_previous = false ;
if ( previous_id )
{
have_previous = * previous_id & & previous_sequence > 0 ;
snprintf ( actual_previous_id , sizeof ( actual_previous_id ) , " %s " , previous_id ) ;
actual_previous_sequence = previous_sequence ;
}
else
{
have_previous = tf_ssb_db_get_latest_message_by_author ( ssb , author , & actual_previous_sequence , actual_previous_id , sizeof ( actual_previous_id ) ) ;
}
2021-01-02 13:10:00 -05:00
JSContext * context = ssb - > context ;
JSValue root = JS_NewObject ( context ) ;
2024-06-16 07:51:06 -04:00
JS_SetPropertyStr ( context , root , " previous " , have_previous ? JS_NewString ( context , actual_previous_id ) : JS_NULL ) ;
2023-07-17 20:59:25 -04:00
JS_SetPropertyStr ( context , root , " author " , JS_NewString ( context , author ) ) ;
2024-06-16 07:51:06 -04:00
JS_SetPropertyStr ( context , root , " sequence " , JS_NewInt64 ( context , actual_previous_sequence + 1 ) ) ;
2021-01-02 13:10:00 -05:00
2022-01-10 22:18:15 -05:00
int64_t now = ( int64_t ) time ( NULL ) ;
JS_SetPropertyStr ( context , root , " timestamp " , JS_NewInt64 ( context , now * 1000LL ) ) ;
2021-01-02 13:10:00 -05:00
JSValue hashstr = JS_NewString ( context , " sha256 " ) ;
JS_SetPropertyStr ( context , root , " hash " , hashstr ) ;
JSValue content = JS_DupValue ( context , message ) ;
JS_SetPropertyStr ( context , root , " content " , content ) ;
JSValue jsonval = JS_JSONStringify ( context , root , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
size_t len = 0 ;
const char * json = JS_ToCStringLen ( context , & len , jsonval ) ;
2023-07-19 21:02:50 -04:00
JS_FreeValue ( context , jsonval ) ;
2021-01-02 13:10:00 -05:00
uint8_t signature [ crypto_sign_BYTES ] ;
unsigned long long siglen ;
2022-07-13 21:01:14 -04:00
bool valid = crypto_sign_detached ( signature , & siglen , ( const uint8_t * ) json , len , private_key ) = = 0 ;
2023-07-19 21:02:50 -04:00
JS_FreeCString ( context , json ) ;
2023-07-17 20:52:08 -04:00
if ( ! valid )
{
tf_printf ( " crypto_sign_detached failed \n " ) ;
2023-07-19 21:02:50 -04:00
JS_FreeValue ( context , root ) ;
root = JS_UNDEFINED ;
2021-01-02 13:10:00 -05:00
}
2022-02-09 22:58:33 -05:00
else
2021-10-10 17:51:38 -04:00
{
2023-07-19 21:02:50 -04:00
char signature_base64 [ crypto_sign_BYTES * 2 ] ;
tf_base64_encode ( signature , sizeof ( signature ) , signature_base64 , sizeof ( signature_base64 ) ) ;
strcat ( signature_base64 , " .sig.ed25519 " ) ;
JSValue sigstr = JS_NewString ( context , signature_base64 ) ;
JS_SetPropertyStr ( context , root , " signature " , sigstr ) ;
2023-07-12 20:20:12 -04:00
}
2023-07-19 21:02:50 -04:00
return root ;
2021-01-02 13:10:00 -05:00
}
2023-05-23 18:47:25 -04:00
static void _tf_ssb_connection_destroy ( tf_ssb_connection_t * connection , const char * reason )
2021-01-02 13:10:00 -05:00
{
tf_ssb_t * ssb = connection - > ssb ;
2023-10-08 11:14:42 -04:00
connection - > closing = true ;
2022-01-25 20:15:04 -05:00
if ( ! connection - > destroy_reason )
{
connection - > destroy_reason = reason ;
2022-11-02 19:34:44 -04:00
}
2024-06-02 12:38:12 -04:00
_tf_ssb_connection_dispatch_scheduled ( connection ) ;
2023-01-16 21:17:29 -05:00
tf_free ( connection - > scheduled ) ;
connection - > scheduled = NULL ;
2022-11-02 19:34:44 -04:00
while ( connection - > requests )
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( connection , connection - > requests - > request_number ) ;
2022-01-25 20:15:04 -05:00
}
2022-11-08 20:31:18 -05:00
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = node - > next )
{
if ( node - > tunnel_connection = = connection )
{
node - > tunnel_connection = NULL ;
node - > mtime = 0 ;
}
}
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * * it = & connection - > ssb - > connections ; * it ; it = & ( * it ) - > next )
{
2023-01-07 19:25:38 -05:00
for ( int i = ( * it ) - > requests_count - 1 ; i > = 0 ; i - - )
2022-11-06 21:57:29 -05:00
{
if ( ( * it ) - > requests [ i ] . dependent_connection = = connection )
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( * it , ( * it ) - > requests [ i ] . request_number ) ;
2022-11-06 21:57:29 -05:00
}
}
2021-10-10 17:51:38 -04:00
if ( * it = = connection )
{
2021-01-02 13:10:00 -05:00
* it = connection - > next ;
connection - > next = NULL ;
2022-01-12 20:08:17 -05:00
ssb - > connections_count - - ;
2022-01-22 15:13:14 -05:00
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_remove , connection ) ;
2021-01-02 13:10:00 -05:00
break ;
}
}
2022-11-02 19:34:44 -04:00
bool again = true ;
while ( again )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
again = false ;
for ( tf_ssb_connection_t * it = connection - > ssb - > connections ; it ; it = it - > next )
{
if ( it - > tunnel_connection = = connection )
{
it - > tunnel_connection = NULL ;
_tf_ssb_connection_close ( it , " tunnel closed " ) ;
again = true ;
break ;
}
2022-11-19 16:42:54 -05:00
else if ( it = = connection - > tunnel_connection )
2022-11-02 19:34:44 -04:00
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( it , connection - > tunnel_request_number ) ;
2022-11-02 19:34:44 -04:00
connection - > tunnel_connection = NULL ;
2022-11-19 16:42:54 -05:00
connection - > tunnel_request_number = 0 ;
2022-11-02 19:34:44 -04:00
}
}
2021-01-02 13:10:00 -05:00
}
2022-01-22 15:13:14 -05:00
if ( ! JS_IsUndefined ( connection - > object ) )
{
2022-01-23 07:52:55 -05:00
JSValue object = connection - > object ;
2022-01-22 15:13:14 -05:00
connection - > object = JS_UNDEFINED ;
2022-01-23 07:52:55 -05:00
JS_SetOpaque ( object , NULL ) ;
JS_FreeValue ( ssb - > context , object ) ;
2022-01-22 15:13:14 -05:00
}
if ( connection - > async . data & & ! uv_is_closing ( ( uv_handle_t * ) & connection - > async ) )
{
uv_close ( ( uv_handle_t * ) & connection - > async , _tf_ssb_connection_on_close ) ;
}
if ( connection - > tcp . data & & ! uv_is_closing ( ( uv_handle_t * ) & connection - > tcp ) )
{
uv_close ( ( uv_handle_t * ) & connection - > tcp , _tf_ssb_connection_on_close ) ;
}
2024-02-15 18:35:01 -05:00
if ( JS_IsUndefined ( connection - > object ) & & ! connection - > async . data & & ! connection - > tcp . data & & ! connection - > connect . data & & connection - > ref_count = = 0 )
2022-01-22 15:13:14 -05:00
{
2023-01-08 12:45:15 -05:00
tf_free ( connection - > message_requests ) ;
connection - > message_requests = NULL ;
connection - > message_requests_count = 0 ;
2023-01-22 15:37:19 -05:00
for ( int i = 0 ; i < k_debug_close_message_count ; i + + )
{
tf_free ( connection - > debug_messages [ i ] ) ;
connection - > debug_messages [ i ] = NULL ;
}
2024-02-15 18:35:01 -05:00
if ( - - connection - > ssb - > connection_ref_count = = 0 & & connection - > ssb - > shutting_down )
2024-02-06 12:42:17 -05:00
{
tf_ssb_destroy ( connection - > ssb ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( connection ) ;
2022-01-22 15:13:14 -05:00
}
}
static void _tf_ssb_connection_on_close ( uv_handle_t * handle )
{
tf_ssb_connection_t * connection = handle - > data ;
handle - > data = NULL ;
2022-01-25 20:15:04 -05:00
if ( connection )
{
_tf_ssb_connection_destroy ( connection , " handle closed " ) ;
}
2021-01-02 13:10:00 -05:00
}
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_on_tcp_recv_internal ( tf_ssb_connection_t * connection , const void * data , ssize_t nread )
2021-01-02 13:10:00 -05:00
{
2021-10-10 17:51:38 -04:00
if ( nread > = 0 )
{
if ( connection - > recv_size + nread > sizeof ( connection - > recv_buffer ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " recv buffer overflow " ) ;
return ;
}
2022-11-02 19:34:44 -04:00
memcpy ( connection - > recv_buffer + connection - > recv_size , data , nread ) ;
2021-01-02 13:10:00 -05:00
connection - > recv_size + = nread ;
2021-10-10 17:51:38 -04:00
switch ( connection - > state )
{
2021-01-02 13:10:00 -05:00
case k_tf_ssb_state_invalid :
_tf_ssb_connection_close ( connection , " received a message in invalid state " ) ;
break ;
case k_tf_ssb_state_connected :
_tf_ssb_connection_close ( connection , " received a message in connected state " ) ;
break ;
case k_tf_ssb_state_sent_hello :
{
uint8_t hello [ 64 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , hello , sizeof ( hello ) ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_send_identity ( connection , hello , hello + 32 ) ;
}
}
break ;
case k_tf_ssb_state_sent_identity :
{
uint8_t identity [ 80 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , identity , sizeof ( identity ) ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_verify_identity ( connection , identity , sizeof ( identity ) ) ;
}
}
break ;
case k_tf_ssb_state_verified :
2022-01-22 15:13:14 -05:00
uv_async_send ( & connection - > async ) ;
2021-01-02 13:10:00 -05:00
break ;
case k_tf_ssb_state_server_wait_hello :
{
uint8_t hello [ 64 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , hello , sizeof ( hello ) ) )
{
2021-01-02 13:10:00 -05:00
uint8_t * hmac = hello ;
memcpy ( connection - > serverepub , hello + crypto_box_PUBLICKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
static_assert ( sizeof ( connection - > serverepub ) = = crypto_box_PUBLICKEYBYTES , " serverepub size " ) ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256_verify ( hmac , connection - > serverepub , 32 , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " crypto_auth_hmacsha512256_verify failed " ) ;
2021-10-10 17:51:38 -04:00
}
else
{
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_client_send_hello ( connection ) ;
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_server_wait_client_identity ;
}
}
}
break ;
case k_tf_ssb_state_server_wait_client_identity :
{
uint8_t identity [ 112 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , identity , sizeof ( identity ) ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_verify_client_identity ( connection , identity , sizeof ( identity ) ) ;
}
}
break ;
case k_tf_ssb_state_server_verified :
2022-01-22 15:13:14 -05:00
uv_async_send ( & connection - > async ) ;
2021-01-02 13:10:00 -05:00
break ;
case k_tf_ssb_state_closing :
break ;
}
2021-10-10 17:51:38 -04:00
}
2022-01-22 16:20:43 -05:00
else if ( nread = = UV_ENOBUFS )
{
/* Our read buffer is full. Try harder to process messages. */
uv_async_send ( & connection - > async ) ;
}
2021-10-10 17:51:38 -04:00
else
{
2023-01-10 20:43:35 -05:00
_tf_ssb_connection_close ( connection , uv_strerror ( nread ) ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_on_tcp_recv ( uv_stream_t * stream , ssize_t nread , const uv_buf_t * buf )
2021-01-02 13:10:00 -05:00
{
tf_ssb_connection_t * connection = stream - > data ;
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_on_tcp_recv_internal ( connection , buf - > base , nread ) ;
tf_free ( buf - > base ) ;
}
static void _tf_ssb_connection_client_send_hello ( tf_ssb_connection_t * connection )
{
2021-01-02 13:10:00 -05:00
char write [ crypto_auth_BYTES + crypto_box_PUBLICKEYBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_box_keypair ( connection - > epub , connection - > epriv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to generate ephemeral keypair " ) ;
return ;
}
uint8_t a [ crypto_auth_hmacsha512256_BYTES ] ;
2024-03-02 15:01:09 -05:00
if ( crypto_auth_hmacsha512256 ( a , connection - > epub , sizeof ( connection - > epub ) , connection - > ssb - > network_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to create hello message " ) ;
return ;
}
char * b = write ;
memcpy ( b , a , crypto_auth_BYTES ) ;
memcpy ( b + crypto_auth_BYTES , connection - > epub , sizeof ( connection - > epub ) ) ;
_tf_ssb_write ( connection , b , crypto_auth_BYTES + sizeof ( connection - > epub ) ) ;
connection - > state = k_tf_ssb_state_sent_hello ;
}
2024-05-22 19:53:33 -04:00
static bool _tf_ssb_connection_read_start ( tf_ssb_connection_t * connection )
{
int result = uv_read_start ( ( uv_stream_t * ) & connection - > tcp , _tf_ssb_connection_on_tcp_alloc , _tf_ssb_connection_on_tcp_recv ) ;
if ( result & & result ! = UV_EALREADY )
{
tf_printf ( " uv_read_start => %s \n " , uv_strerror ( result ) ) ;
_tf_ssb_connection_close ( connection , " uv_read_start failed " ) ;
return false ;
}
return true ;
}
static bool _tf_ssb_connection_read_stop ( tf_ssb_connection_t * connection )
{
int result = uv_read_stop ( ( uv_stream_t * ) & connection - > tcp ) ;
if ( result & & result ! = UV_EALREADY )
{
tf_printf ( " uv_read_stop => %s \n " , uv_strerror ( result ) ) ;
_tf_ssb_connection_close ( connection , " uv_read_stop failed " ) ;
return false ;
}
return true ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_on_connect ( uv_connect_t * connect , int status )
{
tf_ssb_connection_t * connection = connect - > data ;
connect - > data = NULL ;
2021-10-10 17:51:38 -04:00
if ( status = = 0 )
{
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_connected ;
2024-05-22 19:53:33 -04:00
if ( _tf_ssb_connection_read_start ( connection ) )
2022-01-19 23:01:45 -05:00
{
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_client_send_hello ( connection ) ;
2022-01-19 23:01:45 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " uv_tcp_connect failed " ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-10-14 08:27:34 -04:00
static void _load_keys_callback ( const char * identity , void * user_data )
2021-01-02 13:10:00 -05:00
{
2022-10-14 08:27:34 -04:00
tf_ssb_t * ssb = user_data ;
if ( * ssb - > pub )
2021-10-10 17:51:38 -04:00
{
2022-10-14 08:27:34 -04:00
return ;
2021-01-02 13:10:00 -05:00
}
2022-10-14 08:27:34 -04:00
tf_ssb_id_str_to_bin ( ssb - > pub , identity ) ;
tf_ssb_db_identity_get_private_key ( ssb , " :admin " , identity , ssb - > priv , sizeof ( ssb - > priv ) ) ;
2021-01-02 13:10:00 -05:00
}
2022-10-14 08:27:34 -04:00
static bool _tf_ssb_load_keys ( tf_ssb_t * ssb )
2021-01-02 13:10:00 -05:00
{
2022-10-14 08:27:34 -04:00
tf_ssb_db_identity_visit ( ssb , " :admin " , _load_keys_callback , ssb ) ;
return * ssb - > pub ! = ' \0 ' & & * ssb - > priv ! = ' \0 ' ;
2021-01-02 13:10:00 -05:00
}
2021-12-21 14:06:44 -05:00
static void _tf_ssb_trace_timer ( uv_timer_t * timer )
{
tf_ssb_t * ssb = timer - > data ;
2024-02-15 18:35:01 -05:00
const char * names [ ] = {
2021-12-21 14:06:44 -05:00
" connections " ,
" broadcasts " ,
" rpc " ,
" connections_changed " ,
" message_added " ,
" blob_want_added " ,
" broadcasts_changed " ,
} ;
2024-02-15 18:35:01 -05:00
int64_t values [ ] = {
2022-01-12 20:08:17 -05:00
ssb - > connections_count ,
ssb - > broadcasts_count ,
ssb - > rpc_count ,
ssb - > connections_changed_count ,
ssb - > message_added_count ,
ssb - > blob_want_added_count ,
ssb - > broadcasts_changed_count ,
2021-12-21 14:06:44 -05:00
} ;
2022-01-15 12:40:24 -05:00
tf_trace_counter ( ssb - > trace , " ssb " , _countof ( values ) , names , values ) ;
2021-12-21 14:06:44 -05:00
}
2022-02-05 15:18:58 -05:00
void tf_ssb_get_stats ( tf_ssb_t * ssb , tf_ssb_stats_t * out_stats )
{
* out_stats = ( tf_ssb_stats_t )
{
. connections = ssb - > connections_count ,
. broadcasts = ssb - > broadcasts_count ,
. messages_stored = ssb - > messages_stored ,
2023-01-18 17:52:54 -05:00
. blobs_stored = ssb - > blobs_stored ,
2022-02-05 15:18:58 -05:00
. rpc_in = ssb - > rpc_in ,
. rpc_out = ssb - > rpc_out ,
2022-07-09 18:00:33 -04:00
. request_count = ssb - > request_count ,
2022-02-05 15:18:58 -05:00
. callbacks =
{
. rpc = ssb - > rpc_count ,
. connections_changed = ssb - > connections_changed_count ,
. message_added = ssb - > message_added_count ,
. blob_want_added = ssb - > blob_want_added_count ,
. broadcasts_changed = ssb - > broadcasts_changed_count ,
} ,
} ;
ssb - > messages_stored = 0 ;
2023-01-18 17:52:54 -05:00
ssb - > blobs_stored = 0 ;
2022-02-05 15:18:58 -05:00
ssb - > rpc_in = 0 ;
ssb - > rpc_out = 0 ;
}
2024-03-02 15:01:09 -05:00
tf_ssb_t * tf_ssb_create ( uv_loop_t * loop , JSContext * context , const char * db_path , const char * network_key )
2021-01-02 13:10:00 -05:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_t * ssb = tf_malloc ( sizeof ( tf_ssb_t ) ) ;
2021-01-02 13:10:00 -05:00
memset ( ssb , 0 , sizeof ( * ssb ) ) ;
2024-01-09 21:41:28 -05:00
2024-03-02 15:01:09 -05:00
const char * actual_key = network_key ? network_key : k_ssb_network_string ;
if ( sodium_hex2bin ( ssb - > network_key , sizeof ( ssb - > network_key ) , actual_key , strlen ( actual_key ) , " : " , NULL , NULL ) )
{
tf_printf ( " Error parsing network key: %s. " , actual_key ) ;
}
2024-01-09 21:41:28 -05:00
char buffer [ 8 ] = { 0 } ;
size_t buffer_size = sizeof ( buffer ) ;
ssb - > store_debug_messages = uv_os_getenv ( " TF_DEBUG_CLOSE " , buffer , & buffer_size ) = = 0 & & strcmp ( buffer , " 1 " ) = = 0 ;
buffer_size = sizeof ( buffer ) ;
ssb - > verbose = uv_os_getenv ( " TF_SSB_VERBOSE " , buffer , & buffer_size ) = = 0 & & strcmp ( buffer , " 1 " ) = = 0 ;
2021-10-10 17:51:38 -04:00
if ( context )
{
2021-01-02 13:10:00 -05:00
ssb - > context = context ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
ssb - > own_context = true ;
2022-06-20 13:57:07 -04:00
JSMallocFunctions funcs = { 0 } ;
tf_get_js_malloc_functions ( & funcs ) ;
ssb - > runtime = JS_NewRuntime2 ( & funcs , NULL ) ;
2021-01-02 13:10:00 -05:00
ssb - > context = JS_NewContext ( ssb - > runtime ) ;
}
2023-02-07 20:29:44 -05:00
uv_mutex_init ( & ssb - > db_readers_lock ) ;
2023-06-14 20:27:49 -04:00
uv_mutex_init ( & ssb - > db_writer_lock ) ;
2023-02-07 20:29:44 -05:00
2021-09-06 13:50:38 -04:00
JS_NewClassID ( & _connection_class_id ) ;
2024-02-15 18:35:01 -05:00
JSClassDef def = {
2021-09-06 13:50:38 -04:00
. class_name = " connection " ,
. finalizer = _tf_ssb_connection_finalizer ,
} ;
JS_NewClass ( JS_GetRuntime ( ssb - > context ) , _connection_class_id , & def ) ;
2023-02-07 20:29:44 -05:00
ssb - > db_path = tf_strdup ( db_path ) ;
2023-07-19 21:02:50 -04:00
sqlite3_open_v2 ( db_path , & ssb - > db_writer , SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI | SQLITE_OPEN_CREATE , NULL ) ;
2021-08-22 15:34:28 -04:00
tf_ssb_db_init ( ssb ) ;
2021-01-02 13:10:00 -05:00
2021-10-10 17:51:38 -04:00
if ( loop )
{
2021-01-02 13:10:00 -05:00
ssb - > loop = loop ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
uv_loop_init ( & ssb - > own_loop ) ;
ssb - > loop = & ssb - > own_loop ;
}
ssb - > broadcast_timer . data = ssb ;
uv_timer_init ( ssb - > loop , & ssb - > broadcast_timer ) ;
2023-04-29 23:18:12 -04:00
ssb - > trace_timer . data = ssb ;
uv_timer_init ( ssb - > loop , & ssb - > trace_timer ) ;
uv_timer_start ( & ssb - > trace_timer , _tf_ssb_trace_timer , 100 , 100 ) ;
uv_unref ( ( uv_handle_t * ) & ssb - > trace_timer ) ;
2021-10-10 17:51:38 -04:00
if ( ! _tf_ssb_load_keys ( ssb ) )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Generating a new keypair. \n " ) ;
2022-10-14 08:27:34 -04:00
tf_ssb_db_identity_create ( ssb , " :admin " , ssb - > pub , ssb - > priv ) ;
2021-01-02 13:10:00 -05:00
}
ssb - > connections_tracker = tf_ssb_connections_create ( ssb ) ;
2023-10-11 11:44:40 -04:00
_tf_ssb_update_settings ( ssb ) ;
2022-11-16 20:36:24 -05:00
tf_ssb_rpc_register ( ssb ) ;
2024-01-27 09:44:17 -05:00
_tf_ssb_start_update_settings ( ssb ) ;
2021-01-02 13:10:00 -05:00
return ssb ;
}
2023-11-08 18:03:21 -05:00
void tf_ssb_start_periodic ( tf_ssb_t * ssb )
{
tf_ssb_rpc_start_periodic ( ssb ) ;
}
2023-10-08 10:25:22 -04:00
static void _tf_ssb_assert_not_main_thread ( tf_ssb_t * ssb )
{
if ( uv_thread_self ( ) = = ssb - > thread_self )
{
const char * bt = tf_util_backtrace_string ( ) ;
tf_printf ( " Acquiring DB from the main thread: \n %s \n " , bt ) ;
tf_free ( ( void * ) bt ) ;
2024-06-17 12:36:54 -04:00
abort ( ) ;
2023-10-08 10:25:22 -04:00
}
}
2023-02-07 20:29:44 -05:00
sqlite3 * tf_ssb_acquire_db_reader ( tf_ssb_t * ssb )
{
2023-07-20 01:06:15 -04:00
tf_trace_begin ( ssb - > trace , " db_reader " ) ;
2023-10-08 10:25:22 -04:00
_tf_ssb_assert_not_main_thread ( ssb ) ;
2023-02-07 20:29:44 -05:00
sqlite3 * db = NULL ;
uv_mutex_lock ( & ssb - > db_readers_lock ) ;
if ( ssb - > db_readers_count )
{
db = ssb - > db_readers [ - - ssb - > db_readers_count ] ;
}
else
{
2023-06-14 20:27:49 -04:00
sqlite3_open_v2 ( ssb - > db_path , & db , SQLITE_OPEN_READONLY | SQLITE_OPEN_URI , NULL ) ;
2023-02-17 17:43:19 -05:00
tf_ssb_db_init_reader ( db ) ;
2023-02-07 20:29:44 -05:00
}
2023-07-20 01:06:15 -04:00
tf_trace_sqlite ( ssb - > trace , db ) ;
2023-02-07 20:29:44 -05:00
uv_mutex_unlock ( & ssb - > db_readers_lock ) ;
2023-08-25 15:41:54 -04:00
sqlite3_set_authorizer ( db , NULL , NULL ) ;
return db ;
}
sqlite3 * tf_ssb_acquire_db_reader_restricted ( tf_ssb_t * ssb )
{
sqlite3 * db = tf_ssb_acquire_db_reader ( ssb ) ;
sqlite3_set_authorizer ( db , tf_ssb_sqlite_authorizer , ssb ) ;
2023-02-07 20:29:44 -05:00
return db ;
}
void tf_ssb_release_db_reader ( tf_ssb_t * ssb , sqlite3 * db )
{
2024-01-09 21:36:27 -05:00
sqlite3_db_release_memory ( db ) ;
2023-02-07 20:29:44 -05:00
uv_mutex_lock ( & ssb - > db_readers_lock ) ;
ssb - > db_readers = tf_resize_vec ( ssb - > db_readers , sizeof ( sqlite3 * ) * ( ssb - > db_readers_count + 1 ) ) ;
ssb - > db_readers [ ssb - > db_readers_count + + ] = db ;
uv_mutex_unlock ( & ssb - > db_readers_lock ) ;
2023-07-20 01:06:15 -04:00
tf_trace_end ( ssb - > trace ) ;
2023-02-07 20:29:44 -05:00
}
2023-06-14 20:27:49 -04:00
sqlite3 * tf_ssb_acquire_db_writer ( tf_ssb_t * ssb )
{
2023-07-20 01:06:15 -04:00
tf_trace_begin ( ssb - > trace , " db_writer " ) ;
2023-10-08 10:25:22 -04:00
_tf_ssb_assert_not_main_thread ( ssb ) ;
2023-06-14 20:27:49 -04:00
uv_mutex_lock ( & ssb - > db_writer_lock ) ;
sqlite3 * writer = ssb - > db_writer ;
assert ( writer ) ;
ssb - > db_writer = NULL ;
return writer ;
}
void tf_ssb_release_db_writer ( tf_ssb_t * ssb , sqlite3 * db )
{
assert ( ssb - > db_writer = = NULL ) ;
2024-01-09 21:36:27 -05:00
sqlite3_db_release_memory ( db ) ;
2023-06-14 20:27:49 -04:00
ssb - > db_writer = db ;
uv_mutex_unlock ( & ssb - > db_writer_lock ) ;
2023-07-20 01:06:15 -04:00
tf_trace_end ( ssb - > trace ) ;
2023-06-14 20:27:49 -04:00
}
2021-01-02 13:10:00 -05:00
uv_loop_t * tf_ssb_get_loop ( tf_ssb_t * ssb )
{
return ssb - > loop ;
}
void tf_ssb_generate_keys ( tf_ssb_t * ssb )
{
crypto_sign_ed25519_keypair ( ssb - > pub , ssb - > priv ) ;
}
2022-07-13 21:01:14 -04:00
void tf_ssb_generate_keys_buffer ( char * out_public , size_t public_size , char * out_private , size_t private_size )
{
uint8_t public [ crypto_sign_PUBLICKEYBYTES ] ;
uint8_t private [ crypto_sign_SECRETKEYBYTES ] ;
crypto_sign_ed25519_keypair ( public , private ) ;
2023-02-13 22:15:24 -05:00
char buffer [ 512 ] ;
tf_base64_encode ( public , sizeof ( public ) , buffer , sizeof ( buffer ) ) ;
2022-07-13 21:01:14 -04:00
snprintf ( out_public , public_size , " %s.ed25519 " , buffer ) ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( private , sizeof ( private ) , buffer , sizeof ( buffer ) ) ;
2022-07-13 21:01:14 -04:00
snprintf ( out_private , private_size , " %s.ed25519 " , buffer ) ;
}
2023-06-01 18:53:44 -04:00
void tf_ssb_get_private_key ( tf_ssb_t * ssb , uint8_t * out_private , size_t private_size )
{
memcpy ( out_private , ssb - > priv , tf_min ( private_size , sizeof ( ssb - > priv ) ) ) ;
}
2021-01-02 13:10:00 -05:00
void tf_ssb_set_trace ( tf_ssb_t * ssb , tf_trace_t * trace )
{
ssb - > trace = trace ;
2023-06-14 20:27:49 -04:00
sqlite3 * db = tf_ssb_acquire_db_writer ( ssb ) ;
if ( trace & & db )
2021-10-10 17:51:38 -04:00
{
2023-06-14 20:27:49 -04:00
tf_trace_sqlite ( trace , db ) ;
2021-01-02 13:10:00 -05:00
}
2023-06-14 20:27:49 -04:00
tf_ssb_release_db_writer ( ssb , db ) ;
2023-07-20 01:06:15 -04:00
if ( trace )
{
uv_mutex_lock ( & ssb - > db_readers_lock ) ;
for ( int i = 0 ; i < ssb - > db_readers_count ; i + + )
{
tf_trace_sqlite ( trace , ssb - > db_readers [ i ] ) ;
}
uv_mutex_unlock ( & ssb - > db_readers_lock ) ;
}
2021-01-02 13:10:00 -05:00
}
tf_trace_t * tf_ssb_get_trace ( tf_ssb_t * ssb )
{
return ssb - > trace ;
}
JSContext * tf_ssb_get_context ( tf_ssb_t * ssb )
{
return ssb - > context ;
}
static void _tf_ssb_on_handle_close ( uv_handle_t * handle )
{
handle - > data = NULL ;
}
2024-01-27 08:48:16 -05:00
static void _tf_ssb_on_timer_close ( uv_handle_t * handle )
{
tf_free ( handle - > data ) ;
}
2021-01-02 13:10:00 -05:00
void tf_ssb_destroy ( tf_ssb_t * ssb )
{
2024-01-27 09:44:17 -05:00
tf_printf ( " tf_ssb_destroy \n " ) ;
2024-02-06 12:42:17 -05:00
ssb - > shutting_down = true ;
2024-02-13 18:07:36 -05:00
if ( ssb - > connections_tracker )
{
tf_ssb_connections_destroy ( ssb - > connections_tracker ) ;
ssb - > connections_tracker = NULL ;
}
2021-01-02 13:10:00 -05:00
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_listener . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_listener ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_listener , _tf_ssb_on_handle_close ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_sender . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_sender ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_sender , _tf_ssb_on_handle_close ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_timer . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_timer ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_timer , _tf_ssb_on_handle_close ) ;
}
2022-01-19 22:35:03 -05:00
if ( ssb - > broadcast_cleanup_timer . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_cleanup_timer ) )
{
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_cleanup_timer , _tf_ssb_on_handle_close ) ;
}
2021-12-21 14:06:44 -05:00
if ( ssb - > trace_timer . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > trace_timer ) )
{
uv_close ( ( uv_handle_t * ) & ssb - > trace_timer , _tf_ssb_on_handle_close ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > server . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > server ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > server , _tf_ssb_on_handle_close ) ;
}
2024-01-27 08:48:16 -05:00
for ( int i = 0 ; i < ssb - > timers_count ; i + + )
{
uv_close ( ( uv_handle_t * ) & ssb - > timers [ i ] - > timer , _tf_ssb_on_timer_close ) ;
}
ssb - > timers_count = 0 ;
tf_free ( ssb - > timers ) ;
ssb - > timers = NULL ;
2024-01-27 09:44:17 -05:00
tf_printf ( " Waiting for closes. \n " ) ;
2024-02-15 18:35:01 -05:00
while ( ssb - > broadcast_listener . data | | ssb - > broadcast_sender . data | | ssb - > broadcast_timer . data | | ssb - > broadcast_cleanup_timer . data | | ssb - > trace_timer . data | |
2024-02-17 14:22:02 -05:00
ssb - > server . data | | ssb - > ref_count )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
uv_run ( ssb - > loop , UV_RUN_ONCE ) ;
}
2024-01-27 09:44:17 -05:00
tf_printf ( " Waiting for rpc. \n " ) ;
2021-10-10 17:51:38 -04:00
while ( ssb - > rpc )
{
2021-09-06 13:50:38 -04:00
tf_ssb_rpc_callback_node_t * node = ssb - > rpc ;
ssb - > rpc = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > rpc_count - - ;
2021-10-10 17:51:38 -04:00
if ( node - > cleanup )
{
2021-09-06 13:50:38 -04:00
node - > cleanup ( ssb , node - > user_data ) ;
node - > cleanup = NULL ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-09-06 13:50:38 -04:00
}
2021-11-07 17:28:58 -05:00
while ( ssb - > connections_changed )
{
tf_ssb_connections_changed_callback_node_t * node = ssb - > connections_changed ;
ssb - > connections_changed = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > connections_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
2021-11-10 19:05:07 -05:00
while ( ssb - > message_added )
{
tf_ssb_message_added_callback_node_t * node = ssb - > message_added ;
ssb - > message_added = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > message_added_count - - ;
2021-11-10 19:05:07 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-10 19:05:07 -05:00
}
2021-10-10 17:51:38 -04:00
while ( ssb - > blob_want_added )
{
2021-09-06 13:50:38 -04:00
tf_ssb_blob_want_added_callback_node_t * node = ssb - > blob_want_added ;
ssb - > blob_want_added = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > blob_want_added_count - - ;
2021-10-10 17:51:38 -04:00
if ( node - > cleanup )
{
2021-09-06 13:50:38 -04:00
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-09-06 13:50:38 -04:00
}
2021-11-07 17:28:58 -05:00
while ( ssb - > broadcasts_changed )
{
tf_ssb_broadcasts_changed_callback_node_t * node = ssb - > broadcasts_changed ;
ssb - > broadcasts_changed = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
2024-01-27 09:44:17 -05:00
tf_printf ( " Closing connections. \n " ) ;
tf_ssb_connection_t * connection = ssb - > connections ;
while ( connection )
{
tf_ssb_connection_t * next = connection - > next ;
tf_ssb_connection_close ( connection ) ;
connection = next ;
}
tf_printf ( " Closed. \n " ) ;
2022-11-02 19:34:44 -04:00
if ( ssb - > loop = = & ssb - > own_loop )
{
2023-08-02 20:30:48 -04:00
int r = uv_loop_close ( ssb - > loop ) ;
if ( r ! = 0 )
{
tf_printf ( " uv_loop_close: %s \n " , uv_strerror ( r ) ) ;
}
2022-11-02 19:34:44 -04:00
}
2024-02-13 18:07:36 -05:00
tf_printf ( " uv loop closed. \n " ) ;
2021-10-10 17:51:38 -04:00
if ( ssb - > own_context )
{
2024-02-15 19:47:54 -05:00
tf_printf ( " closing ssb context \n " ) ;
2021-01-02 13:10:00 -05:00
JS_FreeContext ( ssb - > context ) ;
JS_FreeRuntime ( ssb - > runtime ) ;
2024-02-13 18:07:36 -05:00
ssb - > own_context = false ;
}
if ( ssb - > db_writer )
{
sqlite3_close ( ssb - > db_writer ) ;
ssb - > db_writer = NULL ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
while ( ssb - > broadcasts )
{
2021-01-02 13:10:00 -05:00
tf_ssb_broadcast_t * broadcast = ssb - > broadcasts ;
ssb - > broadcasts = broadcast - > next ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_count - - ;
2022-06-04 13:04:51 -04:00
tf_free ( broadcast ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-22 15:37:19 -05:00
for ( int i = 0 ; i < k_debug_close_connection_count ; i + + )
{
for ( int j = 0 ; j < k_debug_close_message_count ; j + + )
{
tf_free ( ssb - > debug_close [ i ] . messages [ j ] ) ;
}
}
2023-02-07 20:29:44 -05:00
for ( int i = 0 ; i < ssb - > db_readers_count ; i + + )
{
sqlite3_close ( ssb - > db_readers [ i ] ) ;
}
2024-02-13 18:07:36 -05:00
ssb - > db_readers_count = 0 ;
if ( ssb - > db_readers )
{
tf_free ( ssb - > db_readers ) ;
ssb - > db_readers = NULL ;
}
if ( ssb - > db_path )
{
tf_free ( ( void * ) ssb - > db_path ) ;
ssb - > db_path = NULL ;
}
if ( ssb - > room_name )
{
tf_free ( ssb - > room_name ) ;
ssb - > room_name = NULL ;
}
2024-02-06 12:42:17 -05:00
if ( ssb - > connection_ref_count = = 0 )
{
2024-02-13 18:07:36 -05:00
uv_mutex_destroy ( & ssb - > db_readers_lock ) ;
uv_mutex_destroy ( & ssb - > db_writer_lock ) ;
2024-02-06 12:42:17 -05:00
tf_free ( ssb ) ;
}
2021-01-02 13:10:00 -05:00
}
2024-05-16 12:41:48 -04:00
bool tf_ssb_is_shutting_down ( tf_ssb_t * ssb )
{
return ssb - > shutting_down ;
}
2021-01-02 13:10:00 -05:00
void tf_ssb_run ( tf_ssb_t * ssb )
{
uv_run ( ssb - > loop , UV_RUN_DEFAULT ) ;
}
2021-09-06 13:50:38 -04:00
static void _tf_ssb_connection_finalizer ( JSRuntime * runtime , JSValue value )
{
tf_ssb_connection_t * connection = JS_GetOpaque ( value , _connection_class_id ) ;
2022-01-22 15:13:14 -05:00
if ( connection )
{
connection - > object = JS_UNDEFINED ;
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " object finalized " ) ;
2022-01-22 15:13:14 -05:00
}
2021-09-06 13:50:38 -04:00
}
2022-01-22 15:13:14 -05:00
static void _tf_ssb_connection_process_message_async ( uv_async_t * async )
{
tf_ssb_connection_t * connection = async - > data ;
if ( _tf_ssb_connection_box_stream_recv ( connection ) )
{
uv_async_send ( & connection - > async ) ;
}
}
2021-01-02 13:10:00 -05:00
tf_ssb_connection_t * tf_ssb_connection_create ( tf_ssb_t * ssb , const char * host , const struct sockaddr_in * addr , const uint8_t * public_key )
{
2022-01-19 23:01:45 -05:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2022-11-09 18:25:22 -05:00
if ( memcmp ( connection - > serverpub , public_key , k_id_bin_len ) = = 0 & & connection - > state ! = k_tf_ssb_state_invalid )
2022-01-19 23:01:45 -05:00
{
char id [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , public_key ) ;
2023-03-07 12:50:17 -05:00
tf_printf ( " Not connecting to %s:%d, because we are already connected to %s (state = %d). \n " , host , ntohs ( addr - > sin_port ) , id , connection - > state ) ;
2022-01-19 23:01:45 -05:00
return NULL ;
}
else if ( memcmp ( ssb - > pub , public_key , k_id_bin_len ) = = 0 )
{
char id [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , public_key ) ;
2023-03-07 12:50:17 -05:00
tf_printf ( " Not connecting to %s:%d, because they appear to be ourselves %s. \n " , host , ntohs ( addr - > sin_port ) , id ) ;
2022-01-19 23:01:45 -05:00
return NULL ;
}
}
2021-09-06 13:50:38 -04:00
JSContext * context = ssb - > context ;
2022-06-04 13:04:51 -04:00
tf_ssb_connection_t * connection = tf_malloc ( sizeof ( tf_ssb_connection_t ) ) ;
2024-02-06 12:42:17 -05:00
ssb - > connection_ref_count + + ;
2021-01-02 13:10:00 -05:00
memset ( connection , 0 , sizeof ( * connection ) ) ;
2022-11-02 19:34:44 -04:00
snprintf ( connection - > name , sizeof ( connection - > name ) , " cli%d " , s_connection_index + + ) ;
2021-01-02 13:10:00 -05:00
connection - > ssb = ssb ;
connection - > tcp . data = connection ;
connection - > connect . data = connection ;
connection - > send_request_number = 1 ;
snprintf ( connection - > host , sizeof ( connection - > host ) , " %s " , host ) ;
connection - > port = ntohs ( addr - > sin_port ) ;
2022-01-22 15:13:14 -05:00
connection - > async . data = connection ;
uv_async_init ( ssb - > loop , & connection - > async , _tf_ssb_connection_process_message_async ) ;
2021-01-02 13:10:00 -05:00
2021-09-06 13:50:38 -04:00
connection - > object = JS_NewObjectClass ( ssb - > context , _connection_class_id ) ;
2022-01-22 15:47:10 -05:00
JS_SetOpaque ( connection - > object , connection ) ;
2021-09-06 13:50:38 -04:00
char public_key_str [ k_id_base64_len ] = { 0 } ;
if ( tf_ssb_id_bin_to_str ( public_key_str , sizeof ( public_key_str ) , public_key ) )
{
JS_SetPropertyStr ( context , connection - > object , " id " , JS_NewString ( context , public_key_str ) ) ;
2021-12-27 14:52:42 -05:00
JS_SetPropertyStr ( context , connection - > object , " is_client " , JS_TRUE ) ;
2021-09-06 13:50:38 -04:00
}
2021-01-02 13:10:00 -05:00
memcpy ( connection - > serverpub , public_key , sizeof ( connection - > serverpub ) ) ;
uv_tcp_init ( ssb - > loop , & connection - > tcp ) ;
2022-01-19 23:01:45 -05:00
int result = uv_tcp_connect ( & connection - > connect , & connection - > tcp , ( const struct sockaddr * ) addr , _tf_ssb_connection_on_connect ) ;
if ( result )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " uv_tcp_connect(%s): %s \n " , host , uv_strerror ( result ) ) ;
2022-05-20 21:38:13 -04:00
connection - > connect . data = NULL ;
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " connect failed " ) ;
2022-01-19 23:01:45 -05:00
}
else
{
connection - > next = ssb - > connections ;
ssb - > connections = connection ;
ssb - > connections_count + + ;
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_create , connection ) ;
}
2021-01-02 13:10:00 -05:00
return connection ;
}
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_tunnel_callback (
2024-02-17 14:22:02 -05:00
tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , JSValue args , const uint8_t * message , size_t size , void * user_data )
2022-11-02 19:34:44 -04:00
{
tf_ssb_connection_t * tunnel = user_data ;
2023-08-20 14:25:15 -04:00
if ( flags & k_ssb_rpc_flag_end_error )
{
2024-05-02 19:02:23 -04:00
tf_ssb_connection_rpc_send ( connection , flags , - request_number , NULL , ( const uint8_t * ) " false " , strlen ( " false " ) , NULL , NULL , NULL ) ;
2023-08-20 14:25:15 -04:00
tf_ssb_connection_close ( tunnel ) ;
}
else
{
_tf_ssb_connection_on_tcp_recv_internal ( tunnel , message , size ) ;
}
2022-11-02 19:34:44 -04:00
}
2022-11-12 22:24:30 -05:00
tf_ssb_connection_t * tf_ssb_connection_tunnel_create ( tf_ssb_t * ssb , const char * portal_id , int32_t request_number , const char * target_id )
2022-11-02 19:34:44 -04:00
{
2022-11-12 22:24:30 -05:00
tf_ssb_connection_t * connection = tf_ssb_connection_get ( ssb , portal_id ) ;
2022-11-02 19:34:44 -04:00
JSContext * context = ssb - > context ;
tf_ssb_connection_t * tunnel = tf_malloc ( sizeof ( tf_ssb_connection_t ) ) ;
2024-02-06 12:42:17 -05:00
ssb - > connection_ref_count + + ;
2022-11-02 19:34:44 -04:00
memset ( tunnel , 0 , sizeof ( * tunnel ) ) ;
snprintf ( tunnel - > name , sizeof ( tunnel - > name ) , " tun%d " , s_tunnel_index + + ) ;
tunnel - > ssb = ssb ;
tunnel - > tunnel_connection = connection ;
tunnel - > tunnel_request_number = - request_number ;
tunnel - > send_request_number = 1 ;
tunnel - > async . data = tunnel ;
uv_async_init ( ssb - > loop , & tunnel - > async , _tf_ssb_connection_process_message_async ) ;
tunnel - > object = JS_NewObjectClass ( ssb - > context , _connection_class_id ) ;
JS_SetOpaque ( tunnel - > object , tunnel ) ;
JS_SetPropertyStr ( context , tunnel - > object , " id " , JS_NewString ( context , target_id ) ) ;
JS_SetPropertyStr ( context , tunnel - > object , " is_client " , JS_TRUE ) ;
tf_ssb_id_str_to_bin ( tunnel - > serverpub , target_id ) ;
tunnel - > next = ssb - > connections ;
ssb - > connections = tunnel ;
ssb - > connections_count + + ;
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_create , tunnel ) ;
2024-05-02 19:02:23 -04:00
tf_ssb_connection_add_request ( connection , request_number , " tunnel.connect " , _tf_ssb_connection_tunnel_callback , NULL , tunnel , tunnel ) ;
2022-11-13 17:30:09 -05:00
if ( request_number > 0 )
2022-11-02 19:34:44 -04:00
{
tunnel - > state = k_tf_ssb_state_connected ;
_tf_ssb_connection_client_send_hello ( tunnel ) ;
}
else
{
tunnel - > state = k_tf_ssb_state_server_wait_hello ;
}
return tunnel ;
}
2024-02-15 18:35:01 -05:00
typedef struct _connect_t
{
2021-01-02 13:10:00 -05:00
tf_ssb_t * ssb ;
uv_getaddrinfo_t req ;
char host [ 256 ] ;
int port ;
uint8_t key [ k_id_bin_len ] ;
} connect_t ;
static void _tf_on_connect_getaddrinfo ( uv_getaddrinfo_t * addrinfo , int result , struct addrinfo * info )
{
connect_t * connect = addrinfo - > data ;
2024-05-15 12:37:13 -04:00
if ( ! connect - > ssb - > shutting_down )
2021-10-10 17:51:38 -04:00
{
2024-05-15 12:37:13 -04:00
if ( result = = 0 & & info )
{
struct sockaddr_in addr = * ( struct sockaddr_in * ) info - > ai_addr ;
addr . sin_port = htons ( connect - > port ) ;
tf_ssb_connection_create ( connect - > ssb , connect - > host , & addr , connect - > key ) ;
}
else
{
tf_printf ( " getaddrinfo(%s) => %s \n " , connect - > host , uv_strerror ( result ) ) ;
}
2022-01-19 23:01:45 -05:00
}
2021-01-02 13:10:00 -05:00
uv_freeaddrinfo ( info ) ;
2024-05-15 12:37:13 -04:00
tf_ssb_unref ( connect - > ssb ) ;
tf_free ( connect ) ;
2021-01-02 13:10:00 -05:00
}
void tf_ssb_connect ( tf_ssb_t * ssb , const char * host , int port , const uint8_t * key )
{
2024-05-15 12:37:13 -04:00
if ( ssb - > shutting_down )
{
return ;
}
2022-06-04 13:04:51 -04:00
connect_t * connect = tf_malloc ( sizeof ( connect_t ) ) ;
2024-02-15 18:35:01 -05:00
* connect = ( connect_t ) {
2021-01-02 13:10:00 -05:00
. ssb = ssb ,
. port = port ,
. req . data = connect ,
} ;
2023-01-17 19:37:45 -05:00
char id [ k_id_base64_len ] = { 0 } ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , key ) ;
tf_ssb_connections_store ( ssb - > connections_tracker , host , port , id ) ;
2021-01-02 13:10:00 -05:00
snprintf ( connect - > host , sizeof ( connect - > host ) , " %s " , host ) ;
memcpy ( connect - > key , key , k_id_bin_len ) ;
2024-05-15 12:37:13 -04:00
tf_ssb_ref ( ssb ) ;
2021-01-02 13:10:00 -05:00
int r = uv_getaddrinfo ( ssb - > loop , & connect - > req , _tf_on_connect_getaddrinfo , host , NULL , & ( struct addrinfo ) { . ai_family = AF_INET } ) ;
2021-10-10 17:51:38 -04:00
if ( r < 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " uv_getaddrinfo: %s \n " , uv_strerror ( r ) ) ;
2022-06-04 13:04:51 -04:00
tf_free ( connect ) ;
2024-05-15 12:37:13 -04:00
tf_ssb_unref ( ssb ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-11-08 20:31:18 -05:00
void tf_ssb_connection_close ( tf_ssb_connection_t * connection )
{
_tf_ssb_connection_close ( connection , " tf_ssb_connection_close " ) ;
}
2021-10-10 17:51:38 -04:00
static void _tf_ssb_on_connection ( uv_stream_t * stream , int status )
{
2021-01-02 13:10:00 -05:00
tf_ssb_t * ssb = stream - > data ;
2021-10-10 17:51:38 -04:00
if ( status < 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " uv_listen failed: %s \n " , uv_strerror ( status ) ) ;
2021-01-02 13:10:00 -05:00
return ;
}
2022-06-04 13:04:51 -04:00
tf_ssb_connection_t * connection = tf_malloc ( sizeof ( tf_ssb_connection_t ) ) ;
2024-02-06 12:42:17 -05:00
ssb - > connection_ref_count + + ;
2021-01-02 13:10:00 -05:00
memset ( connection , 0 , sizeof ( * connection ) ) ;
2022-11-02 19:34:44 -04:00
snprintf ( connection - > name , sizeof ( connection - > name ) , " srv%d " , s_connection_index + + ) ;
2021-01-02 13:10:00 -05:00
connection - > ssb = ssb ;
connection - > tcp . data = connection ;
connection - > send_request_number = 1 ;
2022-01-22 15:13:14 -05:00
connection - > async . data = connection ;
uv_async_init ( ssb - > loop , & connection - > async , _tf_ssb_connection_process_message_async ) ;
2021-01-02 13:10:00 -05:00
2021-09-06 13:50:38 -04:00
connection - > object = JS_NewObjectClass ( ssb - > context , _connection_class_id ) ;
JS_SetOpaque ( connection - > object , connection ) ;
2021-10-10 17:51:38 -04:00
if ( uv_tcp_init ( ssb - > loop , & connection - > tcp ) ! = 0 )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " init failed " ) ;
2021-01-02 13:10:00 -05:00
return ;
}
2021-10-10 17:51:38 -04:00
if ( uv_accept ( stream , ( uv_stream_t * ) & connection - > tcp ) ! = 0 )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " accept failed " ) ;
2021-01-02 13:10:00 -05:00
return ;
}
2023-09-09 10:45:55 -04:00
struct sockaddr_storage addr = { 0 } ;
int size = sizeof ( addr ) ;
if ( uv_tcp_getpeername ( & connection - > tcp , ( struct sockaddr * ) & addr , & size ) = = 0 )
{
uv_ip_name ( ( struct sockaddr * ) & addr , connection - > host , sizeof ( connection - > host ) ) ;
connection - > port = ntohs ( ( ( struct sockaddr_in * ) & addr ) - > sin_port ) ;
}
2021-01-02 13:10:00 -05:00
connection - > next = ssb - > connections ;
ssb - > connections = connection ;
2022-01-12 20:08:17 -05:00
ssb - > connections_count + + ;
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_create , connection ) ;
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_server_wait_hello ;
2024-05-22 19:53:33 -04:00
_tf_ssb_connection_read_start ( connection ) ;
2021-01-02 13:10:00 -05:00
}
2023-03-17 21:26:34 -04:00
static void _tf_ssb_send_broadcast ( tf_ssb_t * ssb , struct sockaddr_in * address , struct sockaddr_in * netmask )
2021-01-02 13:10:00 -05:00
{
struct sockaddr server_addr ;
int len = ( int ) sizeof ( server_addr ) ;
2023-06-28 20:17:32 -04:00
int r = uv_tcp_getsockname ( & ssb - > server , & server_addr , & len ) ;
if ( r ! = 0 )
2021-10-10 17:51:38 -04:00
{
2023-06-28 20:17:32 -04:00
tf_printf ( " Unable to get server's address: %s. \n " , uv_strerror ( r ) ) ;
}
else if ( server_addr . sa_family ! = AF_INET )
{
tf_printf ( " Unexpected address family: %d \n " , server_addr . sa_family ) ;
2021-01-02 13:10:00 -05:00
}
char address_str [ 256 ] ;
2021-10-10 17:51:38 -04:00
if ( uv_ip4_name ( address , address_str , sizeof ( address_str ) ) ! = 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Unable to convert address to string. \n " ) ;
2021-01-02 13:10:00 -05:00
}
char fullid [ k_id_base64_len ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( ssb - > pub , sizeof ( ssb - > pub ) , fullid , sizeof ( fullid ) ) ;
2021-01-02 13:10:00 -05:00
char message [ 512 ] ;
snprintf ( message , sizeof ( message ) , " net:%s:%d~shs:%s " , address_str , ntohs ( ( ( struct sockaddr_in * ) & server_addr ) - > sin_port ) , fullid ) ;
uv_buf_t buf = { . base = message , . len = strlen ( message ) } ;
struct sockaddr_in broadcast_addr = { 0 } ;
broadcast_addr . sin_family = AF_INET ;
broadcast_addr . sin_port = htons ( 8008 ) ;
2024-02-15 18:35:01 -05:00
broadcast_addr . sin_addr . s_addr = ( address - > sin_addr . s_addr & netmask - > sin_addr . s_addr ) | ( INADDR_BROADCAST & ~ netmask - > sin_addr . s_addr ) ;
2023-06-28 20:17:32 -04:00
r = uv_udp_try_send ( & ssb - > broadcast_sender , & buf , 1 , ( struct sockaddr * ) & broadcast_addr ) ;
2021-10-10 17:51:38 -04:00
if ( r < 0 )
{
2023-04-29 23:18:12 -04:00
char broadcast_str [ 256 ] = { 0 } ;
uv_ip4_name ( & broadcast_addr , broadcast_str , sizeof ( broadcast_str ) ) ;
tf_printf ( " failed to send broadcast for %s via %s (%d): %s \n " , address_str , broadcast_str , r , uv_strerror ( r ) ) ;
2021-01-02 13:10:00 -05:00
}
}
2024-08-07 21:03:39 -04:00
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 } ;
2024-08-07 22:25:38 -04:00
int result = ares_init_options ( & channel , & options , ARES_OPT_EVENT_THREAD ) ;
if ( result = = ARES_SUCCESS )
2024-08-07 21:03:39 -04:00
{
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 ) ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_broadcast_timer ( uv_timer_t * timer )
{
tf_ssb_t * ssb = timer - > data ;
uv_interface_address_t * info = NULL ;
int count = 0 ;
2021-10-10 17:51:38 -04:00
if ( uv_interface_addresses ( & info , & count ) = = 0 )
{
for ( int i = 0 ; i < count ; i + + )
{
2024-02-15 18:35:01 -05:00
if ( ! info [ i ] . is_internal & & info [ i ] . address . address4 . sin_family = = AF_INET )
2021-10-10 17:51:38 -04:00
{
2023-03-17 21:26:34 -04:00
_tf_ssb_send_broadcast ( ssb , & info [ i ] . address . address4 , & info [ i ] . netmask . netmask4 ) ;
2021-01-02 13:10:00 -05:00
}
}
uv_free_interface_addresses ( info , count ) ;
}
2024-08-07 21:03:39 -04:00
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 ) ;
}
2021-01-02 13:10:00 -05:00
}
2024-03-07 21:03:14 -05:00
int tf_ssb_server_open ( tf_ssb_t * ssb , int port )
2021-01-02 13:10:00 -05:00
{
2021-10-10 17:51:38 -04:00
if ( ssb - > server . data )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Already listening. \n " ) ;
2024-03-07 21:03:14 -05:00
return 0 ;
2021-01-02 13:10:00 -05:00
}
ssb - > server . data = ssb ;
2021-10-10 17:51:38 -04:00
if ( uv_tcp_init ( ssb - > loop , & ssb - > server ) ! = 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " uv_tcp_init failed \n " ) ;
2024-03-07 21:03:14 -05:00
return 0 ;
2021-01-02 13:10:00 -05:00
}
struct sockaddr_in addr = { 0 } ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( port ) ;
addr . sin_addr . s_addr = INADDR_ANY ;
2024-03-04 21:51:27 -05:00
int status = uv_tcp_bind ( & ssb - > server , ( struct sockaddr * ) & addr , 0 ) ;
if ( status ! = 0 )
2021-10-10 17:51:38 -04:00
{
2024-03-04 21:51:27 -05:00
tf_printf ( " %s:%d: uv_tcp_bind failed: %s \n " , __FILE__ , __LINE__ , uv_strerror ( status ) ) ;
2024-03-07 21:03:14 -05:00
return 0 ;
2021-01-02 13:10:00 -05:00
}
2024-03-04 21:51:27 -05:00
status = uv_listen ( ( uv_stream_t * ) & ssb - > server , SOMAXCONN , _tf_ssb_on_connection ) ;
2021-10-10 17:51:38 -04:00
if ( status ! = 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " uv_listen failed: %s \n " , uv_strerror ( status ) ) ;
2021-01-02 13:10:00 -05:00
/* TODO: cleanup */
2024-03-07 21:03:14 -05:00
return 0 ;
2021-01-02 13:10:00 -05:00
}
2024-03-07 21:03:14 -05:00
struct sockaddr_storage name = { 0 } ;
int size = ( int ) sizeof ( name ) ;
status = uv_tcp_getsockname ( & ssb - > server , ( struct sockaddr * ) & name , & size ) ;
int assigned_port = ntohs ( ( ( struct sockaddr_in * ) & name ) - > sin_port ) ;
return status = = 0 ? assigned_port : 0 ;
2021-01-02 13:10:00 -05:00
}
void tf_ssb_server_close ( tf_ssb_t * ssb )
{
2021-10-10 17:51:38 -04:00
if ( ssb - > server . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > server ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > server , _tf_ssb_on_handle_close ) ;
}
uv_timer_stop ( & ssb - > broadcast_timer ) ;
2023-03-07 12:50:17 -05:00
tf_printf ( " Stopped broadcasts. \n " ) ;
2021-01-02 13:10:00 -05:00
}
bool tf_ssb_whoami ( tf_ssb_t * ssb , char * out_id , size_t out_id_size )
{
return tf_ssb_id_bin_to_str ( out_id , out_id_size , ssb - > pub ) ;
}
static bool _tf_ssb_parse_broadcast ( const char * in_broadcast , tf_ssb_broadcast_t * out_broadcast )
{
char public_key_str [ 45 ] = { 0 } ;
int port = 0 ;
static_assert ( sizeof ( out_broadcast - > host ) = = 256 , " host field size " ) ;
2022-11-08 21:15:07 -05:00
if ( sscanf ( in_broadcast , " net:%255[0-9A-Za-z.-]:%d~shs:%44s " , out_broadcast - > host , & port , public_key_str ) = = 3 )
2021-10-10 17:51:38 -04:00
{
2022-11-08 21:15:07 -05:00
out_broadcast - > addr . sin_family = AF_INET ;
out_broadcast - > addr . sin_port = htons ( ( uint16_t ) port ) ;
2023-02-13 22:15:24 -05:00
int r = tf_base64_decode ( public_key_str , strlen ( public_key_str ) , out_broadcast - > pub , crypto_sign_PUBLICKEYBYTES ) ;
2022-11-08 21:15:07 -05:00
return r ! = - 1 ;
2021-10-10 17:51:38 -04:00
}
2022-11-02 19:34:44 -04:00
else if ( strncmp ( in_broadcast , " ws: " , 3 ) = = 0 )
2021-10-10 17:51:38 -04:00
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Unsupported broadcast: %s \n " , in_broadcast ) ;
2021-01-02 13:10:00 -05:00
}
return false ;
}
void tf_ssb_connect_str ( tf_ssb_t * ssb , const char * address )
{
tf_ssb_broadcast_t broadcast = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_parse_broadcast ( address , & broadcast ) )
{
2022-11-08 21:15:07 -05:00
tf_ssb_connect ( ssb , broadcast . host , ntohs ( broadcast . addr . sin_port ) , broadcast . pub ) ;
2021-10-10 17:51:38 -04:00
}
else
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Unable to parse: %s \n " , address ) ;
2021-01-02 13:10:00 -05:00
}
}
static void _tf_ssb_on_broadcast_listener_alloc ( uv_handle_t * handle , size_t suggested_size , uv_buf_t * buf )
{
2022-06-04 13:04:51 -04:00
buf - > base = tf_malloc ( suggested_size ) ;
2022-02-05 14:58:22 -05:00
buf - > len = suggested_size ;
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
static void _tf_ssb_notify_broadcasts_changed ( tf_ssb_t * ssb )
{
2021-12-27 17:28:27 -05:00
tf_ssb_broadcasts_changed_callback_node_t * next = NULL ;
for ( tf_ssb_broadcasts_changed_callback_node_t * node = ssb - > broadcasts_changed ; node ; node = next )
2021-11-07 17:28:58 -05:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2021-11-07 17:28:58 -05:00
if ( node - > callback )
{
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " broadcasts changed " ) ;
2021-11-07 17:28:58 -05:00
node - > callback ( ssb , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-11-07 17:28:58 -05:00
}
}
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_add_broadcast ( tf_ssb_t * ssb , const tf_ssb_broadcast_t * broadcast )
{
2021-10-10 17:51:38 -04:00
if ( memcmp ( broadcast - > pub , ssb - > pub , sizeof ( ssb - > pub ) ) = = 0 )
{
2021-01-02 13:10:00 -05:00
return ;
}
2022-11-02 19:34:44 -04:00
if ( broadcast - > tunnel_connection )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = node - > next )
2021-10-10 17:51:38 -04:00
{
2024-02-15 18:35:01 -05:00
if ( node - > tunnel_connection = = broadcast - > tunnel_connection & & memcmp ( node - > pub , broadcast - > pub , sizeof ( node - > pub ) ) = = 0 )
2022-11-02 19:34:44 -04:00
{
node - > mtime = time ( NULL ) ;
return ;
}
2021-01-02 13:10:00 -05:00
}
}
2022-11-02 19:34:44 -04:00
else
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = node - > next )
{
2024-02-15 18:35:01 -05:00
if ( node - > addr . sin_family = = broadcast - > addr . sin_family & & node - > addr . sin_port = = broadcast - > addr . sin_port & &
2024-02-17 14:22:02 -05:00
node - > addr . sin_addr . s_addr = = broadcast - > addr . sin_addr . s_addr & & memcmp ( node - > pub , broadcast - > pub , sizeof ( node - > pub ) ) = = 0 )
2022-11-02 19:34:44 -04:00
{
node - > mtime = time ( NULL ) ;
return ;
}
}
char key [ k_id_base64_len ] ;
if ( tf_ssb_id_bin_to_str ( key , sizeof ( key ) , broadcast - > pub ) )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " Received new broadcast: host=%s, pub=%s. \n " , broadcast - > host , key ) ;
2022-11-02 19:34:44 -04:00
}
2021-01-02 13:10:00 -05:00
}
2022-06-04 13:04:51 -04:00
tf_ssb_broadcast_t * node = tf_malloc ( sizeof ( tf_ssb_broadcast_t ) ) ;
2021-01-02 13:10:00 -05:00
* node = * broadcast ;
node - > next = ssb - > broadcasts ;
node - > ctime = time ( NULL ) ;
node - > mtime = node - > ctime ;
ssb - > broadcasts = node ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_count + + ;
2021-01-02 13:10:00 -05:00
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_broadcasts_changed ( ssb ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_on_broadcast_listener_recv ( uv_udp_t * handle , ssize_t nread , const uv_buf_t * buf , const struct sockaddr * addr , unsigned flags )
{
2021-10-10 17:51:38 -04:00
if ( nread < = 0 )
{
2022-06-04 13:04:51 -04:00
tf_free ( buf - > base ) ;
2021-01-02 13:10:00 -05:00
return ;
}
tf_ssb_t * ssb = handle - > data ;
( ( char * ) buf - > base ) [ nread ] = ' \0 ' ;
const char * k_delim = " ; " ;
char * state = NULL ;
char * entry = strtok_r ( buf - > base , k_delim , & state ) ;
2021-10-10 17:51:38 -04:00
while ( entry )
{
2021-01-02 13:10:00 -05:00
tf_ssb_broadcast_t broadcast = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_parse_broadcast ( entry , & broadcast ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_add_broadcast ( ssb , & broadcast ) ;
}
entry = strtok_r ( NULL , k_delim , & state ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( buf - > base ) ;
2021-01-02 13:10:00 -05:00
}
2024-02-15 18:35:01 -05:00
void tf_ssb_visit_broadcasts (
2024-02-17 14:22:02 -05:00
tf_ssb_t * ssb , void ( * callback ) ( const char * host , const struct sockaddr_in * addr , tf_ssb_connection_t * tunnel , const uint8_t * pub , void * user_data ) , void * user_data )
2021-01-02 13:10:00 -05:00
{
time_t now = time ( NULL ) ;
2021-12-27 17:28:27 -05:00
tf_ssb_broadcast_t * next = NULL ;
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = next )
2021-10-10 17:51:38 -04:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2021-10-10 17:51:38 -04:00
if ( node - > mtime - now < 60 )
{
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " broadcast " ) ;
2022-11-08 22:51:31 -05:00
callback ( node - > host , & node - > addr , node - > tunnel_connection , node - > pub , user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-01-02 13:10:00 -05:00
}
}
}
2022-01-19 22:35:03 -05:00
static void _tf_ssb_broadcast_cleanup_timer ( uv_timer_t * timer )
{
tf_ssb_t * ssb = timer - > data ;
int modified = 0 ;
time_t now = time ( NULL ) ;
for ( tf_ssb_broadcast_t * * it = & ssb - > broadcasts ; * it ; )
{
2022-11-08 19:37:51 -05:00
if ( ! ( * it ) - > tunnel_connection & & ( * it ) - > mtime < now - 10 )
2022-01-19 22:35:03 -05:00
{
tf_ssb_broadcast_t * node = * it ;
* it = node - > next ;
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2022-01-19 22:35:03 -05:00
ssb - > broadcasts_count - - ;
modified + + ;
}
else
{
it = & ( * it ) - > next ;
}
}
if ( modified )
{
_tf_ssb_notify_broadcasts_changed ( ssb ) ;
}
}
2021-01-02 13:10:00 -05:00
void tf_ssb_broadcast_listener_start ( tf_ssb_t * ssb , bool linger )
{
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_listener . data )
{
2021-01-02 13:10:00 -05:00
return ;
}
ssb - > broadcast_listener . data = ssb ;
uv_udp_init ( ssb - > loop , & ssb - > broadcast_listener ) ;
struct sockaddr_in addr = { 0 } ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( 8008 ) ;
addr . sin_addr . s_addr = INADDR_ANY ;
int result = uv_udp_bind ( & ssb - > broadcast_listener , ( const struct sockaddr * ) & addr , UV_UDP_REUSEADDR ) ;
2021-10-10 17:51:38 -04:00
if ( result ! = 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " bind: %s \n " , uv_strerror ( result ) ) ;
2021-01-02 13:10:00 -05:00
}
result = uv_udp_recv_start ( & ssb - > broadcast_listener , _tf_ssb_on_broadcast_listener_alloc , _tf_ssb_on_broadcast_listener_recv ) ;
2021-10-10 17:51:38 -04:00
if ( result ! = 0 )
{
2023-03-07 12:50:17 -05:00
tf_printf ( " uv_udp_recv_start: %s \n " , uv_strerror ( result ) ) ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
if ( ! linger )
{
2021-01-02 13:10:00 -05:00
uv_unref ( ( uv_handle_t * ) & ssb - > broadcast_listener ) ;
}
2022-01-19 22:35:03 -05:00
ssb - > broadcast_cleanup_timer . data = ssb ;
uv_timer_init ( ssb - > loop , & ssb - > broadcast_cleanup_timer ) ;
uv_timer_start ( & ssb - > broadcast_cleanup_timer , _tf_ssb_broadcast_cleanup_timer , 2000 , 2000 ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-08 08:48:28 -05:00
void tf_ssb_broadcast_sender_start ( tf_ssb_t * ssb )
{
if ( ssb - > broadcast_sender . data )
{
return ;
}
ssb - > broadcast_sender . data = ssb ;
uv_udp_init ( ssb - > loop , & ssb - > broadcast_sender ) ;
2024-02-15 18:35:01 -05:00
struct sockaddr_in broadcast_from = {
2023-01-08 08:48:28 -05:00
. sin_family = AF_INET ,
. sin_addr . s_addr = INADDR_ANY ,
} ;
uv_udp_bind ( & ssb - > broadcast_sender , ( struct sockaddr * ) & broadcast_from , 0 ) ;
uv_udp_set_broadcast ( & ssb - > broadcast_sender , 1 ) ;
2023-04-29 23:18:12 -04:00
tf_printf ( " Starting broadcasts. \n " ) ;
uv_timer_start ( & ssb - > broadcast_timer , _tf_ssb_broadcast_timer , 2000 , 2000 ) ;
2023-01-08 08:48:28 -05:00
}
2022-11-02 19:34:44 -04:00
tf_ssb_connection_t * tf_ssb_connection_get ( tf_ssb_t * ssb , const char * id )
{
uint8_t pub [ k_id_bin_len ] = { 0 } ;
tf_ssb_id_str_to_bin ( pub , id ) ;
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2023-08-20 14:25:15 -04:00
if ( connection - > tunnel_connection )
{
continue ;
}
2022-11-02 19:34:44 -04:00
if ( memcmp ( connection - > serverpub , pub , k_id_bin_len ) = = 0 )
{
return connection ;
}
else if ( memcmp ( ssb - > pub , pub , k_id_bin_len ) = = 0 )
{
return connection ;
}
}
return NULL ;
}
2021-01-02 13:10:00 -05:00
const char * * tf_ssb_get_connection_ids ( tf_ssb_t * ssb )
{
int count = 0 ;
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
if ( connection - > state = = k_tf_ssb_state_verified | | connection - > state = = k_tf_ssb_state_server_verified )
{
2021-01-02 13:10:00 -05:00
count + + ;
}
}
2022-06-04 13:04:51 -04:00
char * buffer = tf_malloc ( sizeof ( char * ) * ( count + 1 ) + k_id_base64_len * count ) ;
2021-01-02 13:10:00 -05:00
char * * array = ( char * * ) buffer ;
char * strings = buffer + sizeof ( char * ) * ( count + 1 ) ;
int i = 0 ;
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
if ( connection - > state = = k_tf_ssb_state_verified | | connection - > state = = k_tf_ssb_state_server_verified )
{
2021-01-02 13:10:00 -05:00
char * write_pos = strings + k_id_base64_len * i ;
tf_ssb_id_bin_to_str ( write_pos , k_id_base64_len , connection - > serverpub ) ;
array [ i + + ] = write_pos ;
}
}
array [ i ] = NULL ;
return ( const char * * ) array ;
}
int tf_ssb_get_connections ( tf_ssb_t * ssb , tf_ssb_connection_t * * out_connections , int out_connections_count )
{
int i = 0 ;
2024-02-15 18:35:01 -05:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection & & i < out_connections_count ; connection = connection - > next )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
out_connections [ i + + ] = connection ;
}
return i ;
}
2021-11-07 17:28:58 -05:00
void tf_ssb_add_broadcasts_changed_callback ( tf_ssb_t * ssb , tf_ssb_broadcasts_changed_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
{
2022-06-04 13:04:51 -04:00
tf_ssb_broadcasts_changed_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_broadcasts_changed_callback_node_t ) ) ;
2024-02-15 18:35:01 -05:00
* node = ( tf_ssb_broadcasts_changed_callback_node_t ) {
2021-11-07 17:28:58 -05:00
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > broadcasts_changed ,
} ;
ssb - > broadcasts_changed = node ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_changed_count + + ;
2021-11-07 17:28:58 -05:00
}
void tf_ssb_remove_broadcasts_changed_callback ( tf_ssb_t * ssb , tf_ssb_broadcasts_changed_callback_t * callback , void * user_data )
2021-01-02 13:10:00 -05:00
{
2021-11-07 17:28:58 -05:00
tf_ssb_broadcasts_changed_callback_node_t * * it = & ssb - > broadcasts_changed ;
while ( * it )
{
2024-02-15 18:35:01 -05:00
if ( ( * it ) - > callback = = callback & & ( * it ) - > user_data = = user_data )
2021-11-07 17:28:58 -05:00
{
tf_ssb_broadcasts_changed_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-07 17:28:58 -05:00
}
}
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_add_connections_changed_callback ( tf_ssb_t * ssb , tf_ssb_connections_changed_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2021-01-02 13:10:00 -05:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_connections_changed_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_connections_changed_callback_node_t ) ) ;
2024-02-15 18:35:01 -05:00
* node = ( tf_ssb_connections_changed_callback_node_t ) {
2021-11-07 17:28:58 -05:00
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > connections_changed ,
} ;
ssb - > connections_changed = node ;
2022-01-12 20:08:17 -05:00
ssb - > connections_changed_count + + ;
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_remove_connections_changed_callback ( tf_ssb_t * ssb , tf_ssb_connections_changed_callback_t * callback , void * user_data )
{
tf_ssb_connections_changed_callback_node_t * * it = & ssb - > connections_changed ;
while ( * it )
{
2024-02-15 18:35:01 -05:00
if ( ( * it ) - > callback = = callback & & ( * it ) - > user_data = = user_data )
2021-11-07 17:28:58 -05:00
{
tf_ssb_connections_changed_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > connections_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-07 17:28:58 -05:00
}
}
}
void tf_ssb_add_rpc_callback ( tf_ssb_t * ssb , const char * * name , tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2021-01-02 13:10:00 -05:00
{
size_t name_len = 0 ;
int name_count = 0 ;
2021-10-10 17:51:38 -04:00
for ( int i = 0 ; name [ i ] ; i + + )
{
2021-01-02 13:10:00 -05:00
name_count + + ;
name_len + = strlen ( name [ i ] ) + 1 ;
}
2024-02-15 18:35:01 -05:00
tf_ssb_rpc_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_rpc_callback_node_t ) + ( name_count + 1 ) * sizeof ( const char * ) + name_len + name_len + 3 ) ;
* node = ( tf_ssb_rpc_callback_node_t ) {
2021-01-02 13:10:00 -05:00
. name = ( const char * * ) ( node + 1 ) ,
2023-02-03 10:06:18 -05:00
. flattened_name = ( const char * ) ( node + 1 ) + ( name_count + 1 ) * sizeof ( const char * ) + name_len ,
2021-01-02 13:10:00 -05:00
. callback = callback ,
2021-09-06 13:50:38 -04:00
. cleanup = cleanup ,
2021-01-02 13:10:00 -05:00
. user_data = user_data ,
. next = ssb - > rpc ,
} ;
char * p = ( char * ) ( node + 1 ) + ( name_count + 1 ) * sizeof ( const char * ) ;
2021-10-10 17:51:38 -04:00
for ( int i = 0 ; i < name_count ; i + + )
{
2021-01-02 13:10:00 -05:00
size_t len = strlen ( name [ i ] ) ;
memcpy ( p , name [ i ] , len + 1 ) ;
node - > name [ i ] = p ;
p + = len + 1 ;
}
2023-02-03 10:06:18 -05:00
char * flattened_name = ( char * ) node - > flattened_name ;
for ( int i = 0 ; i < name_count ; i + + )
{
size_t length = strlen ( name [ i ] ) ;
memcpy ( flattened_name , name [ i ] , length ) ;
flattened_name + = length ;
if ( i ! = name_count - 1 )
{
* flattened_name + + = ' . ' ;
}
}
* flattened_name + + = ' ( ' ;
* flattened_name + + = ' ) ' ;
* flattened_name + + = ' \0 ' ;
2021-01-02 13:10:00 -05:00
node - > name [ name_count ] = NULL ;
ssb - > rpc = node ;
2022-01-12 20:08:17 -05:00
ssb - > rpc_count + + ;
2021-01-02 13:10:00 -05:00
}
JSContext * tf_ssb_connection_get_context ( tf_ssb_connection_t * connection )
{
return connection - > ssb - > context ;
}
tf_ssb_t * tf_ssb_connection_get_ssb ( tf_ssb_connection_t * connection )
{
return connection - > ssb ;
}
int32_t tf_ssb_connection_next_request_number ( tf_ssb_connection_t * connection )
{
return connection - > send_request_number + + ;
}
2021-09-06 13:50:38 -04:00
JSClassID tf_ssb_get_connection_class_id ( )
{
return _connection_class_id ;
}
JSValue tf_ssb_connection_get_object ( tf_ssb_connection_t * connection )
{
return connection ? connection - > object : JS_UNDEFINED ;
}
2024-02-15 18:35:01 -05:00
void tf_ssb_add_message_added_callback (
2024-02-17 14:22:02 -05:00
tf_ssb_t * ssb , void ( * callback ) ( tf_ssb_t * ssb , const char * id , void * user_data ) , void ( * cleanup ) ( tf_ssb_t * ssb , void * user_data ) , void * user_data )
2021-11-10 19:05:07 -05:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_message_added_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_message_added_callback_node_t ) ) ;
2024-02-15 18:35:01 -05:00
* node = ( tf_ssb_message_added_callback_node_t ) {
2021-11-10 19:05:07 -05:00
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > message_added ,
} ;
ssb - > message_added = node ;
2022-01-12 20:08:17 -05:00
ssb - > message_added_count + + ;
2021-11-10 19:05:07 -05:00
}
void tf_ssb_remove_message_added_callback ( tf_ssb_t * ssb , tf_ssb_message_added_callback_t * callback , void * user_data )
{
tf_ssb_message_added_callback_node_t * * it = & ssb - > message_added ;
while ( * it )
{
2024-02-15 18:35:01 -05:00
if ( ( * it ) - > callback = = callback & & ( * it ) - > user_data = = user_data )
2021-11-10 19:05:07 -05:00
{
tf_ssb_message_added_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > message_added_count - - ;
2021-11-10 19:05:07 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-10 19:05:07 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-10 19:05:07 -05:00
}
}
}
2023-01-18 17:52:54 -05:00
void tf_ssb_notify_blob_stored ( tf_ssb_t * ssb , const char * id )
{
ssb - > blobs_stored + + ;
}
2023-10-08 09:52:49 -04:00
void tf_ssb_notify_message_added ( tf_ssb_t * ssb , const char * id , JSValue message_keys )
2021-11-10 19:05:07 -05:00
{
2021-12-27 17:28:27 -05:00
tf_ssb_message_added_callback_node_t * next = NULL ;
2022-02-05 15:18:58 -05:00
ssb - > messages_stored + + ;
2021-12-27 17:28:27 -05:00
for ( tf_ssb_message_added_callback_node_t * node = ssb - > message_added ; node ; node = next )
2021-11-10 19:05:07 -05:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " message added callback " ) ;
2021-11-10 19:05:07 -05:00
node - > callback ( ssb , id , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-11-10 19:05:07 -05:00
}
2023-01-08 12:45:15 -05:00
JSContext * context = ssb - > context ;
2023-10-08 09:52:49 -04:00
if ( ! JS_IsUndefined ( message_keys ) )
2023-01-08 12:45:15 -05:00
{
2023-10-08 09:52:49 -04:00
JSValue message = JS_GetPropertyStr ( context , message_keys , " value " ) ;
2023-01-08 12:45:15 -05:00
JSValue author = JS_GetPropertyStr ( context , message , " author " ) ;
const char * author_string = JS_ToCString ( context , author ) ;
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2023-06-17 10:05:23 -04:00
if ( ! connection - > message_requests_count )
{
continue ;
}
2024-02-17 14:22:02 -05:00
tf_ssb_connection_message_request_t * message_request =
bsearch ( author_string , connection - > message_requests , connection - > message_requests_count , sizeof ( tf_ssb_connection_message_request_t ) , _message_request_compare ) ;
2023-01-08 12:45:15 -05:00
if ( message_request )
{
tf_ssb_connection_rpc_send_json (
2024-05-02 19:02:23 -04:00
connection , k_ssb_rpc_flag_stream , message_request - > request_number , NULL , message_request - > keys ? message_keys : message , NULL , NULL , NULL ) ;
2023-01-08 12:45:15 -05:00
}
}
JS_FreeCString ( context , author_string ) ;
JS_FreeValue ( context , author ) ;
2023-10-08 09:52:49 -04:00
JS_FreeValue ( context , message ) ;
2023-01-08 12:45:15 -05:00
}
2021-11-10 19:05:07 -05:00
}
2024-02-15 18:35:01 -05:00
void tf_ssb_add_blob_want_added_callback (
2024-02-17 14:22:02 -05:00
tf_ssb_t * ssb , void ( * callback ) ( tf_ssb_t * ssb , const char * id , void * user_data ) , void ( * cleanup ) ( tf_ssb_t * ssb , void * user_data ) , void * user_data )
2021-09-06 13:50:38 -04:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_blob_want_added_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_blob_want_added_callback_node_t ) ) ;
2024-02-15 18:35:01 -05:00
* node = ( tf_ssb_blob_want_added_callback_node_t ) {
2021-09-06 13:50:38 -04:00
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > blob_want_added ,
} ;
ssb - > blob_want_added = node ;
2022-01-12 20:08:17 -05:00
ssb - > blob_want_added_count + + ;
2021-09-06 13:50:38 -04:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_remove_blob_want_added_callback ( tf_ssb_t * ssb , tf_ssb_blob_want_added_callback_t * callback , void * user_data )
{
tf_ssb_blob_want_added_callback_node_t * * it = & ssb - > blob_want_added ;
while ( * it )
{
2024-02-15 18:35:01 -05:00
if ( ( * it ) - > callback = = callback & & ( * it ) - > user_data = = user_data )
2021-11-07 17:28:58 -05:00
{
tf_ssb_blob_want_added_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > blob_want_added_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-07 17:28:58 -05:00
}
}
}
2021-09-06 13:50:38 -04:00
void tf_ssb_notify_blob_want_added ( tf_ssb_t * ssb , const char * id )
{
2021-12-27 17:28:27 -05:00
tf_ssb_blob_want_added_callback_node_t * next = NULL ;
for ( tf_ssb_blob_want_added_callback_node_t * node = ssb - > blob_want_added ; node ; node = next )
2021-09-06 13:50:38 -04:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " blob want added callback " ) ;
2021-09-06 13:50:38 -04:00
node - > callback ( ssb , id , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-09-06 13:50:38 -04:00
}
}
2022-11-02 19:34:44 -04:00
void tf_ssb_connection_add_room_attendant ( tf_ssb_connection_t * connection , const char * id )
{
2024-02-15 18:35:01 -05:00
tf_ssb_broadcast_t broadcast = {
2022-11-02 19:34:44 -04:00
. tunnel_connection = connection ,
} ;
tf_ssb_id_str_to_bin ( broadcast . pub , id ) ;
_tf_ssb_add_broadcast ( connection - > ssb , & broadcast ) ;
}
void tf_ssb_connection_remove_room_attendant ( tf_ssb_connection_t * connection , const char * id )
{
uint8_t pub [ k_id_bin_len ] = { 0 } ;
tf_ssb_id_str_to_bin ( pub , id ) ;
int modified = 0 ;
for ( tf_ssb_broadcast_t * * it = & connection - > ssb - > broadcasts ; * it ; )
{
2024-02-15 18:35:01 -05:00
if ( ( * it ) - > tunnel_connection = = connection & & memcmp ( ( * it ) - > pub , pub , k_id_bin_len ) = = 0 )
2022-11-02 19:34:44 -04:00
{
tf_ssb_broadcast_t * node = * it ;
* it = node - > next ;
tf_free ( node ) ;
connection - > ssb - > broadcasts_count - - ;
modified + + ;
}
else
{
it = & ( * it ) - > next ;
}
}
if ( modified )
{
_tf_ssb_notify_broadcasts_changed ( connection - > ssb ) ;
}
}
2023-01-04 19:52:23 -05:00
2023-01-07 19:25:38 -05:00
bool tf_ssb_connection_is_attendant ( tf_ssb_connection_t * connection )
{
return connection - > is_attendant ;
}
int32_t tf_ssb_connection_get_attendant_request_number ( tf_ssb_connection_t * connection )
{
return connection - > attendant_request_number ;
}
void tf_ssb_connection_set_attendant ( tf_ssb_connection_t * connection , bool attendant , int request_number )
{
connection - > is_attendant = attendant ;
connection - > attendant_request_number = request_number ;
_tf_ssb_notify_broadcasts_changed ( connection - > ssb ) ;
}
void tf_ssb_connection_clear_room_attendants ( tf_ssb_connection_t * connection )
{
int modified = 0 ;
for ( tf_ssb_broadcast_t * * it = & connection - > ssb - > broadcasts ; * it ; )
{
if ( ( * it ) - > tunnel_connection = = connection )
{
tf_ssb_broadcast_t * node = * it ;
* it = node - > next ;
tf_free ( node ) ;
connection - > ssb - > broadcasts_count - - ;
modified + + ;
}
else
{
it = & ( * it ) - > next ;
}
}
if ( modified )
{
_tf_ssb_notify_broadcasts_changed ( connection - > ssb ) ;
}
}
2023-01-04 19:52:23 -05:00
tf_ssb_blob_wants_t * tf_ssb_connection_get_blob_wants_state ( tf_ssb_connection_t * connection )
{
return connection ? & connection - > blob_wants : NULL ;
}
2023-01-08 15:01:35 -05:00
2023-07-19 21:02:50 -04:00
typedef struct _store_t
{
tf_ssb_t * ssb ;
2024-01-10 20:38:30 -05:00
tf_ssb_verify_strip_store_callback_t * callback ;
void * user_data ;
2023-07-19 21:02:50 -04:00
bool verified ;
bool stored ;
char id [ crypto_hash_sha256_BYTES * 2 + 1 ] ;
} store_t ;
static void _tf_ssb_verify_strip_and_store_finish ( store_t * store )
{
if ( store - > callback )
{
store - > callback ( store - > id , store - > verified , store - > stored , store - > user_data ) ;
}
tf_free ( store ) ;
}
static void _tf_ssb_verify_strip_and_store_callback ( const char * id , bool stored , void * user_data )
{
store_t * store = user_data ;
store - > stored = stored ;
_tf_ssb_verify_strip_and_store_finish ( store ) ;
}
void tf_ssb_verify_strip_and_store_message ( tf_ssb_t * ssb , JSValue value , tf_ssb_verify_strip_store_callback_t * callback , void * user_data )
2023-01-08 15:01:35 -05:00
{
JSContext * context = tf_ssb_get_context ( ssb ) ;
2023-07-19 21:02:50 -04:00
store_t * async = tf_malloc ( sizeof ( store_t ) ) ;
2024-02-15 18:35:01 -05:00
* async = ( store_t ) {
2023-07-19 21:02:50 -04:00
. ssb = ssb ,
. callback = callback ,
. user_data = user_data ,
} ;
2023-01-13 19:55:51 -05:00
char signature [ crypto_sign_BYTES + 128 ] = { 0 } ;
2024-03-13 19:40:09 -04:00
int flags = 0 ;
if ( tf_ssb_verify_and_strip_signature ( context , value , async - > id , sizeof ( async - > id ) , signature , sizeof ( signature ) , & flags ) )
2023-05-10 20:22:42 -04:00
{
2023-07-19 21:02:50 -04:00
async - > verified = true ;
2024-03-13 19:40:09 -04:00
tf_ssb_db_store_message ( ssb , context , async - > id , value , signature , flags , _tf_ssb_verify_strip_and_store_callback , async ) ;
2023-01-08 15:01:35 -05:00
}
else
{
2023-07-19 21:02:50 -04:00
_tf_ssb_verify_strip_and_store_finish ( async ) ;
2023-01-08 15:01:35 -05:00
}
}
bool tf_ssb_connection_get_sent_clock ( tf_ssb_connection_t * connection )
{
return connection - > sent_clock ;
}
void tf_ssb_connection_set_sent_clock ( tf_ssb_connection_t * connection , bool sent_clock )
{
connection - > sent_clock = sent_clock ;
}
int32_t tf_ssb_connection_get_ebt_request_number ( tf_ssb_connection_t * connection )
{
return connection - > ebt_request_number ;
}
void tf_ssb_connection_set_ebt_request_number ( tf_ssb_connection_t * connection , int32_t request_number )
{
connection - > ebt_request_number = request_number ;
}
2023-01-22 15:37:19 -05:00
JSValue tf_ssb_get_disconnection_debug ( tf_ssb_t * ssb , JSContext * context )
{
JSValue result = JS_NewObject ( context ) ;
JSValue disconnections = JS_NewArray ( context ) ;
for ( int i = 0 ; i < k_debug_close_connection_count ; i + + )
{
JSValue disconnection = JS_NewObject ( context ) ;
if ( * ssb - > debug_close [ i ] . id )
{
JS_SetPropertyStr ( context , disconnection , " id " , JS_NewString ( context , ssb - > debug_close [ i ] . id ) ) ;
if ( * ssb - > debug_close [ i ] . tunnel )
{
JS_SetPropertyStr ( context , disconnection , " tunnel " , JS_NewString ( context , ssb - > debug_close [ i ] . tunnel ) ) ;
}
JS_SetPropertyStr ( context , disconnection , " reason " , JS_NewString ( context , ssb - > debug_close [ i ] . reason ) ) ;
JSValue messages = JS_NewArray ( context ) ;
for ( int j = 0 ; j < k_debug_close_message_count ; j + + )
{
if ( ssb - > debug_close [ i ] . messages [ j ] )
{
JSValue message = JS_NewObject ( context ) ;
JS_SetPropertyStr ( context , message , " direction " , JS_NewString ( context , ssb - > debug_close [ i ] . messages [ j ] - > outgoing ? " out " : " in " ) ) ;
JS_SetPropertyStr ( context , message , " flags " , JS_NewInt32 ( context , ssb - > debug_close [ i ] . messages [ j ] - > flags ) ) ;
JS_SetPropertyStr ( context , message , " request_number " , JS_NewInt32 ( context , ssb - > debug_close [ i ] . messages [ j ] - > request_number ) ) ;
2023-08-20 14:36:46 -04:00
JS_SetPropertyStr ( context , message , " timestamp " , JS_NewFloat64 ( context , ssb - > debug_close [ i ] . messages [ j ] - > timestamp ) ) ;
2024-02-17 14:22:02 -05:00
JS_SetPropertyStr (
context , message , " payload " , JS_NewStringLen ( context , ( const char * ) ssb - > debug_close [ i ] . messages [ j ] - > data , ssb - > debug_close [ i ] . messages [ j ] - > size ) ) ;
2023-01-22 15:37:19 -05:00
JS_SetPropertyUint32 ( context , messages , j , message ) ;
}
}
JS_SetPropertyStr ( context , disconnection , " messages " , messages ) ;
}
JS_SetPropertyUint32 ( context , disconnections , i , disconnection ) ;
}
JS_SetPropertyStr ( context , result , " disconnections " , disconnections ) ;
return result ;
}
2023-02-28 20:36:26 -05:00
2023-08-16 20:01:59 -04:00
void tf_ssb_record_thread_busy ( tf_ssb_t * ssb , bool busy )
2023-02-28 20:36:26 -05:00
{
2023-08-16 20:01:59 -04:00
int32_t busy_value = __atomic_add_fetch ( & ssb - > thread_busy_count , busy ? 1 : - 1 , __ATOMIC_RELAXED ) ;
int32_t current = ssb - > thread_busy_max ;
while ( busy_value > current & & ! __atomic_compare_exchange_n ( & ssb - > thread_busy_max , & current , busy_value , false , __ATOMIC_RELAXED , __ATOMIC_RELAXED ) )
2023-02-28 20:36:26 -05:00
{
2023-08-16 20:01:59 -04:00
current = ssb - > thread_busy_max ;
2023-02-28 20:36:26 -05:00
}
}
2023-08-16 20:01:59 -04:00
float tf_ssb_get_average_thread_percent ( tf_ssb_t * ssb )
2023-02-28 20:36:26 -05:00
{
2023-08-16 20:01:59 -04:00
if ( ! ssb | | ! ssb - > thread_busy_max )
2023-02-28 20:36:26 -05:00
{
2023-08-16 20:01:59 -04:00
return 0.0f ;
2023-02-28 20:36:26 -05:00
}
2023-08-16 20:01:59 -04:00
return 100.0f * ssb - > thread_busy_count / ssb - > thread_busy_max ;
2023-02-28 20:36:26 -05:00
}
2023-04-19 19:05:59 -04:00
void tf_ssb_set_hitch_callback ( tf_ssb_t * ssb , void ( * callback ) ( const char * name , uint64_t duration_ns , void * user_data ) , void * user_data )
{
ssb - > hitch_callback = callback ;
ssb - > hitch_user_data = user_data ;
}
2023-07-19 21:02:50 -04:00
tf_ssb_store_queue_t * tf_ssb_get_store_queue ( tf_ssb_t * ssb )
{
return & ssb - > store_queue ;
}
2023-08-02 20:30:48 -04:00
void tf_ssb_ref ( tf_ssb_t * ssb )
{
ssb - > ref_count + + ;
}
void tf_ssb_unref ( tf_ssb_t * ssb )
{
2024-06-17 21:23:48 -04:00
int new_count = - - ssb - > ref_count ;
if ( new_count < 0 )
{
tf_printf ( " tf_ssb_unref past 0: %d \n " , new_count ) ;
abort ( ) ;
}
2023-08-02 20:30:48 -04:00
}
2023-10-08 10:25:22 -04:00
2023-10-11 11:44:40 -04:00
void tf_ssb_set_main_thread ( tf_ssb_t * ssb , bool main_thread )
2023-10-08 10:25:22 -04:00
{
2023-10-11 11:44:40 -04:00
ssb - > thread_self = main_thread ? uv_thread_self ( ) : 0 ;
2023-10-08 10:25:22 -04:00
}
2023-10-08 11:14:42 -04:00
typedef struct _connection_work_t
{
uv_work_t work ;
tf_ssb_connection_t * connection ;
2024-05-08 21:00:37 -04:00
const char * name ;
const char * after_name ;
2023-10-08 11:14:42 -04:00
void ( * work_callback ) ( tf_ssb_connection_t * connection , void * user_data ) ;
void ( * after_work_callback ) ( tf_ssb_connection_t * connection , int result , void * user_data ) ;
void * user_data ;
} connection_work_t ;
static void _tf_ssb_connection_work_callback ( uv_work_t * work )
{
connection_work_t * data = work - > data ;
tf_ssb_record_thread_busy ( data - > connection - > ssb , true ) ;
if ( data - > work_callback )
{
2024-05-08 21:00:37 -04:00
tf_trace_begin ( data - > connection - > ssb - > trace , data - > name ) ;
2023-10-08 11:14:42 -04:00
data - > work_callback ( data - > connection , data - > user_data ) ;
2024-05-08 21:00:37 -04:00
tf_trace_end ( data - > connection - > ssb - > trace ) ;
2023-10-08 11:14:42 -04:00
}
tf_ssb_record_thread_busy ( data - > connection - > ssb , false ) ;
}
static void _tf_ssb_connection_after_work_callback ( uv_work_t * work , int status )
{
connection_work_t * data = work - > data ;
if ( data - > after_work_callback )
{
2024-05-08 21:00:37 -04:00
tf_trace_begin ( data - > connection - > ssb - > trace , data - > after_name ) ;
2023-10-08 11:14:42 -04:00
data - > after_work_callback ( data - > connection , status , data - > user_data ) ;
2024-05-08 21:00:37 -04:00
tf_trace_end ( data - > connection - > ssb - > trace ) ;
2023-10-08 11:14:42 -04:00
}
data - > connection - > ref_count - - ;
2024-02-15 18:35:01 -05:00
if ( data - > connection - > ref_count = = 0 & & data - > connection - > closing )
2023-10-08 11:14:42 -04:00
{
_tf_ssb_connection_destroy ( data - > connection , " work completed " ) ;
}
2024-05-08 21:00:37 -04:00
tf_free ( ( void * ) data - > name ) ;
tf_free ( ( void * ) data - > after_name ) ;
2023-10-08 11:14:42 -04:00
tf_free ( data ) ;
}
2024-02-15 18:35:01 -05:00
void tf_ssb_connection_run_work ( tf_ssb_connection_t * connection , void ( * work_callback ) ( tf_ssb_connection_t * connection , void * user_data ) ,
2024-02-17 14:22:02 -05:00
void ( * after_work_callback ) ( tf_ssb_connection_t * connection , int result , void * user_data ) , void * user_data )
2023-10-08 11:14:42 -04:00
{
connection_work_t * work = tf_malloc ( sizeof ( connection_work_t ) ) ;
* work = ( connection_work_t )
{
. work =
{
. data = work ,
} ,
. connection = connection ,
. work_callback = work_callback ,
. after_work_callback = after_work_callback ,
. user_data = user_data ,
} ;
connection - > ref_count + + ;
int result = uv_queue_work ( connection - > ssb - > loop , & work - > work , _tf_ssb_connection_work_callback , _tf_ssb_connection_after_work_callback ) ;
if ( result )
{
_tf_ssb_connection_after_work_callback ( & work - > work , result ) ;
}
}
2023-10-11 11:44:40 -04:00
2024-05-08 21:00:37 -04:00
typedef struct _ssb_work_t
{
uv_work_t work ;
tf_ssb_t * ssb ;
const char * name ;
const char * after_name ;
void ( * work_callback ) ( tf_ssb_t * ssb , void * user_data ) ;
void ( * after_work_callback ) ( tf_ssb_t * ssb , int result , void * user_data ) ;
void * user_data ;
} ssb_work_t ;
static void _tf_ssb_work_callback ( uv_work_t * work )
{
ssb_work_t * data = work - > data ;
tf_ssb_record_thread_busy ( data - > ssb , true ) ;
if ( data - > work_callback )
{
tf_trace_begin ( data - > ssb - > trace , data - > name ) ;
data - > work_callback ( data - > ssb , data - > user_data ) ;
tf_trace_end ( data - > ssb - > trace ) ;
}
tf_ssb_record_thread_busy ( data - > ssb , false ) ;
}
static void _tf_ssb_after_work_callback ( uv_work_t * work , int status )
{
ssb_work_t * data = work - > data ;
if ( data - > after_work_callback )
{
tf_trace_begin ( data - > ssb - > trace , data - > after_name ) ;
data - > after_work_callback ( data - > ssb , status , data - > user_data ) ;
tf_trace_end ( data - > ssb - > trace ) ;
}
tf_ssb_unref ( data - > ssb ) ;
tf_free ( ( void * ) data - > name ) ;
tf_free ( ( void * ) data - > after_name ) ;
tf_free ( data ) ;
}
void tf_ssb_run_work ( tf_ssb_t * ssb , void ( * work_callback ) ( tf_ssb_t * ssb , void * user_data ) , void ( * after_work_callback ) ( tf_ssb_t * ssb , int result , void * user_data ) , void * user_data )
{
ssb_work_t * work = tf_malloc ( sizeof ( ssb_work_t ) ) ;
* work = ( ssb_work_t )
{
. work =
{
. data = work ,
} ,
. name = tf_util_function_to_string ( work_callback ) ,
. after_name = tf_util_function_to_string ( after_work_callback ) ,
. ssb = ssb ,
. work_callback = work_callback ,
. after_work_callback = after_work_callback ,
. user_data = user_data ,
} ;
tf_ssb_ref ( ssb ) ;
int result = uv_queue_work ( ssb - > loop , & work - > work , _tf_ssb_work_callback , _tf_ssb_after_work_callback ) ;
if ( result )
{
_tf_ssb_connection_after_work_callback ( & work - > work , result ) ;
}
}
2023-10-11 11:44:40 -04:00
bool tf_ssb_is_room ( tf_ssb_t * ssb )
{
return ssb - > is_room ;
}
void tf_ssb_set_is_room ( tf_ssb_t * ssb , bool is_room )
{
ssb - > is_room = is_room ;
}
const char * tf_ssb_get_room_name ( tf_ssb_t * ssb )
{
return ssb - > room_name ;
}
void tf_ssb_set_room_name ( tf_ssb_t * ssb , const char * room_name )
{
tf_free ( ssb - > room_name ) ;
ssb - > room_name = tf_strdup ( room_name ) ;
}
typedef struct _update_settings_t
{
bool is_room ;
2024-08-07 21:03:39 -04:00
char seeds_host [ 256 ] ;
2023-10-11 11:44:40 -04:00
char room_name [ 1024 ] ;
} update_settings_t ;
static bool _get_global_setting_string ( tf_ssb_t * ssb , const char * name , char * out_value , size_t size )
{
bool result = false ;
sqlite3 * db = tf_ssb_acquire_db_reader ( ssb ) ;
sqlite3_stmt * statement ;
if ( sqlite3_prepare ( db , " SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings' " , - 1 , & statement , NULL ) = = SQLITE_OK )
{
if ( sqlite3_bind_text ( statement , 1 , name , - 1 , NULL ) = = SQLITE_OK )
{
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
snprintf ( out_value , size , " %s " , sqlite3_column_text ( statement , 0 ) ) ;
result = true ;
}
}
sqlite3_finalize ( statement ) ;
}
else
{
tf_printf ( " prepare failed: %s \n " , sqlite3_errmsg ( db ) ) ;
}
tf_ssb_release_db_reader ( ssb , db ) ;
return result ;
}
static bool _get_global_setting_bool ( tf_ssb_t * ssb , const char * name , bool default_value )
{
bool result = default_value ;
sqlite3 * db = tf_ssb_acquire_db_reader ( ssb ) ;
sqlite3_stmt * statement ;
if ( sqlite3_prepare ( db , " SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings' " , - 1 , & statement , NULL ) = = SQLITE_OK )
{
if ( sqlite3_bind_text ( statement , 1 , name , - 1 , NULL ) = = SQLITE_OK )
{
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
result = sqlite3_column_int ( statement , 0 ) ! = 0 ;
}
}
sqlite3_finalize ( statement ) ;
}
else
{
tf_printf ( " prepare failed: %s \n " , sqlite3_errmsg ( db ) ) ;
}
tf_ssb_release_db_reader ( ssb , db ) ;
return result ;
}
2024-05-08 21:00:37 -04:00
static void _tf_ssb_update_settings_work ( tf_ssb_t * ssb , void * user_data )
2023-10-11 11:44:40 -04:00
{
2024-05-08 21:00:37 -04:00
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 ) ) ;
2024-08-07 21:03:39 -04:00
_get_global_setting_string ( ssb , " seeds_host " , update - > seeds_host , sizeof ( update - > seeds_host ) ) ;
2023-10-11 11:44:40 -04:00
}
2024-05-08 21:00:37 -04:00
static void _tf_ssb_update_settings_after_work ( tf_ssb_t * ssb , int result , void * user_data )
2023-10-11 11:44:40 -04:00
{
2024-05-08 21:00:37 -04:00
update_settings_t * update = user_data ;
tf_ssb_set_is_room ( ssb , update - > is_room ) ;
tf_ssb_set_room_name ( ssb , update - > room_name ) ;
2024-08-07 21:03:39 -04:00
snprintf ( ssb - > seeds_host , sizeof ( ssb - > seeds_host ) , " %s " , update - > seeds_host ) ;
2024-05-08 21:00:37 -04:00
_tf_ssb_start_update_settings ( ssb ) ;
2023-10-11 11:44:40 -04:00
tf_free ( update ) ;
}
2024-01-27 09:44:17 -05:00
static void _tf_ssb_start_update_settings_timer ( tf_ssb_t * ssb , void * user_data )
2023-10-11 11:44:40 -04:00
{
update_settings_t * update = tf_malloc ( sizeof ( update_settings_t ) ) ;
2024-05-08 21:00:37 -04:00
* update = ( update_settings_t ) { 0 } ;
tf_ssb_run_work ( ssb , _tf_ssb_update_settings_work , _tf_ssb_update_settings_after_work , update ) ;
2023-10-11 11:44:40 -04:00
}
static void _tf_ssb_update_settings ( tf_ssb_t * ssb )
{
update_settings_t * update = tf_malloc ( sizeof ( update_settings_t ) ) ;
2024-05-08 21:00:37 -04:00
* update = ( update_settings_t ) { 0 } ;
_tf_ssb_update_settings_work ( ssb , update ) ;
_tf_ssb_update_settings_after_work ( ssb , 0 , update ) ;
2023-10-11 11:44:40 -04:00
}
2024-01-27 09:44:17 -05:00
static void _tf_ssb_start_update_settings ( tf_ssb_t * ssb )
2023-10-11 11:44:40 -04:00
{
2024-01-27 09:44:17 -05:00
tf_ssb_schedule_work ( ssb , 5000 , _tf_ssb_start_update_settings_timer , NULL ) ;
2023-10-11 11:44:40 -04:00
}
2023-11-08 19:28:34 -05:00
void tf_ssb_set_verbose ( tf_ssb_t * ssb , bool verbose )
{
ssb - > verbose = verbose ;
}
2024-01-27 08:48:16 -05:00
static void _tf_ssb_scheduled_timer ( uv_timer_t * handle )
{
tf_ssb_timer_t * timer = handle - > data ;
timer - > callback ( timer - > ssb , timer - > user_data ) ;
for ( int i = 0 ; i < timer - > ssb - > timers_count ; i + + )
{
if ( timer - > ssb - > timers [ i ] = = timer )
{
timer - > ssb - > timers [ i ] = timer - > ssb - > timers [ - - timer - > ssb - > timers_count ] ;
break ;
}
}
uv_close ( ( uv_handle_t * ) handle , _tf_ssb_on_timer_close ) ;
}
void tf_ssb_schedule_work ( tf_ssb_t * ssb , int delay_ms , void ( * callback ) ( tf_ssb_t * ssb , void * user_data ) , void * user_data )
{
ssb - > timers = tf_resize_vec ( ssb - > timers , sizeof ( uv_timer_t * ) * ( ssb - > timers_count + 1 ) ) ;
tf_ssb_timer_t * timer = tf_malloc ( sizeof ( tf_ssb_timer_t ) ) ;
* timer = ( tf_ssb_timer_t )
{
. ssb = ssb ,
. timer =
{
. data = timer ,
} ,
. callback = callback ,
. user_data = user_data ,
} ;
ssb - > timers [ ssb - > timers_count + + ] = timer ;
uv_timer_init ( ssb - > loop , & timer - > timer ) ;
uv_timer_start ( & timer - > timer , _tf_ssb_scheduled_timer , delay_ms , 0 ) ;
2024-01-27 09:44:17 -05:00
uv_unref ( ( uv_handle_t * ) & timer - > timer ) ;
2024-01-27 08:48:16 -05:00
}
2024-03-31 16:15:50 -04:00
2024-04-02 20:11:36 -04:00
bool tf_ssb_hmacsha256_verify ( const char * public_key , const void * payload , size_t payload_length , const char * signature , bool signature_is_urlb64 )
2024-03-31 16:15:50 -04:00
{
bool result = false ;
const char * public_key_start = public_key & & * public_key = = ' @ ' ? public_key + 1 : public_key ;
const char * public_key_end = public_key_start ? strstr ( public_key_start , " .ed25519 " ) : NULL ;
if ( public_key_start & & ! public_key_end )
{
public_key_end = public_key_start + strlen ( public_key_start ) ;
}
uint8_t bin_public_key [ crypto_sign_PUBLICKEYBYTES ] = { 0 } ;
if ( tf_base64_decode ( public_key_start , public_key_end - public_key_start , bin_public_key , sizeof ( bin_public_key ) ) > 0 )
{
uint8_t bin_signature [ crypto_sign_BYTES ] = { 0 } ;
2024-04-02 20:11:36 -04:00
if ( sodium_base642bin ( bin_signature , sizeof ( bin_signature ) , signature , strlen ( signature ) , NULL , NULL , NULL ,
signature_is_urlb64 ? sodium_base64_VARIANT_URLSAFE_NO_PADDING : sodium_base64_VARIANT_ORIGINAL ) = = 0 )
2024-03-31 16:15:50 -04:00
{
if ( crypto_sign_verify_detached ( bin_signature , ( const uint8_t * ) payload , payload_length , bin_public_key ) = = 0 )
{
result = true ;
}
}
}
return result ;
}
2024-05-02 19:02:23 -04:00
JSValue tf_ssb_connection_requests_to_object ( tf_ssb_connection_t * connection )
{
JSContext * context = connection - > ssb - > context ;
JSValue object = JS_NewArray ( context ) ;
for ( int i = 0 ; i < connection - > requests_count ; i + + )
{
JSValue request = JS_NewObject ( context ) ;
JS_SetPropertyStr ( context , request , " name " , JS_NewString ( context , connection - > requests [ i ] . name ) ) ;
JS_SetPropertyStr ( context , request , " request_number " , JS_NewInt32 ( context , connection - > requests [ i ] . request_number ) ) ;
JS_SetPropertyUint32 ( context , object , i , request ) ;
}
return object ;
}
2024-05-22 19:53:33 -04:00
void tf_ssb_connection_adjust_read_backpressure ( tf_ssb_connection_t * connection , int delta )
{
const int k_threshold = 256 ;
int old_pressure = connection - > read_back_pressure ;
connection - > read_back_pressure + = delta ;
if ( ! connection - > closing )
{
if ( old_pressure < k_threshold & & connection - > read_back_pressure > = k_threshold )
{
_tf_ssb_connection_read_stop ( connection ) ;
}
else if ( old_pressure > = k_threshold & & connection - > read_back_pressure < k_threshold )
{
_tf_ssb_connection_read_start ( connection ) ;
}
}
connection - > ref_count + = delta ;
if ( connection - > ref_count = = 0 & & connection - > closing )
{
_tf_ssb_connection_destroy ( connection , " backpressure released " ) ;
}
}
2024-06-02 12:38:12 -04:00
void tf_ssb_connection_adjust_write_count ( tf_ssb_connection_t * connection , int delta )
{
connection - > active_write_count + = delta ;
_tf_ssb_connection_dispatch_scheduled ( connection ) ;
}