From e59a00922b306f50ee748b49127a13afb06d079d Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sat, 11 Jan 2025 09:23:12 -0500 Subject: [PATCH] ssb: Respond to tunnel.endpoints. Patchwork didn't seem to like that we responded to tunnel.isRoom but not this. --- src/ssb.c | 20 +++++++++++++++++ src/ssb.h | 22 +++++++++++++++++++ src/ssb.rpc.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/src/ssb.c b/src/ssb.c index 96a27fcc..478e3c5f 100644 --- a/src/ssb.c +++ b/src/ssb.c @@ -294,6 +294,8 @@ typedef struct _tf_ssb_connection_t tf_ssb_state_t state; bool is_attendant; int32_t attendant_request_number; + bool is_endpoint; + int32_t endpoint_request_number; uint8_t epub[crypto_box_PUBLICKEYBYTES]; uint8_t epriv[crypto_box_SECRETKEYBYTES]; @@ -942,6 +944,7 @@ bool tf_ssb_connection_rpc_send_error_method_not_allowed(tf_ssb_connection_t* co { char buffer[1024] = ""; snprintf(buffer, sizeof(buffer), "method '%s' is not in list of allowed methods", name); + tf_printf("%s\n", buffer); return tf_ssb_connection_rpc_send_error(connection, flags, request_number, buffer); } @@ -3857,6 +3860,23 @@ void tf_ssb_connection_set_attendant(tf_ssb_connection_t* connection, bool atten _tf_ssb_notify_broadcasts_changed(connection->ssb); } +void tf_ssb_connection_set_endpoint(tf_ssb_connection_t* connection, bool endpoint, int request_number) +{ + connection->is_endpoint = endpoint; + connection->endpoint_request_number = request_number; + _tf_ssb_notify_broadcasts_changed(connection->ssb); +} + +bool tf_ssb_connection_is_endpoint(tf_ssb_connection_t* connection) +{ + return connection->is_endpoint; +} + +int32_t tf_ssb_connection_get_endpoint_request_number(tf_ssb_connection_t* connection) +{ + return connection->endpoint_request_number; +} + void tf_ssb_connection_clear_room_attendants(tf_ssb_connection_t* connection) { int modified = 0; diff --git a/src/ssb.h b/src/ssb.h index fc53b55e..d2bc4271 100644 --- a/src/ssb.h +++ b/src/ssb.h @@ -883,6 +883,28 @@ int32_t tf_ssb_connection_get_attendant_request_number(tf_ssb_connection_t* conn */ void tf_ssb_connection_set_attendant(tf_ssb_connection_t* connection, bool attendant, int request_number); +/** +** Register for endpoint change notifications on a connection. +** @param connection The SHS connection. +** @param endpoint Whether this connection will be an endpoint. +** @param request_number The request number on which to send endpoint changes. +*/ +void tf_ssb_connection_set_endpoint(tf_ssb_connection_t* connection, bool endpoint, int request_number); + +/** +** Get whether we are a potential tunnel endpoint. +** @param connection The SHS connection. +** @return True if this is an endpoint connection. +*/ +bool tf_ssb_connection_is_endpoint(tf_ssb_connection_t* connection); + +/** +** Get the request number used to notify of tunnel endpoint changes. +** @param connection the SHS connection. +** @return A request number. +*/ +int32_t tf_ssb_connection_get_endpoint_request_number(tf_ssb_connection_t* connection); + /** ** Clear all attendants from a room. ** @param connection The SHS connection. diff --git a/src/ssb.rpc.c b/src/ssb.rpc.c index 6719f10b..13784265 100644 --- a/src/ssb.rpc.c +++ b/src/ssb.rpc.c @@ -435,6 +435,36 @@ static void _tf_ssb_rpc_room_meta(tf_ssb_connection_t* connection, uint8_t flags JS_FreeValue(context, response); } +static void _tf_ssb_rpc_send_endpoints(tf_ssb_t* ssb) +{ + JSContext* context = tf_ssb_get_context(ssb); + JSValue endpoints = JS_NewArray(context); + + tf_ssb_connection_t* connections[1024]; + int count = tf_ssb_get_connections(ssb, connections, tf_countof(connections)); + int id_count = 0; + for (int i = 0; i < count; i++) + { + char id[k_id_base64_len] = { 0 }; + if ((tf_ssb_connection_is_attendant(connections[i]) || tf_ssb_connection_is_endpoint(connections[i])) && + tf_ssb_connection_is_connected(connections[i]) && + tf_ssb_connection_get_id(connections[i], id, sizeof(id))) + { + JS_SetPropertyUint32(context, endpoints, id_count++, JS_NewString(context, id)); + } + } + + for (int i = 0; i < count; i++) + { + if (tf_ssb_connection_is_endpoint(connections[i]) && tf_ssb_connection_is_connected(connections[i])) + { + int32_t request_number = tf_ssb_connection_get_ebt_request_number(connections[i]); + tf_ssb_connection_rpc_send_json(connections[i], k_ssb_rpc_flag_json | k_ssb_rpc_flag_stream, -request_number, NULL, endpoints, NULL, NULL, NULL); + } + } + JS_FreeValue(context, endpoints); +} + static void _tf_ssb_rpc_room_attendants(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_t* ssb = tf_ssb_connection_get_ssb(connection); @@ -460,6 +490,7 @@ static void _tf_ssb_rpc_room_attendants(tf_ssb_connection_t* connection, uint8_t tf_ssb_connection_t* connections[1024]; int count = tf_ssb_get_connections(ssb, connections, tf_countof(connections)); + bool have_endpoints = false; for (int i = 0; i < count; i++) { char id[k_id_base64_len] = { 0 }; @@ -469,15 +500,37 @@ static void _tf_ssb_rpc_room_attendants(tf_ssb_connection_t* connection, uint8_t tf_ssb_connection_rpc_send_json(connections[i], flags, -tf_ssb_connection_get_attendant_request_number(connections[i]), NULL, joined, NULL, NULL, NULL); } + if (tf_ssb_connection_is_endpoint(connections[i])) + { + have_endpoints = true; + } } JS_SetPropertyStr(context, state, "ids", ids); tf_ssb_connection_rpc_send_json(connection, flags, -request_number, NULL, state, NULL, NULL, NULL); JS_FreeValue(context, joined); JS_FreeValue(context, state); + if (have_endpoints) + { + _tf_ssb_rpc_send_endpoints(ssb); + } + tf_ssb_connection_set_attendant(connection, true, request_number); } +static void _tf_ssb_rpc_tunnel_endpoints(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_t* ssb = tf_ssb_connection_get_ssb(connection); + if (!tf_ssb_is_room(ssb)) + { + tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "room.attendants"); + return; + } + + tf_ssb_connection_set_endpoint(connection, true, request_number); + _tf_ssb_rpc_send_endpoints(ssb); +} + typedef struct _blobs_get_t { char id[k_blob_id_len]; @@ -1213,6 +1266,11 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang } } JS_FreeValue(context, left); + + if (tf_ssb_connection_is_endpoint(connection) || tf_ssb_connection_is_attendant(connection)) + { + _tf_ssb_rpc_send_endpoints(ssb); + } } } } @@ -1577,6 +1635,7 @@ void tf_ssb_rpc_register(tf_ssb_t* ssb) tf_ssb_add_rpc_callback(ssb, "blobs.createWants", _tf_ssb_rpc_blobs_createWants, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, "tunnel.connect", _tf_ssb_rpc_tunnel_connect, NULL, NULL); /* DUPLEX */ tf_ssb_add_rpc_callback(ssb, "tunnel.isRoom", _tf_ssb_rpc_room_meta, NULL, NULL); /* FAKE-ASYNC */ + tf_ssb_add_rpc_callback(ssb, "tunnel.endpoints", _tf_ssb_rpc_tunnel_endpoints, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, "room.metadata", _tf_ssb_rpc_room_meta, NULL, NULL); /* ASYNC */ tf_ssb_add_rpc_callback(ssb, "room.attendants", _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, "createHistoryStream", _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */