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;