diff --git a/.gitignore b/.gitignore index 33b7971069..33d31c037c 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 4d6cf22fa9..9237d21c11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,6 +309,8 @@ set(toxcore_SOURCES toxcore/mono_time.h toxcore/net_crypto.c toxcore/net_crypto.h + toxcore/net_profile.c + toxcore/net_profile.h toxcore/network.c toxcore/network.h toxcore/onion_announce.c diff --git a/auto_tests/CMakeLists.txt b/auto_tests/CMakeLists.txt index 8413e1d144..996846b2d3 100644 --- a/auto_tests/CMakeLists.txt +++ b/auto_tests/CMakeLists.txt @@ -71,6 +71,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 4a13ef2481..1cf7748efa 100644 --- a/auto_tests/TCP_test.c +++ b/auto_tests/TCP_test.c @@ -112,12 +112,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); @@ -156,7 +156,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; @@ -242,12 +242,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); @@ -291,7 +291,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; } @@ -535,7 +535,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); ck_assert_msg(conn != nullptr, "Failed to create a TCP client connection."); // TCP sockets might need a moment before they can be written to. c_sleep(50); @@ -572,7 +572,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); ck_assert_msg(conn2 != nullptr, "Failed to create a second TCP client connection."); c_sleep(50); @@ -670,7 +670,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); ck_assert_msg(conn != nullptr, "Failed to create a TCP client connection."); // Run the client's main loop but not the server. diff --git a/auto_tests/netprof_test.c b/auto_tests/netprof_test.c new file mode 100644 index 0000000000..6b1fcd8146 --- /dev/null +++ b/auto_tests/netprof_test.c @@ -0,0 +1,134 @@ +/** Auto Tests: basic network profile functionality test (UDP only) + */ + +#include +#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 uint64_t UDP_count_sent1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t UDP_count_recv1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_RECV); + const uint64_t TCP_count_sent1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t TCP_count_recv1 = tox_netprof_get_packet_total_count(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_RECV); + + const uint64_t UDP_bytes_sent1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t UDP_bytes_recv1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_RECV); + const uint64_t TCP_bytes_sent1 = tox_netprof_get_packet_total_bytes(tox1, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t 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; + + uint64_t total_sent_count = 0; + uint64_t total_recv_count = 0; + uint64_t total_sent_bytes = 0; + uint64_t 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 uint64_t total_packets = total_sent_count + total_recv_count; + ck_assert_msg(total_packets == UDP_count_sent1 + UDP_count_recv1, + "%" PRIu64 "does not match %" PRIu64 "\n", total_packets, UDP_count_sent1 + UDP_count_recv1); + + ck_assert_msg(total_sent_count == UDP_count_sent1, "%" PRIu64 " does not match %" PRIu64 "\n", total_sent_count, UDP_count_sent1); + ck_assert_msg(total_recv_count == UDP_count_recv1, "%" PRIu64 " does not match %" PRIu64"\n", total_recv_count, UDP_count_recv1); + + + const uint64_t total_bytes = total_sent_bytes + total_recv_bytes; + ck_assert_msg(total_bytes == UDP_bytes_sent1 + UDP_bytes_recv1, + "%" PRIu64 "does not match %" PRIu64 "\n", total_bytes, UDP_bytes_sent1 + UDP_bytes_recv1); + + ck_assert_msg(total_sent_bytes == UDP_bytes_sent1, "%" PRIu64 " does not match %" PRIu64 "\n", total_sent_bytes, UDP_bytes_sent1); + ck_assert_msg(total_recv_bytes == UDP_bytes_recv1, "%" PRIu64 " does not match %" PRIu64 "\n", total_recv_bytes, UDP_bytes_recv1); +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + + Tox_Err_Options_New options_err; + struct Tox_Options *tox_opts = tox_options_new(&options_err); + + ck_assert_msg(options_err == TOX_ERR_OPTIONS_NEW_OK, "Failed to initialize tox options: %d\n", options_err); + + tox_options_default(tox_opts); + tox_options_set_udp_enabled(tox_opts, true); + + Run_Auto_Options autotox_opts = default_run_auto_options(); + autotox_opts.graph = GRAPH_COMPLETE; + + run_auto_test(tox_opts, NUM_TOXES, test_netprof, 0, &autotox_opts); + + // TODO(Jfreegman): uncomment this when TCP autotests are fixed + // tox_options_set_udp_enabled(tox_opts, false); + // run_auto_test(tox_opts, NUM_TOXES, test_netprof, 0, &autotox_opts); + + tox_options_free(tox_opts); + + return 0; +} + +#undef NUM_TOXES diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index 8b9204cc20..8bbd870f69 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -350,6 +350,18 @@ cc_library( ], ) +cc_library( + name = "net_profile", + srcs = ["net_profile.c"], + hdrs = ["net_profile.h"], + deps = [ + ":attributes", + ":ccompat", + ":logger", + ":mem", + ], +) + cc_library( name = "network", srcs = ["network.c"], @@ -369,6 +381,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":util", "@libsodium", "@psocket", @@ -635,6 +648,7 @@ cc_library( ":crypto_core", ":logger", ":mem", + ":net_profile", ":network", ], ) @@ -662,6 +676,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":onion", ":util", @@ -683,6 +698,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":util", ], @@ -705,6 +721,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":onion", ":util", @@ -742,6 +759,7 @@ cc_library( ":logger", ":mem", ":mono_time", + ":net_profile", ":network", ":util", "@pthread", @@ -1069,6 +1087,7 @@ cc_library( ":DHT", ":Messenger", ":TCP_client", + ":TCP_server", ":attributes", ":ccompat", ":crypto_core", @@ -1079,6 +1098,7 @@ cc_library( ":mem", ":mono_time", ":net_crypto", + ":net_profile", ":network", ":onion_client", ":state", diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index d4d64bcdb8..2ee4a72f25 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 f80575b0a5..1982412cda 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" @@ -594,7 +595,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); @@ -659,6 +660,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); @@ -845,6 +847,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 de61880b29..3ed6e8c683 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 0782cb98c1..e9f67dcffb 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 8784163325..dd07fd1ec5 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 3064660889..20ac3ce061 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; @@ -1609,6 +1614,14 @@ TCP_Connections *new_tcp_connections(const Logger *logger, const Memory *mem, co return nullptr; } + Net_Profile *np = netprof_new(logger, mem); + + if (np == nullptr) { + mem_delete(mem, temp); + return nullptr; + } + + temp->net_profile = np; temp->logger = logger; temp->mem = mem; temp->rng = rng; @@ -1723,7 +1736,17 @@ void kill_tcp_connections(TCP_Connections *tcp_c) crypto_memzero(tcp_c->self_secret_key, sizeof(tcp_c->self_secret_key)); + netprof_kill(tcp_c->mem, tcp_c->net_profile); mem_delete(tcp_c->mem, tcp_c->tcp_connections); 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 19c47119f0..33388d5f8b 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 186431b1df..f5b32d9c5f 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: { @@ -969,6 +975,14 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random return nullptr; } + Net_Profile *np = netprof_new(logger, mem); + + if (np == nullptr) { + mem_delete(mem, temp); + return nullptr; + } + + temp->net_profile = np; temp->logger = logger; temp->mem = mem; temp->ns = ns; @@ -978,6 +992,7 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random if (socks_listening == nullptr) { LOGGER_ERROR(logger, "socket allocation failed"); + netprof_kill(mem, temp->net_profile); mem_delete(mem, temp); return nullptr; } @@ -989,6 +1004,7 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random if (temp->efd == -1) { LOGGER_ERROR(logger, "epoll initialisation failed"); + netprof_kill(mem, temp->net_profile); mem_delete(mem, socks_listening); mem_delete(mem, temp); return nullptr; @@ -1022,6 +1038,7 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random } if (temp->num_listening_socks == 0) { + netprof_kill(mem, temp->net_profile); mem_delete(mem, temp->socks_listening); mem_delete(mem, temp); return nullptr; @@ -1422,6 +1439,16 @@ void kill_tcp_server(TCP_Server *tcp_server) crypto_memzero(tcp_server->secret_key, sizeof(tcp_server->secret_key)); + netprof_kill(tcp_server->mem, tcp_server->net_profile); 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 b91125af7d..bd4c98b0cd 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/net_crypto.c b/toxcore/net_crypto.c index b957c03b31..b9602415c6 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -24,6 +24,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" #include "util.h" @@ -3097,3 +3098,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 9f4cbf06d2..c21ac7d217 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h @@ -17,6 +17,7 @@ #include "logger.h" #include "mem.h" #include "mono_time.h" +#include "net_profile.h" #include "network.h" /*** Crypto payloads. */ @@ -414,4 +415,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 0000000000..bbff79c94c --- /dev/null +++ b/toxcore/net_profile.c @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 The TokTok team. + */ + +/** + * Functions for the network profile. + */ + +#include "net_profile.h" + +#include + +#include "attributes.h" +#include "logger.h" +#include "mem.h" + +#include "ccompat.h" + +#define NETPROF_TCP_DATA_PACKET_ID 0x10 + +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; + +/** 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_SEND ? 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_SEND ? 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_SEND) { + ++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_SEND ? 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_SEND ? 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_SEND ? 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_SEND ? profile->total_bytes_sent : profile->total_bytes_recv; +} + +Net_Profile *netprof_new(const Logger *log, const Memory *mem) +{ + Net_Profile *np = (Net_Profile *)mem_alloc(mem, sizeof(Net_Profile)); + + if (np == nullptr) { + LOGGER_ERROR(log, "failed to allocate memory for net profiler"); + return nullptr; + } + + return np; +} + +void netprof_kill(const Memory *mem, Net_Profile *net_profile) +{ + if (net_profile != nullptr) { + mem_delete(mem, net_profile); + } +} diff --git a/toxcore/net_profile.h b/toxcore/net_profile.h new file mode 100644 index 0000000000..a2f66a19ff --- /dev/null +++ b/toxcore/net_profile.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 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" +#include "logger.h" +#include "mem.h" + +/* The max number of packet ID's (must fit inside one byte) */ +#define NET_PROF_MAX_PACKET_IDS 256 + +/* If passed to a netprof function as a nullptr the function will have no effect. */ +typedef struct Net_Profile Net_Profile; + +/** Specifies whether the query is for sent or received packets. */ +typedef enum Packet_Direction { + PACKET_DIRECTION_SEND, + 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); + +/** + * Returns a new net_profile object. The caller is responsible for freeing the + * returned memory via `netprof_kill`. + */ +non_null() +Net_Profile *netprof_new(const Logger *log, const Memory *mem); + +/** + * Kills a net_profile object and frees all associated memory. + */ +non_null(1) nullable(2) +void netprof_kill(const Memory *mem, Net_Profile *net_profile); + +#endif /* C_TOXCORE_TOXCORE_NET_PROFILE_H */ diff --git a/toxcore/network.c b/toxcore/network.c index 06ebe8f177..396d56b215 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 @@ -907,9 +908,14 @@ 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 (res > 0) { + netprof_record_packet(net_profile, buf[0], res, PACKET_DIRECTION_SEND); + } + loglogdata(log, "T=>", buf, len, ip_port, res); return res; } @@ -1013,6 +1019,8 @@ struct Networking_Core { uint16_t port; /* Our UDP socket. */ Socket sock; + + Net_Profile *udp_net_profile; }; Family net_family(const Networking_Core *net) @@ -1098,6 +1106,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 && packet.data != nullptr) { + netprof_record_packet(net->udp_net_profile, packet.data[0], packet.length, PACKET_DIRECTION_SEND); + } + return (int)res; } @@ -1202,6 +1215,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) { @@ -1262,6 +1277,14 @@ Networking_Core *new_networking_ex( return nullptr; } + Net_Profile *np = netprof_new(log, mem); + + if (np == nullptr) { + free(temp); + return nullptr; + } + + temp->udp_net_profile = np; temp->ns = ns; temp->log = log; temp->mem = mem; @@ -1278,6 +1301,7 @@ Networking_Core *new_networking_ex( char *strerror = net_new_strerror(neterror); LOGGER_ERROR(log, "failed to get a socket?! %d, %s", neterror, strerror); net_kill_strerror(strerror); + netprof_kill(mem, temp->udp_net_profile); mem_delete(mem, temp); if (error != nullptr) { @@ -1485,6 +1509,7 @@ void kill_networking(Networking_Core *net) kill_sock(net->ns, net->sock); } + netprof_kill(net->mem, net->udp_net_profile); mem_delete(net->mem, net); } @@ -2411,3 +2436,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 40dd2dee53..41d7eafda9 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" { @@ -236,8 +237,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). */ @@ -623,6 +625,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/tox_api.c b/toxcore/tox_api.c index d6996de7c8..7988018be5 100644 --- a/toxcore/tox_api.c +++ b/toxcore/tox_api.c @@ -1722,3 +1722,120 @@ const char *tox_group_mod_event_to_string(Tox_Group_Mod_Event value) return ""; } +const char *tox_netprof_packet_id_to_string(Tox_Netprof_Packet_Id value) +{ + switch (value) { + case TOX_NETPROF_PACKET_ID_ZERO: + return "TOX_NETPROF_PACKET_ID_ZERO"; + case TOX_NETPROF_PACKET_ID_ONE: + return "TOX_NETPROF_PACKET_ID_ONE"; + case TOX_NETPROF_PACKET_ID_TWO: + return "TOX_NETPROF_PACKET_ID_TWO"; + case TOX_NETPROF_PACKET_ID_TCP_DISCONNECT: + return "TOX_NETPROF_PACKET_ID_TCP_DISCONNECT"; + case TOX_NETPROF_PACKET_ID_FOUR: + return "TOX_NETPROF_PACKET_ID_FOUR"; + case TOX_NETPROF_PACKET_ID_TCP_PONG: + return "TOX_NETPROF_PACKET_ID_TCP_PONG"; + case TOX_NETPROF_PACKET_ID_TCP_OOB_SEND: + return "TOX_NETPROF_PACKET_ID_TCP_OOB_SEND"; + case TOX_NETPROF_PACKET_ID_TCP_OOB_RECV: + return "TOX_NETPROF_PACKET_ID_TCP_OOB_RECV"; + case TOX_NETPROF_PACKET_ID_TCP_ONION_REQUEST: + return "TOX_NETPROF_PACKET_ID_TCP_ONION_REQUEST"; + case TOX_NETPROF_PACKET_ID_TCP_ONION_RESPONSE: + return "TOX_NETPROF_PACKET_ID_TCP_ONION_RESPONSE"; + case TOX_NETPROF_PACKET_ID_TCP_DATA: + return "TOX_NETPROF_PACKET_ID_TCP_DATA"; + case TOX_NETPROF_PACKET_ID_COOKIE_REQUEST: + return "TOX_NETPROF_PACKET_ID_COOKIE_REQUEST"; + case TOX_NETPROF_PACKET_ID_COOKIE_RESPONSE: + return "TOX_NETPROF_PACKET_ID_COOKIE_RESPONSE"; + case TOX_NETPROF_PACKET_ID_CRYPTO_HS: + return "TOX_NETPROF_PACKET_ID_CRYPTO_HS"; + case TOX_NETPROF_PACKET_ID_CRYPTO_DATA: + return "TOX_NETPROF_PACKET_ID_CRYPTO_DATA"; + case TOX_NETPROF_PACKET_ID_CRYPTO: + return "TOX_NETPROF_PACKET_ID_CRYPTO"; + case TOX_NETPROF_PACKET_ID_LAN_DISCOVERY: + return "TOX_NETPROF_PACKET_ID_LAN_DISCOVERY"; + case TOX_NETPROF_PACKET_ID_GC_HANDSHAKE: + return "TOX_NETPROF_PACKET_ID_GC_HANDSHAKE"; + case TOX_NETPROF_PACKET_ID_GC_LOSSLESS: + return "TOX_NETPROF_PACKET_ID_GC_LOSSLESS"; + case TOX_NETPROF_PACKET_ID_GC_LOSSY: + return "TOX_NETPROF_PACKET_ID_GC_LOSSY"; + case TOX_NETPROF_PACKET_ID_ONION_SEND_INITIAL: + return "TOX_NETPROF_PACKET_ID_ONION_SEND_INITIAL"; + case TOX_NETPROF_PACKET_ID_ONION_SEND_1: + return "TOX_NETPROF_PACKET_ID_ONION_SEND_1"; + case TOX_NETPROF_PACKET_ID_ONION_SEND_2: + return "TOX_NETPROF_PACKET_ID_ONION_SEND_2"; + case TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST_OLD: + return "TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST_OLD"; + case TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE_OLD: + return "TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE_OLD"; + case TOX_NETPROF_PACKET_ID_ONION_DATA_REQUEST: + return "TOX_NETPROF_PACKET_ID_ONION_DATA_REQUEST"; + case TOX_NETPROF_PACKET_ID_ONION_DATA_RESPONSE: + return "TOX_NETPROF_PACKET_ID_ONION_DATA_RESPONSE"; + case TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST: + return "TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST"; + case TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE: + return "TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE"; + case TOX_NETPROF_PACKET_ID_ONION_RECV_3: + return "TOX_NETPROF_PACKET_ID_ONION_RECV_3"; + case TOX_NETPROF_PACKET_ID_ONION_RECV_2: + return "TOX_NETPROF_PACKET_ID_ONION_RECV_2"; + case TOX_NETPROF_PACKET_ID_ONION_RECV_1: + return "TOX_NETPROF_PACKET_ID_ONION_RECV_1"; + case TOX_NETPROF_PACKET_ID_FORWARD_REQUEST: + return "TOX_NETPROF_PACKET_ID_FORWARD_REQUEST"; + case TOX_NETPROF_PACKET_ID_FORWARDING: + return "TOX_NETPROF_PACKET_ID_FORWARDING"; + case TOX_NETPROF_PACKET_ID_FORWARD_REPLY: + return "TOX_NETPROF_PACKET_ID_FORWARD_REPLY"; + case TOX_NETPROF_PACKET_ID_DATA_SEARCH_REQUEST: + return "TOX_NETPROF_PACKET_ID_DATA_SEARCH_REQUEST"; + case TOX_NETPROF_PACKET_ID_DATA_SEARCH_RESPONSE: + return "TOX_NETPROF_PACKET_ID_DATA_SEARCH_RESPONSE"; + case TOX_NETPROF_PACKET_ID_DATA_RETRIEVE_REQUEST: + return "TOX_NETPROF_PACKET_ID_DATA_RETRIEVE_REQUEST"; + case TOX_NETPROF_PACKET_ID_DATA_RETRIEVE_RESPONSE: + return "TOX_NETPROF_PACKET_ID_DATA_RETRIEVE_RESPONSE"; + case TOX_NETPROF_PACKET_ID_STORE_ANNOUNCE_REQUEST: + return "TOX_NETPROF_PACKET_ID_STORE_ANNOUNCE_REQUEST"; + case TOX_NETPROF_PACKET_ID_STORE_ANNOUNCE_RESPONSE: + return "TOX_NETPROF_PACKET_ID_STORE_ANNOUNCE_RESPONSE"; + case TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO: + return "TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO"; + } + + return ""; +} +const char *tox_netprof_packet_type_to_string(Tox_Netprof_Packet_Type value) +{ + switch (value) { + case TOX_NETPROF_PACKET_TYPE_TCP_CLIENT: + return "TOX_NETPROF_PACKET_TYPE_TCP_CLIENT"; + case TOX_NETPROF_PACKET_TYPE_TCP_SERVER: + return "TOX_NETPROF_PACKET_TYPE_TCP_SERVER"; + case TOX_NETPROF_PACKET_TYPE_TCP: + return "TOX_NETPROF_PACKET_TYPE_TCP"; + case TOX_NETPROF_PACKET_TYPE_UDP: + return "TOX_NETPROF_PACKET_TYPE_UDP"; + } + + return ""; +} +const char *tox_netprof_direction_to_string(Tox_Netprof_Direction value) +{ + switch (value) { + case TOX_NETPROF_DIRECTION_SENT: + return "TOX_NETPROF_DIRECTION_SENT"; + case TOX_NETPROF_DIRECTION_RECV: + return "TOX_NETPROF_DIRECTION_RECV"; + } + + return ""; +} diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c index e9b6c10fcf..d7e13ac13d 100644 --- a/toxcore/tox_private.c +++ b/toxcore/tox_private.c @@ -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 ac1a14d5cd..cc8a085659 100644 --- a/toxcore/tox_private.h +++ b/toxcore/tox_private.h @@ -169,6 +169,267 @@ 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. + * + * Notes: + * - Some packet ID's have different purposes depending on the + * packet type. These ID's are given numeral names. + * + * - Queries for invalid packet ID's return undefined results. For example, + * querying a TCP-exclusive packet ID for UDP, or querying an ID that + * doesn't exist in this enum. + */ +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; + +const char *tox_netprof_packet_id_to_string(Tox_Netprof_Packet_Id value); + +/** + * 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; + +const char *tox_netprof_packet_type_to_string(Tox_Netprof_Packet_Type value); + +/** + * 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; + +const char *tox_netprof_direction_to_string(Tox_Netprof_Direction value); + +/** + * 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.