From b91f5a87580f0cb4dab26f6202820691561a851d Mon Sep 17 00:00:00 2001 From: jfreegman Date: Sun, 30 Jan 2022 13:18:14 -0500 Subject: [PATCH] Add tox network profiling Profiling can be enabled with the -s run option --- Makefile | 2 +- src/netprof.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/netprof.h | 30 ++++++ src/toxic.c | 46 +++++---- src/windows.h | 3 + 5 files changed, 333 insertions(+), 18 deletions(-) create mode 100644 src/netprof.c create mode 100644 src/netprof.h diff --git a/Makefile b/Makefile index ef62823..6410019 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ LDFLAGS += ${USER_LDFLAGS} OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o conference.o help.o input.o line_info.o -OBJ += log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o +OBJ += log.o message_queue.o misc_tools.o name_lookup.o netprof.o notify.o prompt.o qr_code.o settings.o OBJ += term_mplex.o toxic.o toxic_strings.o windows.o # Check if debug build is enabled diff --git a/src/netprof.c b/src/netprof.c new file mode 100644 index 0000000..8b28021 --- /dev/null +++ b/src/netprof.c @@ -0,0 +1,270 @@ +/* netprof.c + * + * + * Copyright (C) 2022 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#include +#include + +#include "netprof.h" + +#include "../../toxcore/toxcore/tox_private.h" // set this to your local toxcore source directory + +static void log_tcp_packet_id(FILE *fp, unsigned int id, uint64_t total, uint64_t TCP_id_sent, uint64_t TCP_id_recv) +{ + switch (id) { + case TOX_NETPROF_PACKET_ID_ZERO: + case TOX_NETPROF_PACKET_ID_ONE: + case TOX_NETPROF_PACKET_ID_TWO: + case TOX_NETPROF_PACKET_ID_TCP_DISCONNECT: + case TOX_NETPROF_PACKET_ID_FOUR: + case TOX_NETPROF_PACKET_ID_TCP_PONG: + case TOX_NETPROF_PACKET_ID_TCP_OOB_SEND: + case TOX_NETPROF_PACKET_ID_TCP_OOB_RECV: + case TOX_NETPROF_PACKET_ID_TCP_ONION_REQUEST: + case TOX_NETPROF_PACKET_ID_TCP_ONION_RESPONSE: + case TOX_NETPROF_PACKET_ID_TCP_DATA: { + if (TCP_id_recv || TCP_id_sent) { + fprintf(fp, "0x%02x (total): %lu (%.2f%%)\n", id, TCP_id_sent + TCP_id_recv, + ((float)TCP_id_recv + TCP_id_sent) / total * 100.0); + } + + if (TCP_id_sent) { + fprintf(fp, "0x%02x (sent): %lu (%.2f%%)\n", id, TCP_id_sent, (float)TCP_id_sent / total * 100.0); + } + + if (TCP_id_recv) { + fprintf(fp, "0x%02x (recv): %lu (%.2f%%)\n", id, TCP_id_recv, (float)TCP_id_recv / total * 100.0); + } + + break; + } + + default: + return; + } +} +static void log_udp_packet_id(FILE *fp, unsigned int id, uint64_t total, uint64_t UDP_id_sent, uint64_t UDP_id_recv) +{ + switch (id) { + case TOX_NETPROF_PACKET_ID_ZERO: + case TOX_NETPROF_PACKET_ID_ONE: + case TOX_NETPROF_PACKET_ID_TWO: + case TOX_NETPROF_PACKET_ID_FOUR: + case TOX_NETPROF_PACKET_ID_COOKIE_REQUEST: + case TOX_NETPROF_PACKET_ID_COOKIE_RESPONSE: + case TOX_NETPROF_PACKET_ID_CRYPTO_HS: + case TOX_NETPROF_PACKET_ID_CRYPTO_DATA: + case TOX_NETPROF_PACKET_ID_CRYPTO: + case TOX_NETPROF_PACKET_ID_LAN_DISCOVERY: + case TOX_NETPROF_PACKET_ID_ONION_SEND_INITIAL: + case TOX_NETPROF_PACKET_ID_ONION_SEND_1: + case TOX_NETPROF_PACKET_ID_ONION_SEND_2: + case TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST: + case TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE: + case TOX_NETPROF_PACKET_ID_ONION_DATA_REQUEST: + case TOX_NETPROF_PACKET_ID_ONION_DATA_RESPONSE: + case TOX_NETPROF_PACKET_ID_ONION_RECV_3: + case TOX_NETPROF_PACKET_ID_ONION_RECV_2: + case TOX_NETPROF_PACKET_ID_ONION_RECV_1: + case TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO: { + if (UDP_id_recv || UDP_id_sent) { + fprintf(fp, "0x%02x (total): %lu (%.2f%%)\n", id, UDP_id_sent + UDP_id_recv, + ((float)UDP_id_recv + UDP_id_sent) / total * 100.0); + } + + if (UDP_id_sent) { + fprintf(fp, "0x%02x (sent): %lu (%.2f%%)\n", id, UDP_id_sent, (float)UDP_id_sent / total * 100.0); + } + + if (UDP_id_recv) { + fprintf(fp, "0x%02x (recv): %lu (%.2f%%)\n", id, UDP_id_recv, (float)UDP_id_recv / total * 100.0); + } + + break; + } + + default: + return; + } +} + +static void dump_packet_id_counts(const Tox *m, FILE *fp, uint64_t total_count, Tox_Netprof_Packet_Type packet_type) +{ + if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) { + fprintf(fp, "--- TCP packet counts by packet ID --- \n"); + } else { + fprintf(fp, "--- UDP packet counts by packet ID --- \n"); + } + + for (unsigned long i = TOX_NETPROF_PACKET_ID_ZERO; i <= TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO; ++i) { + const uint64_t id_count_sent = tox_netprof_get_packet_id_count(m, packet_type, i, TOX_NETPROF_DIRECTION_SENT); + const uint64_t id_count_recv = tox_netprof_get_packet_id_count(m, packet_type, i, TOX_NETPROF_DIRECTION_RECV); + + if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) { + log_tcp_packet_id(fp, i, total_count, id_count_sent, id_count_recv); + } else { + log_udp_packet_id(fp, i, total_count, id_count_sent, id_count_recv); + } + } + + fprintf(fp, "\n\n"); +} + +static void dump_packet_id_bytes(const Tox *m, FILE *fp, uint64_t total_bytes, Tox_Netprof_Packet_Type packet_type) +{ + if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) { + fprintf(fp, "--- TCP byte counts by packet ID --- \n"); + } else { + fprintf(fp, "--- UDP byte counts by packet ID --- \n"); + } + + for (unsigned long i = TOX_NETPROF_PACKET_ID_ZERO; i <= TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO; ++i) { + const uint64_t id_bytes_sent = tox_netprof_get_packet_id_bytes(m, packet_type, i, TOX_NETPROF_DIRECTION_SENT); + const uint64_t id_bytes_recv = tox_netprof_get_packet_id_bytes(m, packet_type, i, TOX_NETPROF_DIRECTION_RECV); + + if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) { + log_tcp_packet_id(fp, i, total_bytes, id_bytes_sent, id_bytes_recv); + } else { + log_udp_packet_id(fp, i, total_bytes, id_bytes_sent, id_bytes_recv); + } + } + + fprintf(fp, "\n\n"); +} + +static void dump_packet_count_totals(const Tox *m, FILE *fp, uint64_t total_packet_count, + uint64_t UDP_count_sent, uint64_t UDP_count_recv, + uint64_t TCP_count_sent, uint64_t TCP_count_recv) +{ + const uint64_t total_UDP_count = UDP_count_sent + UDP_count_recv; + const uint64_t total_TCP_count = TCP_count_sent + TCP_count_recv; + const uint64_t total_packet_count_sent = UDP_count_sent + TCP_count_sent; + const uint64_t total_packet_count_recv = UDP_count_recv + TCP_count_recv; + + fprintf(fp, "--- Total packet counts --- \n"); + + fprintf(fp, "Total packets: %lu\n", total_packet_count); + + fprintf(fp, "Total packets sent: %lu (%.2f%%)\n", total_packet_count_sent, + (float)total_packet_count_sent / total_packet_count * 100.0); + + fprintf(fp, "Total packets recv: %lu (%.2f%%)\n", total_packet_count_recv, + (float)total_packet_count_recv / total_packet_count * 100.0); + + fprintf(fp, "total UDP packets: %lu (%.2f%%)\n", total_UDP_count, + (float)total_UDP_count / total_packet_count * 100.0); + + fprintf(fp, "UDP packets sent: %lu (%.2f%%)\n", UDP_count_sent, + (float)UDP_count_sent / total_packet_count * 100.0); + + fprintf(fp, "UDP packets recv: %lu (%.2f%%)\n", UDP_count_recv, + (float)UDP_count_recv / total_packet_count * 100.0); + + fprintf(fp, "Total TCP packets: %lu (%.2f%%)\n", total_TCP_count, + (float)total_TCP_count / total_packet_count * 100.0); + + fprintf(fp, "TCP packets sent: %lu (%.2f%%)\n", TCP_count_sent, + (float)TCP_count_sent / total_packet_count * 100.0); + + fprintf(fp, "TCP packets recv: %lu (%.2f%%)\n", TCP_count_recv, + (float)TCP_count_recv / total_packet_count * 100.0); + + fprintf(fp, "\n\n"); +} + +void dump_packet_bytes_totals(const Tox *m, FILE *fp, const uint64_t total_bytes, + const uint64_t UDP_bytes_sent, const uint64_t UDP_bytes_recv, + const uint64_t TCP_bytes_sent, const uint64_t TCP_bytes_recv) +{ + const uint64_t total_UDP_bytes = UDP_bytes_sent + UDP_bytes_recv; + const uint64_t total_TCP_bytes = TCP_bytes_sent + TCP_bytes_recv; + const uint64_t total_bytes_sent = UDP_bytes_sent + TCP_bytes_sent; + const uint64_t total_bytes_recv = UDP_bytes_recv + TCP_bytes_recv; + + fprintf(fp, "--- Total byte counts --- \n"); + + fprintf(fp, "Total bytes: %lu\n", total_bytes); + + fprintf(fp, "Total bytes sent: %lu (%.2f%%)\n", total_bytes_sent, + (float)total_bytes_sent / total_bytes * 100.0); + + fprintf(fp, "Total bytes recv: %lu (%.2f%%)\n", total_bytes_recv, + (float)total_bytes_recv / total_bytes * 100.0); + + fprintf(fp, "Total UDP bytes: %lu (%.2f%%)\n", total_UDP_bytes, + (float)total_UDP_bytes / total_bytes * 100.0); + + fprintf(fp, "UDP bytes sent: %lu (%.2f%%)\n", UDP_bytes_sent, + (float)UDP_bytes_sent / total_bytes * 100.0); + + fprintf(fp, "UDP bytes recv: %lu (%.2f%%)\n", UDP_bytes_recv, + (float)UDP_bytes_recv / total_bytes * 100.0); + + fprintf(fp, "Total TCP bytes: %lu (%.2f%%)\n", total_TCP_bytes, + (float)total_TCP_bytes / total_bytes * 100.0); + + fprintf(fp, "TCP bytes sent: %lu (%.2f%%)\n", TCP_bytes_sent, + (float)TCP_bytes_sent / total_bytes * 100.0); + + fprintf(fp, "TCP bytes recv: %lu (%.2f%%)\n", TCP_bytes_recv, + (float)TCP_bytes_recv / total_bytes * 100.0); + + fprintf(fp, "\n\n"); +} + +void netprof_log_dump(const Tox *m, FILE *fp) +{ + if (fp == NULL) { + fprintf(stderr, "Failed to dump network statistics: null file pointer\n"); + return; + } + + const uint64_t UDP_count_sent = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t UDP_count_recv = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_RECV); + const uint64_t TCP_count_sent = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t TCP_count_recv = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_RECV); + const uint64_t UDP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t UDP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP, + TOX_NETPROF_DIRECTION_RECV); + const uint64_t TCP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_SENT); + const uint64_t TCP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP, + TOX_NETPROF_DIRECTION_RECV); + + const uint64_t total_count = UDP_count_sent + UDP_count_recv + TCP_count_sent + TCP_count_recv; + const uint64_t total_bytes = UDP_bytes_sent + UDP_bytes_recv + TCP_bytes_sent + TCP_bytes_recv; + + dump_packet_count_totals(m, fp, total_count, UDP_count_sent, UDP_count_recv, TCP_count_sent, TCP_count_recv); + dump_packet_bytes_totals(m, fp, total_bytes, UDP_bytes_sent, UDP_bytes_recv, TCP_bytes_sent, TCP_bytes_recv); + dump_packet_id_counts(m, fp, total_count, TOX_NETPROF_PACKET_TYPE_TCP); + dump_packet_id_counts(m, fp, total_count, TOX_NETPROF_PACKET_TYPE_UDP); + dump_packet_id_bytes(m, fp, total_bytes, TOX_NETPROF_PACKET_TYPE_TCP); + dump_packet_id_bytes(m, fp, total_bytes, TOX_NETPROF_PACKET_TYPE_UDP); + + fflush(fp); +} + + diff --git a/src/netprof.h b/src/netprof.h new file mode 100644 index 0000000..88de7eb --- /dev/null +++ b/src/netprof.h @@ -0,0 +1,30 @@ +/* netprof.h + * + * + * Copyright (C) 2022 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#ifndef TOXIC_NETPROF +#define TOXIC_NETPROF + +#include + +void netprof_log_dump(const Tox *m, FILE *fp); + +#endif // TOXIC_NETPROF diff --git a/src/toxic.c b/src/toxic.c index 33e4f46..5965106 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -58,6 +58,7 @@ #include "message_queue.h" #include "misc_tools.h" #include "name_lookup.h" +#include "netprof.h" #include "notify.h" #include "prompt.h" #include "settings.h" @@ -143,6 +144,22 @@ static void catch_SIGSEGV(int sig) exit(EXIT_FAILURE); } +void cb_toxcore_logger(Tox *m, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, + const char *message, void *user_data) +{ + UNUSED_VAR(user_data); + UNUSED_VAR(file); + UNUSED_VAR(m); + + if (user_data) { + FILE *fp = (FILE *)user_data; + fprintf(fp, "[%d] %u:%s() - %s\n", level, line, func, message); + fflush(fp); + } else { + fprintf(stderr, "[%d] %u:%s() - %s\n", level, line, func, message); + } +} + static void flag_window_resize(int sig) { UNUSED_VAR(sig); @@ -177,6 +194,10 @@ void free_global_data(void) void exit_toxic_success(Tox *m) { + if (arg_opts.netprof_log_dump) { + netprof_log_dump(m, arg_opts.netprof_fp); + } + store_data(m, DATA_FILE); user_password = (struct user_password) { @@ -207,6 +228,11 @@ void exit_toxic_success(Tox *m) arg_opts.log_fp = NULL; } + if (arg_opts.netprof_fp != NULL) { + fclose(arg_opts.netprof_fp); + arg_opts.netprof_fp = NULL; + } + endwin(); curl_global_cleanup(); @@ -229,22 +255,6 @@ void exit_toxic_err(const char *errmsg, int errcode) exit(EXIT_FAILURE); } -void cb_toxcore_logger(Tox *m, Tox_Log_Level level, const char *file, uint32_t line, const char *func, - const char *message, void *user_data) -{ - UNUSED_VAR(user_data); - UNUSED_VAR(file); - UNUSED_VAR(m); - - if (user_data) { - FILE *fp = (FILE *)user_data; - fprintf(fp, "[%d] %u:%s() - %s\n", level, line, func, message); - fflush(fp); - } else { - fprintf(stderr, "[%d] %u:%s() - %s\n", level, line, func, message); - } -} - /* Sets ncurses refresh rate. Lower values make it refresh more often. */ void set_window_refresh_rate(size_t refresh_rate) { @@ -1199,6 +1209,7 @@ static void print_usage(void) fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n"); fprintf(stderr, " -P, --HTTP-proxy Use HTTP proxy: Requires [IP] [port]\n"); fprintf(stderr, " -r, --namelist Use specified name lookup server list\n"); + fprintf(stderr, " -s, --netstats Dump network statistic to log on exit: Requires [path]\n"); fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n"); fprintf(stderr, " -T, --tcp-server Act as a TCP relay server: Requires [port]\n"); fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n"); @@ -1238,6 +1249,7 @@ static void parse_args(int argc, char *argv[]) {"help", no_argument, 0, 'h'}, {"noconnect", no_argument, 0, 'o'}, {"namelist", required_argument, 0, 'r'}, + {"netstats", required_argument, 0, 's'}, {"force-tcp", no_argument, 0, 't'}, {"tcp-server", required_argument, 0, 'T'}, {"SOCKS5-proxy", required_argument, 0, 'p'}, @@ -1247,7 +1259,7 @@ static void parse_args(int argc, char *argv[]) {NULL, no_argument, NULL, 0}, }; - const char *opts_str = "4bdehLotuxvc:f:l:n:r:p:P:T:"; + const char *opts_str = "4bdehLotuxvc:f:l:n:r:s:p:P:T:"; int opt = 0; int indexptr = 0; diff --git a/src/windows.h b/src/windows.h index c103016..e8f0a0e 100644 --- a/src/windows.h +++ b/src/windows.h @@ -142,6 +142,9 @@ struct arg_opts { bool logging; FILE *log_fp; + bool netprof_log_dump; + FILE *netprof_fp; + char proxy_address[256]; uint8_t proxy_type; uint16_t proxy_port;