forked from cory/tildefriends
First go at implementing rooms. A test passes that appears to exercise them.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4017 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
347
src/ssb.c
347
src/ssb.c
@ -28,6 +28,11 @@
|
||||
#define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
|
||||
#endif
|
||||
|
||||
#define GREEN "\e[1;32m"
|
||||
#define MAGENTA "\e[1;35m"
|
||||
#define CYAN "\e[1;36m"
|
||||
#define RESET "\e[0m"
|
||||
|
||||
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");
|
||||
@ -66,6 +71,7 @@ typedef struct _tf_ssb_request_t
|
||||
{
|
||||
int32_t request_number;
|
||||
tf_ssb_rpc_callback_t* callback;
|
||||
tf_ssb_callback_cleanup_t* cleanup;
|
||||
void* user_data;
|
||||
} tf_ssb_request_t;
|
||||
|
||||
@ -76,6 +82,7 @@ typedef struct _tf_ssb_broadcast_t
|
||||
time_t mtime;
|
||||
char host[256];
|
||||
struct sockaddr_in addr;
|
||||
tf_ssb_connection_t* tunnel_connection;
|
||||
uint8_t pub[crypto_sign_PUBLICKEYBYTES];
|
||||
} tf_ssb_broadcast_t;
|
||||
|
||||
@ -184,8 +191,13 @@ typedef struct _tf_ssb_connection_t
|
||||
uv_connect_t connect;
|
||||
uv_async_t async;
|
||||
|
||||
tf_ssb_connection_t* tunnel_connection;
|
||||
int32_t tunnel_request_number;
|
||||
|
||||
JSValue object;
|
||||
|
||||
char name[32];
|
||||
|
||||
char host[256];
|
||||
int port;
|
||||
|
||||
@ -224,14 +236,17 @@ typedef struct _tf_ssb_connection_t
|
||||
} tf_ssb_connection_t;
|
||||
|
||||
static JSClassID _connection_class_id;
|
||||
static int s_connection_index;
|
||||
static int s_tunnel_index;
|
||||
|
||||
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason);
|
||||
static void _tf_ssb_connection_client_send_hello(uv_stream_t* stream);
|
||||
static void _tf_ssb_connection_client_send_hello(tf_ssb_connection_t* connection);
|
||||
static void _tf_ssb_connection_on_close(uv_handle_t* handle);
|
||||
static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char* reason);
|
||||
static void _tf_ssb_nonce_inc(uint8_t* nonce);
|
||||
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size);
|
||||
static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value);
|
||||
static void _tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t request_number);
|
||||
|
||||
static void _tf_ssb_connection_send_close(tf_ssb_connection_t* connection)
|
||||
{
|
||||
@ -285,14 +300,29 @@ static void _tf_ssb_connection_on_write(uv_write_t* req, int status)
|
||||
|
||||
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size)
|
||||
{
|
||||
uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size);
|
||||
*write = (uv_write_t) { .data = connection };
|
||||
memcpy(write + 1, data, size);
|
||||
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)
|
||||
if (connection->tcp.data)
|
||||
{
|
||||
_tf_ssb_connection_close(connection, "write failed");
|
||||
tf_free(write);
|
||||
uv_write_t* write = tf_malloc(sizeof(uv_write_t) + size);
|
||||
*write = (uv_write_t) { .data = connection };
|
||||
memcpy(write + 1, data, size);
|
||||
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)
|
||||
{
|
||||
_tf_ssb_connection_close(connection, "write failed");
|
||||
tf_free(write);
|
||||
}
|
||||
}
|
||||
else if (connection->tunnel_connection)
|
||||
{
|
||||
tf_ssb_connection_rpc_send(
|
||||
connection->tunnel_connection,
|
||||
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream,
|
||||
-connection->tunnel_request_number,
|
||||
data,
|
||||
size,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,18 +466,14 @@ static bool _tf_ssb_connection_get_request_callback(tf_ssb_connection_t* connect
|
||||
return false;
|
||||
}
|
||||
|
||||
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t* callback, void* user_data)
|
||||
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||
{
|
||||
if (_tf_ssb_connection_get_request_callback(connection, request_number, NULL, NULL))
|
||||
{
|
||||
/* TODO: This leaks the callback. */
|
||||
printf("Adding a request %d that is already registered.\n", request_number);
|
||||
return;
|
||||
}
|
||||
_tf_ssb_connection_remove_request(connection, request_number);
|
||||
tf_ssb_request_t request =
|
||||
{
|
||||
.request_number = request_number,
|
||||
.callback = callback,
|
||||
.cleanup = cleanup,
|
||||
.user_data = user_data,
|
||||
};
|
||||
int index = tf_util_insert_index(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare);
|
||||
@ -467,9 +493,9 @@ static void _tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, i
|
||||
tf_ssb_request_t* request = bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare);
|
||||
if (request)
|
||||
{
|
||||
if (request->user_data)
|
||||
if (request->cleanup)
|
||||
{
|
||||
JS_FreeValue(tf_ssb_connection_get_context(connection), JS_MKPTR(JS_TAG_OBJECT, request->user_data));
|
||||
request->cleanup(connection->ssb, request->user_data);
|
||||
}
|
||||
int index = request - connection->requests;
|
||||
memmove(request, request + 1, sizeof(tf_ssb_request_t) * (connection->requests_count - index - 1));
|
||||
@ -479,7 +505,7 @@ static void _tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, i
|
||||
}
|
||||
}
|
||||
|
||||
void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size, tf_ssb_rpc_callback_t* callback, void* user_data)
|
||||
void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||
{
|
||||
if (!connection)
|
||||
{
|
||||
@ -487,7 +513,7 @@ void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags,
|
||||
}
|
||||
if (request_number > 0 && callback)
|
||||
{
|
||||
tf_ssb_connection_add_request(connection, request_number, callback, user_data);
|
||||
tf_ssb_connection_add_request(connection, request_number, callback, cleanup, user_data);
|
||||
}
|
||||
uint8_t* combined = tf_malloc(9 + size);
|
||||
*combined = flags;
|
||||
@ -496,9 +522,9 @@ void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags,
|
||||
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);
|
||||
printf(MAGENTA "%s RPC SEND" RESET " flags=%x RN=%d: %.*s\n", connection->name, flags, request_number, (flags & k_ssb_rpc_mask_type) == k_ssb_rpc_flag_binary? 0 : (int)size, message);
|
||||
_tf_ssb_connection_box_stream_send(connection, combined, 1 + 2 * sizeof(uint32_t) + size);
|
||||
tf_free(combined);
|
||||
printf("RPC SEND flags=%x RN=%d: %.*s\n", flags, request_number, (int)size, message);
|
||||
connection->ssb->rpc_out++;
|
||||
}
|
||||
|
||||
@ -852,17 +878,20 @@ bool tf_ssb_connection_get_id(tf_ssb_connection_t* connection, char* out_id, siz
|
||||
return tf_ssb_id_bin_to_str(out_id, out_id_size, connection->serverpub);
|
||||
}
|
||||
|
||||
static bool _tf_ssb_is_already_connected(tf_ssb_t* ssb, uint8_t* id)
|
||||
static bool _tf_ssb_is_already_connected(tf_ssb_t* ssb, uint8_t* id, tf_ssb_connection_t* ignore_connection)
|
||||
{
|
||||
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
|
||||
{
|
||||
if (memcmp(connection->serverpub, id, k_id_bin_len) == 0)
|
||||
if (!ignore_connection || connection != ignore_connection)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (memcmp(ssb->pub, id, k_id_bin_len) == 0)
|
||||
{
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -937,9 +966,13 @@ static void _tf_ssb_connection_verify_client_identity(tf_ssb_connection_t* conne
|
||||
}
|
||||
uint8_t* detached_signature_A = m;
|
||||
|
||||
if (_tf_ssb_is_already_connected(connection->ssb, m + 64))
|
||||
if (_tf_ssb_is_already_connected(connection->ssb, m + 64, connection))
|
||||
{
|
||||
_tf_ssb_connection_close(connection, "already connected");
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1101,11 +1134,16 @@ static bool _tf_ssb_name_equals(JSContext* context, JSValue object, const char**
|
||||
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)
|
||||
{
|
||||
connection->ssb->rpc_in++;
|
||||
if (flags & k_ssb_rpc_flag_json)
|
||||
if (size == 0)
|
||||
{
|
||||
_tf_ssb_connection_close(connection, "read zero");
|
||||
return;
|
||||
}
|
||||
else if (flags & k_ssb_rpc_flag_json)
|
||||
{
|
||||
char id[k_id_base64_len] = "";
|
||||
tf_ssb_id_bin_to_str(id, sizeof(id), connection->serverpub);
|
||||
printf("RPC RECV from %s flags=%x RN=%d: %.*s\n", id, flags, request_number, (int)size, message);
|
||||
printf(CYAN "%s RPC RECV" RESET " from %s flags=%x RN=%d: %.*s\n", connection->name, id, flags, request_number, (int)size, message);
|
||||
JSContext* context = connection->ssb->context;
|
||||
JSValue val = JS_ParseJSON(context, (const char*)message, size, NULL);
|
||||
|
||||
@ -1139,7 +1177,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
{
|
||||
const char* k_unsupported = "{\"message\": \"method: is not in list of allowed methods\", \"name\": \"Error\", \"stack\": \"none\"}";
|
||||
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json | k_ssb_rpc_flag_end_error | (flags & k_ssb_rpc_flag_stream), -request_number,
|
||||
(const uint8_t*)k_unsupported, strlen(k_unsupported), NULL, NULL);
|
||||
(const uint8_t*)k_unsupported, strlen(k_unsupported), NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1152,7 +1190,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
}
|
||||
else if ((flags & k_ssb_rpc_mask_type) == k_ssb_rpc_flag_binary)
|
||||
{
|
||||
printf("RPC RECV flags=%x RN=%d: %zd bytes\n", flags, request_number, size);
|
||||
printf(CYAN "%s RPC RECV" RESET " flags=%x RN=%d: %zd bytes\n", connection->name, flags, request_number, size);
|
||||
tf_ssb_rpc_callback_t* callback = NULL;
|
||||
void* user_data = NULL;
|
||||
if (_tf_ssb_connection_get_request_callback(connection, -request_number, &callback, &user_data))
|
||||
@ -1162,6 +1200,10 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
callback(connection, flags, request_number, JS_UNDEFINED, message, size, user_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("No request callback for %p %d\n", connection, -request_number);
|
||||
}
|
||||
}
|
||||
|
||||
if (request_number < 0 &&
|
||||
@ -1348,7 +1390,11 @@ void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* rea
|
||||
if (!connection->destroy_reason)
|
||||
{
|
||||
connection->destroy_reason = reason;
|
||||
printf("destroying connection: %s\n", reason);
|
||||
printf("destroying connection %p obj=%p: %s\n", connection, JS_VALUE_GET_PTR(connection->object), reason);
|
||||
}
|
||||
while (connection->requests)
|
||||
{
|
||||
_tf_ssb_connection_remove_request(connection, connection->requests->request_number);
|
||||
}
|
||||
for (tf_ssb_connection_t** it = &connection->ssb->connections; *it; it = &(*it)->next)
|
||||
{
|
||||
@ -1361,9 +1407,27 @@ void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* rea
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (connection->requests)
|
||||
bool again = true;
|
||||
while (again)
|
||||
{
|
||||
_tf_ssb_connection_remove_request(connection, connection->requests->request_number);
|
||||
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;
|
||||
}
|
||||
else if (connection->tunnel_connection == it)
|
||||
{
|
||||
connection->tunnel_connection = NULL;
|
||||
_tf_ssb_connection_close(it, "tunnel closed");
|
||||
again = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!JS_IsUndefined(connection->object))
|
||||
{
|
||||
@ -1404,18 +1468,16 @@ static void _tf_ssb_connection_on_close(uv_handle_t* handle)
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_on_tcp_recv(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
static void _tf_ssb_connection_on_tcp_recv_internal(tf_ssb_connection_t* connection, const void* data, ssize_t nread)
|
||||
{
|
||||
tf_ssb_connection_t* connection = stream->data;
|
||||
if (nread >= 0)
|
||||
{
|
||||
if (connection->recv_size + nread > sizeof(connection->recv_buffer))
|
||||
{
|
||||
_tf_ssb_connection_close(connection, "recv buffer overflow");
|
||||
tf_free(buf->base);
|
||||
return;
|
||||
}
|
||||
memcpy(connection->recv_buffer + connection->recv_size, buf->base, nread);
|
||||
memcpy(connection->recv_buffer + connection->recv_size, data, nread);
|
||||
connection->recv_size += nread;
|
||||
|
||||
switch (connection->state)
|
||||
@ -1461,7 +1523,7 @@ static void _tf_ssb_connection_on_tcp_recv(uv_stream_t* stream, ssize_t nread, c
|
||||
}
|
||||
else
|
||||
{
|
||||
_tf_ssb_connection_client_send_hello((uv_stream_t*)&connection->tcp);
|
||||
_tf_ssb_connection_client_send_hello(connection);
|
||||
connection->state = k_tf_ssb_state_server_wait_client_identity;
|
||||
}
|
||||
}
|
||||
@ -1492,12 +1554,17 @@ static void _tf_ssb_connection_on_tcp_recv(uv_stream_t* stream, ssize_t nread, c
|
||||
{
|
||||
_tf_ssb_connection_close(connection, "read zero");
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_on_tcp_recv(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
tf_ssb_connection_t* connection = stream->data;
|
||||
_tf_ssb_connection_on_tcp_recv_internal(connection, buf->base, nread);
|
||||
tf_free(buf->base);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_client_send_hello(uv_stream_t* stream)
|
||||
static void _tf_ssb_connection_client_send_hello(tf_ssb_connection_t* connection)
|
||||
{
|
||||
tf_ssb_connection_t* connection = stream->data;
|
||||
char write[crypto_auth_BYTES + crypto_box_PUBLICKEYBYTES];
|
||||
|
||||
if (crypto_box_keypair(connection->epub, connection->epriv) != 0)
|
||||
@ -1536,7 +1603,7 @@ static void _tf_ssb_connection_on_connect(uv_connect_t* connect, int status)
|
||||
}
|
||||
else
|
||||
{
|
||||
_tf_ssb_connection_client_send_hello(connect->handle);
|
||||
_tf_ssb_connection_client_send_hello(connection);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1788,10 +1855,6 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
uv_run(ssb->loop, UV_RUN_ONCE);
|
||||
}
|
||||
|
||||
if (ssb->loop == &ssb->own_loop)
|
||||
{
|
||||
uv_loop_close(ssb->loop);
|
||||
}
|
||||
while (ssb->rpc)
|
||||
{
|
||||
tf_ssb_rpc_callback_node_t* node = ssb->rpc;
|
||||
@ -1848,6 +1911,10 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
}
|
||||
tf_free(node);
|
||||
}
|
||||
if (ssb->loop == &ssb->own_loop)
|
||||
{
|
||||
uv_loop_close(ssb->loop);
|
||||
}
|
||||
if (ssb->own_context)
|
||||
{
|
||||
JS_FreeContext(ssb->context);
|
||||
@ -1893,6 +1960,15 @@ static void _tf_ssb_connection_send_json_response(tf_ssb_connection_t* connectio
|
||||
_tf_ssb_on_rpc(connection, flags, request_number, args, message, size, user_data);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_cleanup_value(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
if (user_data)
|
||||
{
|
||||
JSValue callback = JS_MKPTR(JS_TAG_OBJECT, user_data);
|
||||
JS_FreeValue(tf_ssb_get_context(ssb), callback);
|
||||
}
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_connection_send_json(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
tf_ssb_connection_t* connection = JS_GetOpaque(this_val, _connection_class_id);
|
||||
@ -1915,9 +1991,10 @@ static JSValue _tf_ssb_connection_send_json(JSContext* context, JSValueConst thi
|
||||
(const uint8_t*)message,
|
||||
size,
|
||||
_tf_ssb_connection_send_json_response,
|
||||
_tf_ssb_connection_cleanup_value,
|
||||
JS_IsFunction(context, argv[1]) ? JS_VALUE_GET_PTR(JS_DupValue(context, argv[1])) : NULL);
|
||||
JS_FreeCString(context, message);
|
||||
return JS_UNDEFINED;
|
||||
return JS_NewInt32(context, request_number);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_process_message_async(uv_async_t* async)
|
||||
@ -1952,6 +2029,7 @@ tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, c
|
||||
JSContext* context = ssb->context;
|
||||
tf_ssb_connection_t* connection = tf_malloc(sizeof(tf_ssb_connection_t));
|
||||
memset(connection, 0, sizeof(*connection));
|
||||
snprintf(connection->name, sizeof(connection->name), "cli%d", s_connection_index++);
|
||||
connection->ssb = ssb;
|
||||
connection->tcp.data = connection;
|
||||
connection->connect.data = connection;
|
||||
@ -1962,6 +2040,7 @@ tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, c
|
||||
uv_async_init(ssb->loop, &connection->async, _tf_ssb_connection_process_message_async);
|
||||
|
||||
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
||||
printf("%s = %p\n", connection->name, JS_VALUE_GET_PTR(connection->object));
|
||||
JS_SetOpaque(connection->object, connection);
|
||||
JS_SetPropertyStr(context, connection->object, "send_json", JS_NewCFunction(context, _tf_ssb_connection_send_json, "send_json", 2));
|
||||
char public_key_str[k_id_base64_len] = { 0 };
|
||||
@ -1992,6 +2071,67 @@ tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, c
|
||||
return connection;
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_tunnel_callback(
|
||||
tf_ssb_connection_t* connection,
|
||||
uint8_t flags,
|
||||
int32_t request_number,
|
||||
JSValue args,
|
||||
const uint8_t* message,
|
||||
size_t size,
|
||||
void* user_data)
|
||||
{
|
||||
tf_ssb_connection_t* tunnel = user_data;
|
||||
_tf_ssb_connection_on_tcp_recv_internal(tunnel, message, size);
|
||||
}
|
||||
|
||||
tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_connection_t* connection, int32_t request_number, const char* target_id)
|
||||
{
|
||||
tf_ssb_t* ssb = connection->ssb;
|
||||
|
||||
JSContext* context = ssb->context;
|
||||
tf_ssb_connection_t* tunnel = tf_malloc(sizeof(tf_ssb_connection_t));
|
||||
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);
|
||||
printf("%s = %p\n", tunnel->name, JS_VALUE_GET_PTR(connection->object));
|
||||
JS_SetOpaque(tunnel->object, tunnel);
|
||||
JS_SetPropertyStr(context, tunnel->object, "send_json", JS_NewCFunction(context, _tf_ssb_connection_send_json, "send_json", 2));
|
||||
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);
|
||||
|
||||
tf_ssb_connection_add_request(
|
||||
connection,
|
||||
request_number,
|
||||
_tf_ssb_connection_tunnel_callback,
|
||||
NULL,
|
||||
tunnel);
|
||||
if (request_number < 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
typedef struct _connect_t {
|
||||
tf_ssb_t* ssb;
|
||||
uv_getaddrinfo_t req;
|
||||
@ -2047,6 +2187,7 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
|
||||
|
||||
tf_ssb_connection_t* connection = tf_malloc(sizeof(tf_ssb_connection_t));
|
||||
memset(connection, 0, sizeof(*connection));
|
||||
snprintf(connection->name, sizeof(connection->name), "srv%d", s_connection_index++);
|
||||
connection->ssb = ssb;
|
||||
connection->tcp.data = connection;
|
||||
connection->send_request_number = 1;
|
||||
@ -2054,6 +2195,7 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
|
||||
uv_async_init(ssb->loop, &connection->async, _tf_ssb_connection_process_message_async);
|
||||
|
||||
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
||||
printf("%s = %p\n", connection->name, JS_VALUE_GET_PTR(connection->object));
|
||||
JS_SetPropertyStr(ssb->context, connection->object, "send_json", JS_NewCFunction(ssb->context, _tf_ssb_connection_send_json, "send_json", 2));
|
||||
JS_SetOpaque(connection->object, connection);
|
||||
|
||||
@ -2204,7 +2346,7 @@ static bool _tf_ssb_parse_broadcast(const char* in_broadcast, tf_ssb_broadcast_t
|
||||
printf("pton failed\n");
|
||||
}
|
||||
}
|
||||
else if (strncmp(in_broadcast, "ws:", 3))
|
||||
else if (strncmp(in_broadcast, "ws:", 3) == 0)
|
||||
{
|
||||
printf("Unsupported broadcast: %s\n", in_broadcast);
|
||||
}
|
||||
@ -2250,25 +2392,40 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
||||
return;
|
||||
}
|
||||
|
||||
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
||||
if (broadcast->tunnel_connection)
|
||||
{
|
||||
if (node->addr.sin_family == broadcast->addr.sin_family &&
|
||||
node->addr.sin_port == broadcast->addr.sin_port &&
|
||||
node->addr.sin_addr.s_addr == broadcast->addr.sin_addr.s_addr &&
|
||||
memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
||||
{
|
||||
node->mtime = time(NULL);
|
||||
return;
|
||||
if (node->tunnel_connection == broadcast->tunnel_connection &&
|
||||
memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||
{
|
||||
node->mtime = time(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char key[k_id_base64_len];
|
||||
if (tf_ssb_id_bin_to_str(key, sizeof(key), broadcast->pub))
|
||||
else
|
||||
{
|
||||
tf_ssb_connections_store(ssb->connections_tracker, broadcast->host, ntohs(broadcast->addr.sin_port), key);
|
||||
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
||||
{
|
||||
if (node->addr.sin_family == broadcast->addr.sin_family &&
|
||||
node->addr.sin_port == broadcast->addr.sin_port &&
|
||||
node->addr.sin_addr.s_addr == broadcast->addr.sin_addr.s_addr &&
|
||||
memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||
{
|
||||
node->mtime = time(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char key[k_id_base64_len];
|
||||
if (tf_ssb_id_bin_to_str(key, sizeof(key), broadcast->pub))
|
||||
{
|
||||
tf_ssb_connections_store(ssb->connections_tracker, broadcast->host, ntohs(broadcast->addr.sin_port), key);
|
||||
}
|
||||
printf("Received new broadcast: host=%s, pub=%s.\n", broadcast->host, key);
|
||||
}
|
||||
|
||||
printf("Received new broadcast: host=%s, pub=%s.\n", broadcast->host, key);
|
||||
tf_ssb_broadcast_t* node = tf_malloc(sizeof(tf_ssb_broadcast_t));
|
||||
*node = *broadcast;
|
||||
node->next = ssb->broadcasts;
|
||||
@ -2306,7 +2463,7 @@ static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread,
|
||||
tf_free(buf->base);
|
||||
}
|
||||
|
||||
void tf_ssb_visit_broadcasts(tf_ssb_t* ssb, void (*callback)(const struct sockaddr_in* addr, const uint8_t* pub, void* user_data), void* user_data)
|
||||
void tf_ssb_visit_broadcasts(tf_ssb_t* ssb, void (*callback)(const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
tf_ssb_broadcast_t* next = NULL;
|
||||
@ -2315,7 +2472,7 @@ void tf_ssb_visit_broadcasts(tf_ssb_t* ssb, void (*callback)(const struct sockad
|
||||
next = node->next;
|
||||
if (node->mtime - now < 60)
|
||||
{
|
||||
callback(&node->addr, node->pub, user_data);
|
||||
callback(&node->addr, node->tunnel_connection, node->pub, user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2392,6 +2549,24 @@ void tf_ssb_append_post(tf_ssb_t* ssb, const char* text)
|
||||
JS_FreeValue(ssb->context, obj);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
const char** tf_ssb_get_connection_ids(tf_ssb_t* ssb)
|
||||
{
|
||||
int count = 0;
|
||||
@ -2561,6 +2736,11 @@ JSClassID tf_ssb_get_connection_class_id()
|
||||
|
||||
JSValue tf_ssb_connection_get_object(tf_ssb_connection_t* connection)
|
||||
{
|
||||
if (connection && !JS_IsUndefined(connection->object))
|
||||
{
|
||||
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(connection->object);
|
||||
printf("%p _get_object count=%d\nn", JS_VALUE_GET_PTR(connection->object), p->ref_count);
|
||||
}
|
||||
return connection ? connection->object : JS_UNDEFINED;
|
||||
}
|
||||
|
||||
@ -2660,3 +2840,42 @@ void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id)
|
||||
node->callback(ssb, id, node->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void tf_ssb_connection_add_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
||||
{
|
||||
tf_ssb_broadcast_t broadcast =
|
||||
{
|
||||
.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;)
|
||||
{
|
||||
if ((*it)->tunnel_connection == connection &&
|
||||
memcmp((*it)->pub, pub, k_id_bin_len) == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user