From 422c8bbb5f2bd5cc726d298e6a3f03b0023424d5 Mon Sep 17 00:00:00 2001 From: jfreegman Date: Tue, 24 Sep 2024 09:57:04 -0400 Subject: [PATCH] feat: Implement Tox network profiler --- .gitignore | 1 + CMakeLists.txt | 2 + auto_tests/CMakeLists.txt | 1 + auto_tests/TCP_test.c | 18 +-- auto_tests/netprof_test.c | 120 ++++++++++++++++ auto_tests/onion_test.c | 2 +- other/bootstrap_node_packets.c | 2 +- toxcore/BUILD.bazel | 18 +++ toxcore/LAN_discovery.c | 4 +- toxcore/LAN_discovery.h | 2 +- toxcore/Makefile.inc | 2 + toxcore/TCP_client.c | 6 +- toxcore/TCP_client.h | 5 +- toxcore/TCP_common.c | 10 +- toxcore/TCP_common.h | 5 + toxcore/TCP_connection.c | 20 ++- toxcore/TCP_connection.h | 8 ++ toxcore/TCP_server.c | 17 ++- toxcore/TCP_server.h | 8 ++ toxcore/forwarding.c | 4 +- toxcore/forwarding.h | 4 +- toxcore/net_crypto.c | 16 +++ toxcore/net_crypto.h | 8 ++ toxcore/net_profile.c | 121 ++++++++++++++++ toxcore/net_profile.h | 69 +++++++++ toxcore/network.c | 33 ++++- toxcore/network.h | 19 ++- toxcore/onion.c | 2 +- toxcore/onion.h | 2 +- toxcore/onion_announce.c | 4 +- toxcore/onion_announce.h | 4 +- toxcore/tox.c | 3 +- toxcore/tox_private.c | 201 +++++++++++++++++++++++++- toxcore/tox_private.h | 250 +++++++++++++++++++++++++++++++++ 34 files changed, 945 insertions(+), 46 deletions(-) create mode 100644 auto_tests/netprof_test.c create mode 100644 toxcore/net_profile.c create mode 100644 toxcore/net_profile.h diff --git a/.gitignore b/.gitignore index 33b7971069b..33d31c037c0 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ testing/data # Vim *.swp +*.nvimlog # Object files *.o diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f6d37da138..caafd641a70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,8 @@ set(toxcore_SOURCES toxcore/mem.h toxcore/mono_time.c toxcore/mono_time.h + toxcore/net_profile.c + toxcore/net_profile.h toxcore/net_crypto.c toxcore/net_crypto.h toxcore/network.c diff --git a/auto_tests/CMakeLists.txt b/auto_tests/CMakeLists.txt index d891ba122b0..d3383c4fcab 100644 --- a/auto_tests/CMakeLists.txt +++ b/auto_tests/CMakeLists.txt @@ -67,6 +67,7 @@ auto_test(invalid_udp_proxy) auto_test(lan_discovery) auto_test(lossless_packet) auto_test(lossy_packet) +auto_test(netprof) auto_test(network) auto_test(onion) auto_test(overflow_recvq) diff --git a/auto_tests/TCP_test.c b/auto_tests/TCP_test.c index c4ea79b08d0..baaa4a2d139 100644 --- a/auto_tests/TCP_test.c +++ b/auto_tests/TCP_test.c @@ -111,12 +111,12 @@ static void test_basic(void) // Sending the handshake ck_assert_msg(net_send(ns, logger, sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, - &localhost) == TCP_CLIENT_HANDSHAKE_SIZE - 1, + &localhost, nullptr) == TCP_CLIENT_HANDSHAKE_SIZE - 1, "An attempt to send the initial handshake minus last byte failed."); do_tcp_server_delay(tcp_s, mono_time, 50); - ck_assert_msg(net_send(ns, logger, sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, &localhost) == 1, + ck_assert_msg(net_send(ns, logger, sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, &localhost, nullptr) == 1, "The attempt to send the last byte of handshake failed."); free(handshake); @@ -155,7 +155,7 @@ static void test_basic(void) msg_length = sizeof(r_req) - i; } - ck_assert_msg(net_send(ns, logger, sock, r_req + i, msg_length, &localhost) == msg_length, + ck_assert_msg(net_send(ns, logger, sock, r_req + i, msg_length, &localhost, nullptr) == msg_length, "Failed to send request after completing the handshake."); i += msg_length; @@ -234,12 +234,12 @@ static struct sec_TCP_con *new_tcp_con(const Logger *logger, const Memory *mem, "Failed to encrypt the outgoing handshake."); ck_assert_msg(net_send(ns, logger, sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, - &localhost) == TCP_CLIENT_HANDSHAKE_SIZE - 1, + &localhost, nullptr) == TCP_CLIENT_HANDSHAKE_SIZE - 1, "Failed to send the first portion of the handshake to the TCP relay server."); do_tcp_server_delay(tcp_s, mono_time, 50); - ck_assert_msg(net_send(ns, logger, sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, &localhost) == 1, + ck_assert_msg(net_send(ns, logger, sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, &localhost, nullptr) == 1, "Failed to send last byte of handshake."); do_tcp_server_delay(tcp_s, mono_time, 50); @@ -283,7 +283,7 @@ static int write_packet_tcp_test_connection(const Logger *logger, struct sec_TCP localhost.ip = get_loopback(); localhost.port = 0; - ck_assert_msg(net_send(con->ns, logger, con->sock, packet, packet_size, &localhost) == packet_size, + ck_assert_msg(net_send(con->ns, logger, con->sock, packet, packet_size, &localhost, nullptr) == packet_size, "Failed to send a packet."); return 0; } @@ -524,7 +524,7 @@ static void test_client(void) ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); ip_port_tcp_s.ip = get_loopback(); - TCP_Client_Connection *conn = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, nullptr); + TCP_Client_Connection *conn = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, nullptr, nullptr); // TCP sockets might need a moment before they can be written to. c_sleep(50); do_tcp_connection(logger, mono_time, conn, nullptr); @@ -560,7 +560,7 @@ static void test_client(void) crypto_new_keypair(rng, f2_public_key, f2_secret_key); ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); TCP_Client_Connection *conn2 = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, self_public_key, f2_public_key, - f2_secret_key, nullptr); + f2_secret_key, nullptr, nullptr); c_sleep(50); // The client should call this function (defined earlier) during the routing process. @@ -657,7 +657,7 @@ static void test_client_invalid(void) ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); ip_port_tcp_s.ip = get_loopback(); TCP_Client_Connection *conn = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, - self_public_key, f_public_key, f_secret_key, nullptr); + self_public_key, f_public_key, f_secret_key, nullptr, nullptr); // Run the client's main loop but not the server. mono_time_update(mono_time); diff --git a/auto_tests/netprof_test.c b/auto_tests/netprof_test.c new file mode 100644 index 00000000000..f9207fee528 --- /dev/null +++ b/auto_tests/netprof_test.c @@ -0,0 +1,120 @@ +/** Auto Tests: basic network profile functionality test (UDP only) + * TODO(JFreegman): test TCP packets as well + */ + +#include +#include + +#include "../toxcore/tox_private.h" +#include "../toxcore/util.h" + +#include "auto_test_support.h" +#include "check_compat.h" + +#define NUM_TOXES 2 + +static void test_netprof(AutoTox *autotoxes) +{ + // Send some messages to create fake traffic + for (size_t i = 0; i < 256; ++i) { + for (uint32_t j = 0; j < NUM_TOXES; ++j) { + tox_friend_send_message(autotoxes[j].tox, 0, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)"test", 4, nullptr); + } + + iterate_all_wait(autotoxes, NUM_TOXES, ITERATION_INTERVAL); + } + + // idle traffic for a while + for (size_t i = 0; i < 100; ++i) { + iterate_all_wait(autotoxes, NUM_TOXES, ITERATION_INTERVAL); + } + + const Tox *tox1 = autotoxes[0].tox; + + const unsigned long long UDP_count_sent1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_SENT); + const unsigned long long UDP_count_recv1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_RECV); + const unsigned long long TCP_count_sent1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_SENT); + const unsigned long long TCP_count_recv1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_RECV); + + const unsigned long long UDP_bytes_sent1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_SENT); + const unsigned long long UDP_bytes_recv1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_RECV); + const unsigned long long TCP_bytes_sent1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_SENT); + const unsigned long long TCP_bytes_recv1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_RECV); + + ck_assert(UDP_count_recv1 > 0 && UDP_count_sent1 > 0); + ck_assert(UDP_bytes_recv1 > 0 && UDP_bytes_sent1 > 0); + + (void)TCP_count_sent1; + (void)TCP_bytes_sent1; + (void)TCP_bytes_recv1; + (void)TCP_count_recv1; + + unsigned long long total_sent_count = 0; + unsigned long long total_recv_count = 0; + unsigned long long total_sent_bytes = 0; + unsigned long long total_recv_bytes = 0; + + // tox1 makes sure the sum value of all packet ID's is equal to the totals + for (size_t i = 0; i < 256; ++i) { + // this id isn't valid for UDP packets but we still want to call the + // functions and make sure they return some non-zero value + if (i == TOX_NETPROF_PACKET_ID_TCP_DATA) { + ck_assert(tox_netprof_get_packet_id_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_SENT) > 0); + ck_assert(tox_netprof_get_packet_id_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_SENT) > 0); + ck_assert(tox_netprof_get_packet_id_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_SENT) > 0); + ck_assert(tox_netprof_get_packet_id_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_RECV) > 0); + continue; + } + + total_sent_count += tox_netprof_get_packet_id_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_SENT); + total_recv_count += tox_netprof_get_packet_id_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_RECV); + + total_sent_bytes += tox_netprof_get_packet_id_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_SENT); + total_recv_bytes += tox_netprof_get_packet_id_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, i, + TOX_NETPROF_DIRECTION_RECV); + } + + const unsigned long long total_packets = total_sent_count + total_recv_count; + ck_assert_msg(total_packets == UDP_count_sent1 + UDP_count_recv1, + "%llu does not match %llu\n", total_packets, UDP_count_sent1 + UDP_count_recv1); + + ck_assert_msg(total_sent_count == UDP_count_sent1, "%llu does not match %llu\n", total_sent_count, UDP_count_sent1); + ck_assert_msg(total_recv_count == UDP_count_recv1, "%llu does not match %llu\n", total_recv_count, UDP_count_recv1); + + + const unsigned long long total_bytes = total_sent_bytes + total_recv_bytes; + ck_assert_msg(total_bytes == UDP_bytes_sent1 + UDP_bytes_recv1, + "%llu does not match %llu\n", total_bytes, UDP_bytes_sent1 + UDP_bytes_recv1); + + ck_assert_msg(total_sent_bytes == UDP_bytes_sent1, "%llu does not match %llu\n", total_sent_bytes, UDP_bytes_sent1); + ck_assert_msg(total_recv_bytes == UDP_bytes_recv1, "%llu does not match %llu\n", total_recv_bytes, UDP_bytes_recv1); +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + + Run_Auto_Options autotox_opts = default_run_auto_options(); + autotox_opts.graph = GRAPH_COMPLETE; + + run_auto_test(nullptr, NUM_TOXES, test_netprof, 0, &autotox_opts); + + return 0; +} + +#undef NUM_TOXES diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c index 3a81df41b8f..549f8ce9dd2 100644 --- a/auto_tests/onion_test.c +++ b/auto_tests/onion_test.c @@ -202,7 +202,7 @@ static int handle_test_4(void *object, const IP_Port *source, const uint8_t *pac * Use Onion_Path path to send data of length to dest. * Maximum length of data is ONION_MAX_DATA_SIZE. */ -static void send_onion_packet(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length) +static void send_onion_packet(Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length) { uint8_t packet[ONION_MAX_PACKET_SIZE]; const int len = create_onion_packet(rng, packet, sizeof(packet), path, dest, data, length); diff --git a/other/bootstrap_node_packets.c b/other/bootstrap_node_packets.c index c250b2552bc..03b62b94199 100644 --- a/other/bootstrap_node_packets.c +++ b/other/bootstrap_node_packets.c @@ -30,7 +30,7 @@ static int handle_info_request(void *object, const IP_Port *source, const uint8_ return 1; } - const Networking_Core *nc = (const Networking_Core *)object; + Networking_Core *nc = (Networking_Core *)object; uint8_t data[1 + sizeof(bootstrap_version) + MAX_MOTD_LENGTH]; data[0] = BOOTSTRAP_INFO_PACKET_ID; diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index 0f313e2af58..edcb3cb2677 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -299,6 +299,16 @@ cc_library( ], ) +cc_library( + name = "net_profile", + srcs = ["net_profile.c"], + hdrs = ["net_profile.h"], + deps = [ + ":attributes", + ":ccompat", + ], +) + cc_library( name = "network", srcs = ["network.c"], @@ -318,6 +328,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":util", "@libsodium", "@psocket", @@ -570,6 +581,7 @@ cc_library( ":crypto_core", ":logger", ":mem", + ":net_profile", ":network", ], ) @@ -597,6 +609,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":onion", ":util", @@ -618,6 +631,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":util", ], @@ -640,6 +654,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":onion", ":util", @@ -674,6 +689,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":util", "@pthread", @@ -993,6 +1009,7 @@ cc_library( ":DHT", ":Messenger", ":TCP_client", + ":TCP_server", ":attributes", ":ccompat", ":crypto_core", @@ -1003,6 +1020,7 @@ cc_library( ":mem", ":mono_time", ":net_crypto", + ":net_profile", ":network", ":onion_client", ":state", diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c index aead9759116..8b746a0cd98 100644 --- a/toxcore/LAN_discovery.c +++ b/toxcore/LAN_discovery.c @@ -210,7 +210,7 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns) * @retval false on failure to find any valid broadcast target. */ non_null() -static bool send_broadcasts(const Networking_Core *net, const Broadcast_Info *broadcast, uint16_t port, +static bool send_broadcasts(Networking_Core *net, const Broadcast_Info *broadcast, uint16_t port, const uint8_t *data, uint16_t length) { if (broadcast->count == 0) { @@ -339,7 +339,7 @@ bool ip_is_lan(const IP *ip) return false; } -bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk, +bool lan_discovery_send(Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk, uint16_t port) { if (broadcast == nullptr) { diff --git a/toxcore/LAN_discovery.h b/toxcore/LAN_discovery.h index 94e5d3581c8..6486243ed5a 100644 --- a/toxcore/LAN_discovery.h +++ b/toxcore/LAN_discovery.h @@ -25,7 +25,7 @@ typedef struct Broadcast_Info Broadcast_Info; * @return true on success, false on failure. */ non_null() -bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk, +bool lan_discovery_send(Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk, uint16_t port); /** diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index db3e1932431..e22e59d9e0f 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -74,6 +74,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \ ../toxcore/ping_array.c \ ../toxcore/net_crypto.h \ ../toxcore/net_crypto.c \ + ../toxcore/net_profile.c \ + ../toxcore/net_profile.h \ ../toxcore/friend_requests.h \ ../toxcore/friend_requests.c \ ../toxcore/LAN_discovery.h \ diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index 2b8c6e448f5..2c66fe977ea 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -20,6 +20,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #include "util.h" @@ -582,7 +583,7 @@ void forwarding_handler(TCP_Client_Connection *con, forwarded_response_cb *forwa TCP_Client_Connection *new_tcp_connection( const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Random *rng, const Network *ns, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key, - const TCP_Proxy_Info *proxy_info) + const TCP_Proxy_Info *proxy_info, Net_Profile *net_profile) { assert(logger != nullptr); assert(mem != nullptr); @@ -634,6 +635,7 @@ TCP_Client_Connection *new_tcp_connection( temp->con.rng = rng; temp->con.sock = sock; temp->con.ip_port = *ip_port; + temp->con.net_profile = net_profile; memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE); encrypt_precompute(temp->public_key, self_secret_key, temp->con.shared_key); @@ -819,6 +821,8 @@ static int handle_tcp_client_packet(const Logger *logger, TCP_Client_Connection return -1; } + netprof_record_packet(conn->con.net_profile, data[0], length, PACKET_DIRECTION_RECV); + switch (data[0]) { case TCP_PACKET_ROUTING_RESPONSE: return handle_tcp_client_routing_response(conn, data, length); diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index ea2654b953b..b103baa6c17 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -15,6 +15,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #define TCP_CONNECTION_TIMEOUT 10 @@ -60,11 +61,11 @@ non_null() void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value); /** Create new TCP connection to ip_port/public_key */ -non_null(1, 2, 3, 4, 5, 6, 7, 8, 9) nullable(10) +non_null(1, 2, 3, 4, 5, 6, 7, 8, 9) nullable(10, 11) TCP_Client_Connection *new_tcp_connection( const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Random *rng, const Network *ns, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key, - const TCP_Proxy_Info *proxy_info); + const TCP_Proxy_Info *proxy_info, Net_Profile *net_profile); /** Run the TCP connection */ non_null(1, 2, 3) nullable(4) diff --git a/toxcore/TCP_common.c b/toxcore/TCP_common.c index bd3b7ca4c74..919f09f76fe 100644 --- a/toxcore/TCP_common.c +++ b/toxcore/TCP_common.c @@ -35,7 +35,8 @@ int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con) } const uint16_t left = con->last_packet_length - con->last_packet_sent; - const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port); + const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port, + con->net_profile); if (len <= 0) { return -1; @@ -66,7 +67,7 @@ int send_pending_data(const Logger *logger, TCP_Connection *con) while (p != nullptr) { const uint16_t left = p->size - p->sent; - const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port); + const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port, con->net_profile); if (len != left) { if (len > 0) { @@ -164,7 +165,8 @@ int write_packet_tcp_secure_connection(const Logger *logger, TCP_Connection *con } if (priority) { - len = sendpriority ? net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port) : 0; + len = sendpriority ? net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port, + con->net_profile) : 0; if (len <= 0) { len = 0; @@ -179,7 +181,7 @@ int write_packet_tcp_secure_connection(const Logger *logger, TCP_Connection *con return add_priority(con, packet, packet_size, len) ? 1 : 0; } - len = net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port); + len = net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port, con->net_profile); if (len <= 0) { return 0; diff --git a/toxcore/TCP_common.h b/toxcore/TCP_common.h index 9fa136609ca..3b6a5488a87 100644 --- a/toxcore/TCP_common.h +++ b/toxcore/TCP_common.h @@ -10,6 +10,7 @@ #include "crypto_core.h" #include "logger.h" #include "mem.h" +#include "net_profile.h" #include "network.h" typedef struct TCP_Priority_List TCP_Priority_List; @@ -66,6 +67,10 @@ typedef struct TCP_Connection { TCP_Priority_List *priority_queue_start; TCP_Priority_List *priority_queue_end; + + // This is a shared pointer to the parent's respective Net_Profile object + // (either TCP_Server for TCP server packets or TCP_Connections for TCP client packets). + Net_Profile *net_profile; } TCP_Connection; /** diff --git a/toxcore/TCP_connection.c b/toxcore/TCP_connection.c index c7161a92894..bbfc4137013 100644 --- a/toxcore/TCP_connection.c +++ b/toxcore/TCP_connection.c @@ -20,6 +20,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #include "util.h" @@ -56,6 +57,9 @@ struct TCP_Connections { bool onion_status; uint16_t onion_num_conns; + + /* Network profile for all TCP client packets. */ + Net_Profile net_profile; }; static const TCP_Connection_to empty_tcp_connection_to = {0}; @@ -928,7 +932,8 @@ static int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connec uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; memcpy(relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE); kill_tcp_connection(tcp_con->connection); - tcp_con->connection = new_tcp_connection(tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info); + tcp_con->connection = new_tcp_connection(tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info, + &tcp_c->net_profile); if (tcp_con->connection == nullptr) { kill_tcp_relay_connection(tcp_c, tcp_connections_number); @@ -1017,7 +1022,7 @@ static int unsleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connecti tcp_con->connection = new_tcp_connection( tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &tcp_con->ip_port, - tcp_con->relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info); + tcp_con->relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info, &tcp_c->net_profile); if (tcp_con->connection == nullptr) { kill_tcp_relay_connection(tcp_c, tcp_connections_number); @@ -1315,7 +1320,7 @@ static int add_tcp_relay_instance(TCP_Connections *tcp_c, const IP_Port *ip_port tcp_con->connection = new_tcp_connection( tcp_c->logger, tcp_c->mem, tcp_c->mono_time, tcp_c->rng, tcp_c->ns, &ipp_copy, - relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info); + relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info, &tcp_c->net_profile); if (tcp_con->connection == nullptr) { return -1; @@ -1727,3 +1732,12 @@ void kill_tcp_connections(TCP_Connections *tcp_c) mem_delete(tcp_c->mem, tcp_c->connections); mem_delete(tcp_c->mem, tcp_c); } + +const Net_Profile *tcp_connection_get_client_net_profile(const TCP_Connections *tcp_c) +{ + if (tcp_c == nullptr) { + return nullptr; + } + + return &tcp_c->net_profile; +} diff --git a/toxcore/TCP_connection.h b/toxcore/TCP_connection.h index 2d35919f10e..8d0de32a2bf 100644 --- a/toxcore/TCP_connection.h +++ b/toxcore/TCP_connection.h @@ -21,6 +21,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #define TCP_CONN_NONE 0 @@ -317,4 +318,11 @@ void do_tcp_connections(const Logger *logger, TCP_Connections *tcp_c, void *user nullable(1) void kill_tcp_connections(TCP_Connections *tcp_c); +/** @brief a pointer to the tcp client net profile associated with tcp_c. + * + * @retval null if tcp_c is null. + */ +non_null() +const Net_Profile *tcp_connection_get_client_net_profile(const TCP_Connections *tcp_c); + #endif /* C_TOXCORE_TOXCORE_TCP_CONNECTION_H */ diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c index 1363d902207..8daee4101d0 100644 --- a/toxcore/TCP_server.c +++ b/toxcore/TCP_server.c @@ -27,6 +27,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #include "onion.h" @@ -91,6 +92,9 @@ struct TCP_Server { uint64_t counter; BS_List accepted_key_list; + + /* Network profile for all TCP server packets. */ + Net_Profile net_profile; }; static_assert(sizeof(TCP_Server) < 7 * 1024 * 1024, @@ -236,6 +240,7 @@ static int add_accepted(TCP_Server *tcp_server, const Mono_Time *mono_time, TCP_ tcp_server->accepted_connection_array[index].identifier = ++tcp_server->counter; tcp_server->accepted_connection_array[index].last_pinged = mono_time_get(mono_time); tcp_server->accepted_connection_array[index].ping_id = 0; + tcp_server->accepted_connection_array[index].con.net_profile = &tcp_server->net_profile; return index; } @@ -357,7 +362,7 @@ static int handle_tcp_handshake(const Logger *logger, TCP_Secure_Connection *con const IP_Port ipp = {{{0}}}; - if (TCP_SERVER_HANDSHAKE_SIZE != net_send(con->con.ns, logger, con->con.sock, response, TCP_SERVER_HANDSHAKE_SIZE, &ipp)) { + if (TCP_SERVER_HANDSHAKE_SIZE != net_send(con->con.ns, logger, con->con.sock, response, TCP_SERVER_HANDSHAKE_SIZE, &ipp, con->con.net_profile)) { crypto_memzero(shared_key, sizeof(shared_key)); return -1; } @@ -680,6 +685,7 @@ static int handle_tcp_packet(TCP_Server *tcp_server, uint32_t con_id, const uint } TCP_Secure_Connection *const con = &tcp_server->accepted_connection_array[con_id]; + netprof_record_packet(con->con.net_profile, data[0], length, PACKET_DIRECTION_RECV); switch (data[0]) { case TCP_PACKET_ROUTING_REQUEST: { @@ -1425,3 +1431,12 @@ void kill_tcp_server(TCP_Server *tcp_server) mem_delete(tcp_server->mem, tcp_server->socks_listening); mem_delete(tcp_server->mem, tcp_server); } + +const Net_Profile *tcp_server_get_net_profile(const TCP_Server *tcp_server) +{ + if (tcp_server == nullptr) { + return nullptr; + } + + return &tcp_server->net_profile; +} diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h index 1d3933a415e..b20c5e1c940 100644 --- a/toxcore/TCP_server.h +++ b/toxcore/TCP_server.h @@ -15,6 +15,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #include "onion.h" @@ -52,4 +53,11 @@ void do_tcp_server(TCP_Server *tcp_server, const Mono_Time *mono_time); nullable(1) void kill_tcp_server(TCP_Server *tcp_server); +/** @brief Returns a pointer to the net profile associated with `tcp_server`. + * + * Returns null if `tcp_server` is null. + */ +nullable(1) +const Net_Profile *tcp_server_get_net_profile(const TCP_Server *tcp_server); + #endif /* C_TOXCORE_TOXCORE_TCP_SERVER_H */ diff --git a/toxcore/forwarding.c b/toxcore/forwarding.c index 18ff3203fc4..1c455107538 100644 --- a/toxcore/forwarding.c +++ b/toxcore/forwarding.c @@ -43,7 +43,7 @@ DHT *forwarding_get_dht(const Forwarding *forwarding) #define SENDBACK_TIMEOUT 3600 -bool send_forward_request(const Networking_Core *net, const IP_Port *forwarder, +bool send_forward_request(Networking_Core *net, const IP_Port *forwarder, const uint8_t *chain_keys, uint16_t chain_length, const uint8_t *data, uint16_t data_length) { @@ -321,7 +321,7 @@ static int handle_forwarding(void *object, const IP_Port *source, const uint8_t } } -bool forward_reply(const Networking_Core *net, const IP_Port *forwarder, +bool forward_reply(Networking_Core *net, const IP_Port *forwarder, const uint8_t *sendback, uint16_t sendback_length, const uint8_t *data, uint16_t length) { diff --git a/toxcore/forwarding.h b/toxcore/forwarding.h index bd0ef09e1c4..e3f3ff1f028 100644 --- a/toxcore/forwarding.h +++ b/toxcore/forwarding.h @@ -45,7 +45,7 @@ DHT *forwarding_get_dht(const Forwarding *forwarding); * @return true on success, false otherwise. */ non_null() -bool send_forward_request(const Networking_Core *net, const IP_Port *forwarder, +bool send_forward_request(Networking_Core *net, const IP_Port *forwarder, const uint8_t *chain_keys, uint16_t chain_length, const uint8_t *data, uint16_t data_length); @@ -79,7 +79,7 @@ bool create_forward_chain_packet(const uint8_t *chain_keys, uint16_t chain_lengt * @return true on success, false otherwise. */ non_null() -bool forward_reply(const Networking_Core *net, const IP_Port *forwarder, +bool forward_reply(Networking_Core *net, const IP_Port *forwarder, const uint8_t *sendback, uint16_t sendback_length, const uint8_t *data, uint16_t length); diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 1680b078b72..52cbfd2f200 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -23,6 +23,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #include "util.h" @@ -3227,3 +3228,18 @@ void kill_net_crypto(Net_Crypto *c) crypto_memzero(c, sizeof(Net_Crypto)); mem_delete(mem, c); } + +const Net_Profile *nc_get_tcp_client_net_profile(const Net_Crypto *c) +{ + if (c == nullptr) { + return nullptr; + } + + const TCP_Connections *tcp_c = nc_get_tcp_c(c); + + if (tcp_c == nullptr) { + return nullptr; + } + + return tcp_connection_get_client_net_profile(tcp_c); +} diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index 0d817e43151..06db4c40e30 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h @@ -20,6 +20,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" /*** Crypto payloads. */ @@ -418,4 +419,11 @@ void do_net_crypto(Net_Crypto *c, void *userdata); nullable(1) void kill_net_crypto(Net_Crypto *c); +/** + * Returns a pointer to the net profile object for the TCP client associated with `c`. + * Returns null if `c` is null or the TCP_Connections associated with `c` is null. + */ +non_null() +const Net_Profile *nc_get_tcp_client_net_profile(const Net_Crypto *c); + #endif /* C_TOXCORE_TOXCORE_NET_CRYPTO_H */ diff --git a/toxcore/net_profile.c b/toxcore/net_profile.c new file mode 100644 index 00000000000..2505d95c2dd --- /dev/null +++ b/toxcore/net_profile.c @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023 The TokTok team. + */ + +/** + * Functions for the network profile. + */ + +#include "net_profile.h" + +#include + +#include "attributes.h" +#include "ccompat.h" + +#define NETPROF_TCP_DATA_PACKET_ID 0x10 + +/** Returns the number of sent or received packets for all ID's between `start_id` and `end_id`. */ +nullable(1) +static uint64_t netprof_get_packet_count_id_range(const Net_Profile *profile, uint8_t start_id, uint8_t end_id, + Packet_Direction dir) +{ + if (profile == nullptr) { + return 0; + } + + const uint64_t *arr = dir == PACKET_DIRECTION_SENT ? profile->packets_sent : profile->packets_recv; + uint64_t count = 0; + + for (size_t i = start_id; i <= end_id; ++i) { + count += arr[i]; + } + + return count; +} + +/** Returns the number of sent or received bytes for all ID's between `start_id` and `end_id`. */ +nullable(1) +static uint64_t netprof_get_bytes_id_range(const Net_Profile *profile, uint8_t start_id, uint8_t end_id, + Packet_Direction dir) +{ + if (profile == nullptr) { + return 0; + } + + const uint64_t *arr = dir == PACKET_DIRECTION_SENT ? profile->bytes_sent : profile->bytes_recv; + uint64_t bytes = 0; + + for (size_t i = start_id; i <= end_id; ++i) { + bytes += arr[i]; + } + + return bytes; +} + +void netprof_record_packet(Net_Profile *profile, uint8_t id, size_t length, Packet_Direction dir) +{ + if (profile == nullptr) { + return; + } + + if (dir == PACKET_DIRECTION_SENT) { + ++profile->total_packets_sent; + ++profile->packets_sent[id]; + + profile->total_bytes_sent += length; + profile->bytes_sent[id] += length; + } else { + ++profile->total_packets_recv; + ++profile->packets_recv[id]; + + profile->total_bytes_recv += length; + profile->bytes_recv[id] += length; + } +} + +uint64_t netprof_get_packet_count_id(const Net_Profile *profile, uint8_t id, Packet_Direction dir) +{ + if (profile == nullptr) { + return 0; + } + + // Special case - TCP data packets can have any ID between 0x10 and 0xff + if (id == NETPROF_TCP_DATA_PACKET_ID) { + return netprof_get_packet_count_id_range(profile, id, UINT8_MAX, dir); + } + + return dir == PACKET_DIRECTION_SENT ? profile->packets_sent[id] : profile->packets_recv[id]; +} + +uint64_t netprof_get_packet_count_total(const Net_Profile *profile, Packet_Direction dir) +{ + if (profile == nullptr) { + return 0; + } + + return dir == PACKET_DIRECTION_SENT ? profile->total_packets_sent : profile->total_packets_recv; +} + +uint64_t netprof_get_bytes_id(const Net_Profile *profile, uint8_t id, Packet_Direction dir) +{ + if (profile == nullptr) { + return 0; + } + + // Special case - TCP data packets can have any ID between 0x10 and 0xff + if (id == NETPROF_TCP_DATA_PACKET_ID) { + return netprof_get_bytes_id_range(profile, id, 0xff, dir); + } + + return dir == PACKET_DIRECTION_SENT ? profile->bytes_sent[id] : profile->bytes_recv[id]; +} + +uint64_t netprof_get_bytes_total(const Net_Profile *profile, Packet_Direction dir) +{ + if (profile == nullptr) { + return 0; + } + + return dir == PACKET_DIRECTION_SENT ? profile->total_bytes_sent : profile->total_bytes_recv; +} diff --git a/toxcore/net_profile.h b/toxcore/net_profile.h new file mode 100644 index 00000000000..3c40ffffa21 --- /dev/null +++ b/toxcore/net_profile.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023 The TokTok team. + */ + +/** + * Functions for the network profile. + */ +#ifndef C_TOXCORE_TOXCORE_NET_PROFILE_H +#define C_TOXCORE_TOXCORE_NET_PROFILE_H + +#include +#include + +#include "attributes.h" + +/* The max number of packet ID's (must fit inside one byte) */ +#define NET_PROF_MAX_PACKET_IDS 256 + +typedef struct Net_Profile { + uint64_t packets_recv[NET_PROF_MAX_PACKET_IDS]; + uint64_t packets_sent[NET_PROF_MAX_PACKET_IDS]; + + uint64_t total_packets_recv; + uint64_t total_packets_sent; + + uint64_t bytes_recv[NET_PROF_MAX_PACKET_IDS]; + uint64_t bytes_sent[NET_PROF_MAX_PACKET_IDS]; + + uint64_t total_bytes_recv; + uint64_t total_bytes_sent; +} Net_Profile; + +/** Specifies whether the query is for sent or received packets. */ +typedef enum Packet_Direction { + PACKET_DIRECTION_SENT, + PACKET_DIRECTION_RECV, +} Packet_Direction; + +/** + * Records a sent or received packet of type `id` and size `length` to the given profile. + */ +nullable(1) +void netprof_record_packet(Net_Profile *profile, uint8_t id, size_t length, Packet_Direction dir); + +/** + * Returns the number of sent or received packets of type `id` for the given profile. + */ +nullable(1) +uint64_t netprof_get_packet_count_id(const Net_Profile *profile, uint8_t id, Packet_Direction dir); + +/** + * Returns the total number of sent or received packets for the given profile. + */ +nullable(1) +uint64_t netprof_get_packet_count_total(const Net_Profile *profile, Packet_Direction dir); + +/** + * Returns the number of bytes sent or received of packet type `id` for the given profile. + */ +nullable(1) +uint64_t netprof_get_bytes_id(const Net_Profile *profile, uint8_t id, Packet_Direction dir); + +/** + * Returns the total number of bytes sent or received for the given profile. + */ +nullable(1) +uint64_t netprof_get_bytes_total(const Net_Profile *profile, Packet_Direction dir); + +#endif /* C_TOXCORE_TOXCORE_NET_PROFILE_H */ diff --git a/toxcore/network.c b/toxcore/network.c index 55aa4e28184..775a90b9bdc 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -86,6 +86,7 @@ #include "ccompat.h" #include "logger.h" #include "mem.h" +#include "net_profile.h" #include "util.h" // Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD @@ -812,9 +813,15 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu } int net_send(const Network *ns, const Logger *log, - Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port) + Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port, Net_Profile *net_profile) { const int res = ns->funcs->send(ns->obj, sock, buf, len); + + if (buf != nullptr && res == len) { + const uint8_t *data = buf; + netprof_record_packet(net_profile, data[0], len, PACKET_DIRECTION_SENT); + } + loglogdata(log, "T=>", buf, len, ip_port, res); return res; } @@ -914,6 +921,8 @@ struct Networking_Core { uint16_t port; /* Our UDP socket. */ Socket sock; + + Net_Profile udp_net_profile; }; Family net_family(const Networking_Core *net) @@ -929,7 +938,7 @@ uint16_t net_port(const Networking_Core *net) /* Basic network functions: */ -int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packet) +int send_packet(Networking_Core *net, const IP_Port *ip_port, Packet packet) { IP_Port ipp_copy = *ip_port; @@ -999,6 +1008,11 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe loglogdata(net->log, "O=>", packet.data, packet.length, ip_port, res); assert(res <= INT_MAX); + + if (res == packet.length) { + netprof_record_packet(&net->udp_net_profile, packet.data[0], packet.length, PACKET_DIRECTION_SENT); + } + return (int)res; } @@ -1007,7 +1021,7 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe * * @deprecated Use send_packet instead. */ -int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t *data, uint16_t length) +int sendpacket(Networking_Core *net, const IP_Port *ip_port, const uint8_t *data, uint16_t length) { const Packet packet = {data, length}; return send_packet(net, ip_port, packet); @@ -1087,7 +1101,7 @@ void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handl net->packethandlers[byte].object = object; } -void networking_poll(const Networking_Core *net, void *userdata) +void networking_poll(Networking_Core *net, void *userdata) { if (net_family_is_unspec(net->family)) { /* Socket not initialized */ @@ -1103,6 +1117,8 @@ void networking_poll(const Networking_Core *net, void *userdata) continue; } + netprof_record_packet(&net->udp_net_profile, data[0], length, PACKET_DIRECTION_RECV); + const Packet_Handler *const handler = &net->packethandlers[data[0]]; if (handler->function == nullptr) { @@ -2296,3 +2312,12 @@ void net_kill_strerror(char *strerror) free(strerror); #endif /* OS_WIN32 */ } + +const Net_Profile *net_get_net_profile(const Networking_Core *net) +{ + if (net == nullptr) { + return nullptr; + } + + return &net->udp_net_profile; +} diff --git a/toxcore/network.h b/toxcore/network.h index 06857b89179..e7bfaeb5c0a 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -17,6 +17,7 @@ #include "bin_pack.h" #include "logger.h" #include "mem.h" +#include "net_profile.h" #ifdef __cplusplus extern "C" { @@ -234,8 +235,9 @@ Socket net_invalid_socket(void); /** * Calls send(sockfd, buf, len, MSG_NOSIGNAL). */ -non_null() -int net_send(const Network *ns, const Logger *log, Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port); +non_null(1, 2, 4, 6) nullable(7) +int net_send(const Network *ns, const Logger *log, Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port, + Net_Profile *net_profile); /** * Calls recv(sockfd, buf, len, MSG_NOSIGNAL). */ @@ -477,7 +479,7 @@ typedef struct Packet { * Function to send a network packet to a given IP/port. */ non_null() -int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packet); +int send_packet(Networking_Core *net, const IP_Port *ip_port, Packet packet); /** * Function to send packet(data) of length length to ip_port. @@ -485,7 +487,7 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe * @deprecated Use send_packet instead. */ non_null() -int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t *data, uint16_t length); +int sendpacket(Networking_Core *net, const IP_Port *ip_port, const uint8_t *data, uint16_t length); /** Function to call when packet beginning with byte is received. */ non_null(1) nullable(3, 4) @@ -493,7 +495,7 @@ void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handl /** Call this several times a second. */ non_null(1) nullable(2) -void networking_poll(const Networking_Core *net, void *userdata); +void networking_poll(Networking_Core *net, void *userdata); /** @brief Connect a socket to the address specified by the ip_port. * @@ -603,6 +605,13 @@ Networking_Core *new_networking_no_udp(const Logger *log, const Memory *mem, con nullable(1) void kill_networking(Networking_Core *net); +/** @brief Returns a pointer to the network net_profile object associated with `net`. + * + * Returns null if `net` is null. + */ +non_null() +const Net_Profile *net_get_net_profile(const Networking_Core *net); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/toxcore/onion.c b/toxcore/onion.c index 9fab57af90a..175169a8974 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c @@ -292,7 +292,7 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac * return -1 on failure. * return 0 on success. */ -int send_onion_response(const Logger *log, const Networking_Core *net, +int send_onion_response(const Logger *log, Networking_Core *net, const IP_Port *dest, const uint8_t *data, uint16_t length, const uint8_t *ret) { diff --git a/toxcore/onion.h b/toxcore/onion.h index a5d3554e7b0..7394fb89bc5 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h @@ -130,7 +130,7 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac * return 0 on success. */ non_null() -int send_onion_response(const Logger *log, const Networking_Core *net, +int send_onion_response(const Logger *log, Networking_Core *net, const IP_Port *dest, const uint8_t *data, uint16_t length, const uint8_t *ret); diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 593d81aa2ca..8a34c4193a2 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -193,7 +193,7 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_ * return 0 on success. */ int send_announce_request( - const Logger *log, const Networking_Core *net, const Random *rng, + const Logger *log, Networking_Core *net, const Random *rng, const Onion_Path *path, const Node_format *dest, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, @@ -238,7 +238,7 @@ int send_announce_request( * return 0 on success. */ int send_data_request( - const Logger *log, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, + const Logger *log, Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) { diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index 11580931709..b5f9cf559f5 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h @@ -101,7 +101,7 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_ */ non_null() int send_announce_request( - const Logger *log, const Networking_Core *net, const Random *rng, + const Logger *log, Networking_Core *net, const Random *rng, const Onion_Path *path, const Node_format *dest, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, @@ -125,7 +125,7 @@ int send_announce_request( */ non_null() int send_data_request( - const Logger *log, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, + const Logger *log, Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); diff --git a/toxcore/tox.c b/toxcore/tox.c index 03e34414a8e..652db6b737e 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2018 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013 Tox project. */ @@ -18,6 +18,7 @@ #include "DHT.h" #include "Messenger.h" #include "TCP_client.h" +#include "TCP_server.h" #include "attributes.h" #include "ccompat.h" #include "crypto_core.h" diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c index 7b6050a9f8b..dfab730e91d 100644 --- a/toxcore/tox_private.c +++ b/toxcore/tox_private.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2022 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013 Tox project. */ @@ -11,13 +11,16 @@ #include #include "DHT.h" +#include "TCP_server.h" #include "attributes.h" #include "ccompat.h" #include "crypto_core.h" #include "group_chats.h" #include "group_common.h" +#include "logger.h" #include "mem.h" #include "net_crypto.h" +#include "net_profile.h" #include "network.h" #include "tox.h" #include "tox_struct.h" @@ -226,3 +229,199 @@ bool tox_group_peer_get_ip_address(const Tox *tox, uint32_t group_number, uint32 SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK); return true; } + +uint64_t tox_netprof_get_packet_id_count(const Tox *tox, Tox_Netprof_Packet_Type type, uint8_t id, + Tox_Netprof_Direction direction) +{ + assert(tox != nullptr); + + tox_lock(tox); + + const Net_Profile *tcp_c_profile = nc_get_tcp_client_net_profile(tox->m->net_crypto); + const Net_Profile *tcp_s_profile = tcp_server_get_net_profile(tox->m->tcp_server); + + const Packet_Direction dir = (Packet_Direction) direction; + + uint64_t count = 0; + + switch (type) { + case TOX_NETPROF_PACKET_TYPE_TCP_CLIENT: { + count = netprof_get_packet_count_id(tcp_c_profile, id, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP_SERVER: { + count = netprof_get_packet_count_id(tcp_s_profile, id, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP: { + const uint64_t tcp_c_count = netprof_get_packet_count_id(tcp_c_profile, id, dir); + const uint64_t tcp_s_count = netprof_get_packet_count_id(tcp_s_profile, id, dir); + count = tcp_c_count + tcp_s_count; + break; + } + + case TOX_NETPROF_PACKET_TYPE_UDP: { + const Net_Profile *udp_profile = net_get_net_profile(tox->m->net); + count = netprof_get_packet_count_id(udp_profile, id, dir); + break; + } + + default: { + LOGGER_ERROR(tox->m->log, "invalid packet type: %d", type); + break; + } + } + + tox_unlock(tox); + + return count; +} + +uint64_t tox_netprof_get_packet_total_count(const Tox *tox, Tox_Netprof_Packet_Type type, + Tox_Netprof_Direction direction) +{ + assert(tox != nullptr); + + tox_lock(tox); + + const Net_Profile *tcp_c_profile = nc_get_tcp_client_net_profile(tox->m->net_crypto); + const Net_Profile *tcp_s_profile = tcp_server_get_net_profile(tox->m->tcp_server); + + const Packet_Direction dir = (Packet_Direction) direction; + + uint64_t count = 0; + + switch (type) { + case TOX_NETPROF_PACKET_TYPE_TCP_CLIENT: { + count = netprof_get_packet_count_total(tcp_c_profile, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP_SERVER: { + count = netprof_get_packet_count_total(tcp_s_profile, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP: { + const uint64_t tcp_c_count = netprof_get_packet_count_total(tcp_c_profile, dir); + const uint64_t tcp_s_count = netprof_get_packet_count_total(tcp_s_profile, dir); + count = tcp_c_count + tcp_s_count; + break; + } + + case TOX_NETPROF_PACKET_TYPE_UDP: { + const Net_Profile *udp_profile = net_get_net_profile(tox->m->net); + count = netprof_get_packet_count_total(udp_profile, dir); + break; + } + + default: { + LOGGER_ERROR(tox->m->log, "invalid packet type: %d", type); + break; + } + } + + tox_unlock(tox); + + return count; +} + +uint64_t tox_netprof_get_packet_id_bytes(const Tox *tox, Tox_Netprof_Packet_Type type, uint8_t id, + Tox_Netprof_Direction direction) +{ + assert(tox != nullptr); + + tox_lock(tox); + + const Net_Profile *tcp_c_profile = nc_get_tcp_client_net_profile(tox->m->net_crypto); + const Net_Profile *tcp_s_profile = tcp_server_get_net_profile(tox->m->tcp_server); + + const Packet_Direction dir = (Packet_Direction) direction; + + uint64_t bytes = 0; + + switch (type) { + case TOX_NETPROF_PACKET_TYPE_TCP_CLIENT: { + bytes = netprof_get_bytes_id(tcp_c_profile, id, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP_SERVER: { + bytes = netprof_get_bytes_id(tcp_s_profile, id, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP: { + const uint64_t tcp_c_bytes = netprof_get_bytes_id(tcp_c_profile, id, dir); + const uint64_t tcp_s_bytes = netprof_get_bytes_id(tcp_s_profile, id, dir); + bytes = tcp_c_bytes + tcp_s_bytes; + break; + } + + case TOX_NETPROF_PACKET_TYPE_UDP: { + const Net_Profile *udp_profile = net_get_net_profile(tox->m->net); + bytes = netprof_get_bytes_id(udp_profile, id, dir); + break; + } + + default: { + LOGGER_ERROR(tox->m->log, "invalid packet type: %d", type); + break; + } + } + + tox_unlock(tox); + + return bytes; +} + +uint64_t tox_netprof_get_packet_total_bytes(const Tox *tox, Tox_Netprof_Packet_Type type, + Tox_Netprof_Direction direction) +{ + assert(tox != nullptr); + + tox_lock(tox); + + const Net_Profile *tcp_c_profile = nc_get_tcp_client_net_profile(tox->m->net_crypto); + const Net_Profile *tcp_s_profile = tcp_server_get_net_profile(tox->m->tcp_server); + + const Packet_Direction dir = (Packet_Direction) direction; + + uint64_t bytes = 0; + + switch (type) { + case TOX_NETPROF_PACKET_TYPE_TCP_CLIENT: { + bytes = netprof_get_bytes_total(tcp_c_profile, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP_SERVER: { + bytes = netprof_get_bytes_total(tcp_s_profile, dir); + break; + } + + case TOX_NETPROF_PACKET_TYPE_TCP: { + const uint64_t tcp_c_bytes = netprof_get_bytes_total(tcp_c_profile, dir); + const uint64_t tcp_s_bytes = netprof_get_bytes_total(tcp_s_profile, dir); + bytes = tcp_c_bytes + tcp_s_bytes; + break; + } + + case TOX_NETPROF_PACKET_TYPE_UDP: { + const Net_Profile *udp_profile = net_get_net_profile(tox->m->net); + bytes = netprof_get_bytes_total(udp_profile, dir); + break; + } + + default: { + LOGGER_ERROR(tox->m->log, "invalid packet type: %d", type); + break; + } + } + + tox_unlock(tox); + + return bytes; +} diff --git a/toxcore/tox_private.h b/toxcore/tox_private.h index fe86479a5dd..afb4c92d61a 100644 --- a/toxcore/tox_private.h +++ b/toxcore/tox_private.h @@ -171,6 +171,256 @@ uint16_t tox_dht_get_num_closelist(const Tox *tox); */ uint16_t tox_dht_get_num_closelist_announce_capable(const Tox *tox); +/******************************************************************************* + * + * :: Network profiler + * + ******************************************************************************/ + + +/** + * Represents all of the network packet identifiers that Toxcore uses. + * + * Note: Some packet ID's have different purposes depending on the + * packet type. These ID's are given numeral names. + */ +typedef enum Tox_Netprof_Packet_Id { + /** + * Ping request packet (UDP). + * Routing request (TCP). + */ + TOX_NETPROF_PACKET_ID_ZERO = 0x00, + + /** + * Ping response packet (UDP). + * Routing response (TCP). + */ + TOX_NETPROF_PACKET_ID_ONE = 0x01, + + /** + * Get nodes request packet (UDP). + * Connection notification (TCP). + */ + TOX_NETPROF_PACKET_ID_TWO = 0x02, + + /** + * TCP disconnect notification. + */ + TOX_NETPROF_PACKET_ID_TCP_DISCONNECT = 0x03, + + /** + * Send nodes response packet (UDP). + * Ping packet (TCP). + */ + TOX_NETPROF_PACKET_ID_FOUR = 0x04, + + /** + * TCP pong packet. + */ + TOX_NETPROF_PACKET_ID_TCP_PONG = 0x05, + + /** + * TCP out-of-band send packet. + */ + TOX_NETPROF_PACKET_ID_TCP_OOB_SEND = 0x06, + + /** + * TCP out-of-band receive packet. + */ + TOX_NETPROF_PACKET_ID_TCP_OOB_RECV = 0x07, + + /** + * TCP onion request packet. + */ + TOX_NETPROF_PACKET_ID_TCP_ONION_REQUEST = 0x08, + + /** + * TCP onion response packet. + */ + TOX_NETPROF_PACKET_ID_TCP_ONION_RESPONSE = 0x09, + + /** + * TCP data packet. + */ + TOX_NETPROF_PACKET_ID_TCP_DATA = 0x10, + + /** + * Cookie request packet. + */ + TOX_NETPROF_PACKET_ID_COOKIE_REQUEST = 0x18, + + /** + * Cookie response packet. + */ + TOX_NETPROF_PACKET_ID_COOKIE_RESPONSE = 0x19, + + /** + * Crypto handshake packet. + */ + TOX_NETPROF_PACKET_ID_CRYPTO_HS = 0x1a, + + /** + * Crypto data packet. + */ + TOX_NETPROF_PACKET_ID_CRYPTO_DATA = 0x1b, + + /** + * Encrypted data packet. + */ + TOX_NETPROF_PACKET_ID_CRYPTO = 0x20, + + /** + * LAN discovery packet. + */ + TOX_NETPROF_PACKET_ID_LAN_DISCOVERY = 0x21, + + /** + * DHT groupchat packets. + */ + TOX_NETPROF_PACKET_ID_GC_HANDSHAKE = 0x5a, + TOX_NETPROF_PACKET_ID_GC_LOSSLESS = 0x5b, + TOX_NETPROF_PACKET_ID_GC_LOSSY = 0x5c, + + /** + * Onion send packets. + */ + TOX_NETPROF_PACKET_ID_ONION_SEND_INITIAL = 0x80, + TOX_NETPROF_PACKET_ID_ONION_SEND_1 = 0x81, + TOX_NETPROF_PACKET_ID_ONION_SEND_2 = 0x82, + + /** + * DHT announce request packet (deprecated). + */ + TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST_OLD = 0x83, + + /** + * DHT announce response packet (deprecated). + */ + TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE_OLD = 0x84, + + /** + * Onion data request packet. + */ + TOX_NETPROF_PACKET_ID_ONION_DATA_REQUEST = 0x85, + + /** + * Onion data response packet. + */ + TOX_NETPROF_PACKET_ID_ONION_DATA_RESPONSE = 0x86, + + /** + * DHT announce request packet. + */ + TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST = 0x87, + + /** + * DHT announce response packet. + */ + TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE = 0x88, + + /** + * Onion receive packets. + */ + TOX_NETPROF_PACKET_ID_ONION_RECV_3 = 0x8c, + TOX_NETPROF_PACKET_ID_ONION_RECV_2 = 0x8d, + TOX_NETPROF_PACKET_ID_ONION_RECV_1 = 0x8e, + + TOX_NETPROF_PACKET_ID_FORWARD_REQUEST = 0x90, + TOX_NETPROF_PACKET_ID_FORWARDING = 0x91, + TOX_NETPROF_PACKET_ID_FORWARD_REPLY = 0x92, + + TOX_NETPROF_PACKET_ID_DATA_SEARCH_REQUEST = 0x93, + TOX_NETPROF_PACKET_ID_DATA_SEARCH_RESPONSE = 0x94, + TOX_NETPROF_PACKET_ID_DATA_RETRIEVE_REQUEST = 0x95, + TOX_NETPROF_PACKET_ID_DATA_RETRIEVE_RESPONSE = 0x96, + TOX_NETPROF_PACKET_ID_STORE_ANNOUNCE_REQUEST = 0x97, + TOX_NETPROF_PACKET_ID_STORE_ANNOUNCE_RESPONSE = 0x98, + + /** + * Bootstrap info packet. + */ + TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO = 0xf0, +} Tox_Netprof_Packet_Id; + +/** + * Specifies the packet type for a given query. + */ +typedef enum Tox_Netprof_Packet_Type { + /** + * TCP client packets. + */ + TOX_NETPROF_PACKET_TYPE_TCP_CLIENT, + + /** + * TCP server packets. + */ + TOX_NETPROF_PACKET_TYPE_TCP_SERVER, + + /** + * Combined TCP server and TCP client packets. + */ + TOX_NETPROF_PACKET_TYPE_TCP, + + /** + * UDP packets. + */ + TOX_NETPROF_PACKET_TYPE_UDP, +} Tox_Netprof_Packet_Type; + +/** + * Specifies the packet direction for a given query. + */ +typedef enum Tox_Netprof_Direction { + /** + * Outbound packets. + */ + TOX_NETPROF_DIRECTION_SENT, + + /** + * Inbound packets. + */ + TOX_NETPROF_DIRECTION_RECV, +} Tox_Netprof_Direction; + +/** + * Return the number of packets sent or received for a specific packet ID. + * + * @param type The types of packets being queried. + * @param id The packet ID being queried. + * @param direction The packet direction. + */ +uint64_t tox_netprof_get_packet_id_count(const Tox *tox, Tox_Netprof_Packet_Type type, uint8_t id, + Tox_Netprof_Direction direction); + +/** + * Return the total number of packets sent or received. + * + * @param type The types of packets being queried. + * @param direction The packet direction. + */ +uint64_t tox_netprof_get_packet_total_count(const Tox *tox, Tox_Netprof_Packet_Type type, + Tox_Netprof_Direction direction); + +/** + * Return the number of bytes sent or received for a specific packet ID. + * + * @param type The types of packets being queried. + * @param id The packet ID being queried. + * @param direction The packet direction. + */ +uint64_t tox_netprof_get_packet_id_bytes(const Tox *tox, Tox_Netprof_Packet_Type type, uint8_t id, + Tox_Netprof_Direction direction); + +/** + * Return the total number of bytes sent or received. + * + * @param type The types of packets being queried. + * @param direction The packet direction. + */ +uint64_t tox_netprof_get_packet_total_bytes(const Tox *tox, Tox_Netprof_Packet_Type type, + Tox_Netprof_Direction direction); + + /******************************************************************************* * * :: DHT groupchat queries.