From 5375587282ff43a6e80285355ec7bc6a18320d0a Mon Sep 17 00:00:00 2001 From: Andreas Gocht-Zech Date: Sun, 17 Sep 2023 22:35:57 +0200 Subject: [PATCH 1/3] move C-style-list to std::list --- src/libnethogs.cpp | 18 ++++++------------ src/main.cpp | 8 ++++---- src/nethogs.cpp | 5 +---- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/libnethogs.cpp b/src/libnethogs.cpp index 1aad548..689bfc6 100644 --- a/src/libnethogs.cpp +++ b/src/libnethogs.cpp @@ -10,6 +10,7 @@ extern "C" { #include #include #include +#include ////////////////////////////// extern ProcList *processes; @@ -33,7 +34,7 @@ static fd_set pc_loop_fd_set; static std::vector pc_loop_fd_list; static bool pc_loop_use_select = true; -static handle *handles = NULL; +static std::list handles; static std::pair create_self_pipe() { int pfd[2]; @@ -117,7 +118,7 @@ static int nethogsmonitor_init(int devc, char **devicenames, bool all, if (dp_setnonblock(newhandle, 1, errbuf) == -1) { fprintf(stderr, "Error putting libpcap in nonblocking mode\n"); } - handles = new handle(newhandle, current_dev->name, handles); + handles.push_front(handle(newhandle, current_dev->name)); if (pc_loop_use_select) { // some devices may not support pcap_get_selectable_fd @@ -264,15 +265,10 @@ static void nethogsmonitor_handle_update(NethogsMonitorCallback cb) { static void nethogsmonitor_clean_up() { // clean up - handle *current_handle = handles; - handle *rem; - while (current_handle != NULL) { + for(auto current_handle = handles.begin(); current_handle != handles.end(); current_handle++){ pcap_close(current_handle->content->pcap_handle); - rem = current_handle; - current_handle = current_handle->next; - free(rem); } - handles = NULL; + handles.clear(); // close file descriptors for (std::vector::const_iterator it = pc_loop_fd_list.begin(); @@ -307,8 +303,7 @@ int nethogsmonitor_loop_devices(NethogsMonitorCallback cb, char *filter, while (monitor_run_flag) { bool packets_read = false; - handle *current_handle = handles; - while (current_handle != NULL) { + for(auto current_handle = handles.begin(); current_handle != handles.end(); current_handle++) { userdata->device = current_handle->devicename; userdata->sa_family = AF_UNSPEC; int retval = dp_dispatch(current_handle->content, -1, (u_char *)userdata, @@ -320,7 +315,6 @@ int nethogsmonitor_loop_devices(NethogsMonitorCallback cb, char *filter, } else { gettimeofday(&curtime, NULL); } - current_handle = current_handle->next; } time_t const now = ::time(NULL); diff --git a/src/main.cpp b/src/main.cpp index b5dfdec..de95c5f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef __linux__ #include @@ -236,7 +237,7 @@ int main(int argc, char **argv) { int nb_devices = 0; int nb_failed_devices = 0; - handle *handles = NULL; + std::list handles; device *current_dev = devices; while (current_dev != NULL) { ++nb_devices; @@ -262,7 +263,7 @@ int main(int argc, char **argv) { if (dp_setnonblock(newhandle, 1, errbuf) == -1) { fprintf(stderr, "Error putting libpcap in nonblocking mode\n"); } - handles = new handle(newhandle, current_dev->name, handles); + handles.push_front(handle(newhandle, current_dev->name)); if (pc_loop_use_select) { // some devices may not support pcap_get_selectable_fd @@ -308,8 +309,7 @@ int main(int argc, char **argv) { while (1) { bool packets_read = false; - for (handle *current_handle = handles; current_handle != NULL; - current_handle = current_handle->next) { + for (auto current_handle = handles.begin(); current_handle != handles.end(); current_handle ++) { userdata->device = current_handle->devicename; userdata->sa_family = AF_UNSPEC; int retval = dp_dispatch(current_handle->content, -1, (u_char *)userdata, diff --git a/src/nethogs.cpp b/src/nethogs.cpp index a1c446c..6e5d487 100644 --- a/src/nethogs.cpp +++ b/src/nethogs.cpp @@ -237,13 +237,10 @@ int process_ip6(u_char *userdata, const dp_header * /* header */, class handle { public: - handle(dp_handle *m_handle, const char *m_devicename = NULL, - handle *m_next = NULL) { + handle(dp_handle *m_handle, const char *m_devicename = NULL) { content = m_handle; - next = m_next; devicename = m_devicename; } dp_handle *content; const char *devicename; - handle *next; }; From b9abb65df0c1557613bb3055f47db0e0cf6af124 Mon Sep 17 00:00:00 2001 From: Andreas Gocht-Zech Date: Sun, 17 Sep 2023 22:39:11 +0200 Subject: [PATCH 2/3] add pcap packet stats --- python/bindings.cpp | 25 +++++++++++++++++++++++++ src/decpcap.c | 17 +++++++++++++++++ src/decpcap.h | 5 +++++ src/libnethogs.cpp | 17 +++++++++++++++++ src/libnethogs.h | 17 +++++++++++++++++ 5 files changed, 81 insertions(+) diff --git a/python/bindings.cpp b/python/bindings.cpp index dddda45..b4cd07c 100644 --- a/python/bindings.cpp +++ b/python/bindings.cpp @@ -66,6 +66,21 @@ int nethogsmonitor_loop_devices_py( return retval; } +std::vector nethogs_packet_stats_py() +{ + NethogsPackageStats* stats; + int stat_count; + + nethogs_packet_stats(&stats, &stat_count); + + std::vector stats_vector(stat_count); + std::copy_n(stats,stat_count, stats_vector.begin()); + + free(stats); + + return stats_vector; +} + //--- python module binding PYBIND11_MODULE(nethogs, m) { py::class_(m, "NethogsMonitorRecord") @@ -81,6 +96,12 @@ PYBIND11_MODULE(nethogs, m) { .def_readwrite("sent_kbs", &NethogsMonitorRecord::sent_kbs) .def_readwrite("recv_kbs", &NethogsMonitorRecord::recv_kbs); + py::class_(m, "NethogsPackageStats") + .def_readonly("ps_recv", &NethogsPackageStats::ps_recv) + .def_readonly("ps_drop", &NethogsPackageStats::ps_drop) + .def_readonly("ps_ifdrop", &NethogsPackageStats::ps_ifdrop) + .def_readonly("devicename", &NethogsPackageStats::devicename); + m.def("nethogsmonitor_loop", &nethogsmonitor_loop_py, R"pbdoc( Nethogs monitor loop )pbdoc"); @@ -90,6 +111,10 @@ PYBIND11_MODULE(nethogs, m) { m.def("nethogsmonitor_breakloop", &nethogsmonitor_breakloop, R"pbdoc( Nethogs monitor loop break )pbdoc"); + m.def("nethogs_packet_stats", &nethogs_packet_stats_py, R"pbdoc( + Nethogs pcap packet stats + )pbdoc"); + #ifdef VERSION m.attr("__version__") = VERSION; diff --git a/src/decpcap.c b/src/decpcap.c index edaf743..37e2fcf 100644 --- a/src/decpcap.c +++ b/src/decpcap.c @@ -110,6 +110,23 @@ struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc, return dp_fillhandle(temp); } +/* function to get packet statistics, e.g. dropped packets */ + +dp_stat dp_stats(struct dp_handle* handle) +{ + struct pcap_stat ps; + if(pcap_stats(handle->pcap_handle, &ps) == PCAP_ERROR) + { + fprintf(stderr, "Error getting pcap_stats: %s\n", + pcap_geterr(handle->pcap_handle)); + ps.ps_recv = 0; + ps.ps_drop = 0; + ps.ps_ifdrop = 0; + return ps; + } + return ps; +} + /* functions to add callbacks */ void dp_addcb(struct dp_handle *handle, enum dp_packet_type type, diff --git a/src/decpcap.h b/src/decpcap.h index 5ecba60..6d2c86f 100644 --- a/src/decpcap.h +++ b/src/decpcap.h @@ -52,6 +52,7 @@ enum dp_packet_type { * pcap };*/ typedef struct pcap_pkthdr dp_header; +typedef struct pcap_stat dp_stat; typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *); @@ -69,6 +70,10 @@ struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc, int to_ms, char *filter, char *errbuf); struct dp_handle *dp_open_offline(char *fname, char *ebuf); +/* function to get packet statistics, e.g. dropped packets */ + +dp_stat dp_stats(struct dp_handle* handle); + /* functions to add callbacks */ void dp_addcb(struct dp_handle *handle, enum dp_packet_type type, diff --git a/src/libnethogs.cpp b/src/libnethogs.cpp index 689bfc6..81c02b6 100644 --- a/src/libnethogs.cpp +++ b/src/libnethogs.cpp @@ -339,3 +339,20 @@ void nethogsmonitor_breakloop() { monitor_run_flag = false; write(self_pipe.second, "x", 1); } + +void nethogs_packet_stats(NethogsPackageStats **stats, int *stats_size) +{ + + *stats = static_cast(malloc(handles.size() * sizeof(NethogsPackageStats))); + int i = 0; + + for(auto current_handle = handles.begin(); current_handle != handles.end(); current_handle ++){ + dp_stat stat = dp_stats(current_handle->content); + stats[i]->ps_recv = stat.ps_recv; + stats[i]->ps_drop = stat.ps_drop; + stats[i]->ps_ifdrop = stat.ps_ifdrop; + stats[i]->devicename = current_handle->devicename; + i++; + } + *stats_size = handles.size(); +} \ No newline at end of file diff --git a/src/libnethogs.h b/src/libnethogs.h index 2974662..26849f9 100644 --- a/src/libnethogs.h +++ b/src/libnethogs.h @@ -7,6 +7,7 @@ extern "C" { #include #include +#include #define NETHOGS_DSO_VISIBLE __attribute__((visibility("default"))) #define NETHOGS_DSO_HIDDEN __attribute__((visibility("hidden"))) @@ -32,6 +33,14 @@ typedef struct NethogsMonitorRecord { float recv_kbs; } NethogsMonitorRecord; +typedef struct NethogsPackageStats +{ + u_int ps_recv; /** number of packets received */ + u_int ps_drop; /** number of packets dropped because there was no room in the operating system's buffer when they arrived, because packets weren't being read fast enough */ + u_int ps_ifdrop; /** number of packets dropped by the network interface or its driver. */ + const char *devicename; /** name of the network interface */ +} NethogsPackageStats; + /** * @brief Defines a callback to handle updates about applications * @param action NETHOGS_APP_ACTION_SET if data is being added or updated, @@ -95,6 +104,14 @@ NETHOGS_DSO_VISIBLE int nethogsmonitor_loop_devices(NethogsMonitorCallback cb, */ NETHOGS_DSO_VISIBLE void nethogsmonitor_breakloop(); +/** + * @brief returns the pcap packet stats per device + * + * @param stats C-Style array the will hold the stats + * @param stats_size elements and therefore devices in stats + */ +NETHOGS_DSO_VISIBLE void nethogs_packet_stats(NethogsPackageStats **stats, int *stats_size); + #undef NETHOGS_DSO_VISIBLE #undef NETHOGS_DSO_HIDDEN From 08524d2740d88288b9b73c5c462d661ef726e169 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Mon, 28 Aug 2023 13:00:10 +0200 Subject: [PATCH 3/3] Clarify units On the internet the usage of b and B for bits or bytes is inconsistent. Lowercase b seems to be used for either, and upperace B is more often used to mean bytes but usege for bits also exists. I am not aware of any standard that would mandate one or other use. Consequently, spelling out the whole word in the output or adding explanation in documentation is the only way to make sure the output is interpreted correctly. To save space on small screens only alter documentation and the bytes label without prefixes/suffixes. While at it change uppercase K to lowercase k to correctly spell the kilo- prefix. Fixes: #261 Signed-off-by: Michal Suchanek --- doc/nethogs.8 | 4 +++- src/cui.cpp | 2 +- src/main.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/nethogs.8 b/doc/nethogs.8 index 3c827a7..e291684 100644 --- a/doc/nethogs.8 +++ b/doc/nethogs.8 @@ -41,7 +41,9 @@ bughunt mode - implies tracemode. delay for update refresh rate in seconds. default is 1. .TP \fB-v\fP -view mode (0 = KB/s, 1 = total KB, 2 = total B, 3 = total MB, 4 = MB/s, 5 = GB/s). default is 0. +view mode (0 = kB/s, 1 = total kB, 2 = total bytes, 3 = total MB, 4 = MB/s, 5 = GB/s). default is 0. + +kB: 2e10 bytes, MB: 2e20 bytes, GB: 2e30 bytes .TP \fB-c\fP number of updates. default is 0 (unlimited). diff --git a/src/cui.cpp b/src/cui.cpp index 40a7455..137bce6 100644 --- a/src/cui.cpp +++ b/src/cui.cpp @@ -68,7 +68,7 @@ const char *COLUMN_FORMAT_RECEIVED = "%11.3f"; // All descriptions are padded to 6 characters in length with spaces const char *const desc_view_mode[VIEWMODE_COUNT] = { - "KB/s ", "KB ", "B ", "MB ", "MB/s ", "GB/s "}; + "kB/s ", "kB ", "bytes ", "MB ", "MB/s ", "GB/s "}; constexpr char FILE_SEPARATOR = '/'; diff --git a/src/main.cpp b/src/main.cpp index de95c5f..7501461 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,8 +38,8 @@ static void help(bool iserror) { output << " -x : bughunt mode - implies tracemode.\n"; output << " -d : delay for update refresh rate in seconds. default " "is 1.\n"; - output << " -v : view mode (0 = KB/s, 1 = total KB, 2 = total B, 3 " - "= total MB, 4 = MB/s, 5 = GB/s). default is 0.\n"; + output << " -v : view mode (0 = kB/s, 1 = total kB, 2 = " + "total bytes, 3 = total MB, 4 = MB/s, 5 = GB/s). default is 0.\n"; output << " -c : number of updates. default is 0 (unlimited).\n"; output << " -t : tracemode.\n"; // output << " -f : format of packets on interface, default is @@ -67,8 +67,8 @@ static void help(bool iserror) { output << " r: sort by RECEIVED traffic\n"; output << " l: display command line\n"; output << " b: display the program basename instead of the fullpath\n"; - output << " m: switch between total (KB, B, MB) and throughput (KB/s, MB/s, " - "GB/s) mode\n"; + output << " m: switch between total (kB, bytes, MB) and throughput (kB/s, " + " MB/s, GB/s) mode\n"; } void quit_cb(int /* i */) {