adding network !!
- rx/tx graph - label rx/tx/error - rewriting some codes - adding packetin/packetout for each pid - adding pcap sniffing port -> count - adding inode mapping to get port <- inode <- pid # Conflicts: # src/main.c # src/process-monitor.c # src/process-monitor.h # src/process-statusbar.c # src/process-window.c # src/process-window.h # src/settings.h # src/task-manager-linux.c # src/task-manager.c # src/task-manager.h starting freebsd get mac address trough getifaddrs function, should be more portable remove mac_get_binary_from_file that use /sys/class/net/%s/address freebsd adding packetin/packetout/active socket trough sockstat - move linux code - adding pseudo inode mapping OpenBSD suppoort & code cleanup NetBSD global network usage & per process hiding of settings and columns on network initialization failure Apply .clang-format file # Conflicts: # src/main.c # src/process-monitor.c # src/process-monitor.h # src/process-statusbar.c # src/process-window.c # src/process-window.h # src/settings-dialog.c # src/settings.h # src/task-manager-bsd.c # src/task-manager.c # src/task-manager.h use AC_CHECK_LIB and add the corresponding ifdef to disable pcap functionality fix compilation openbsd clang format fix compilation netbsd clang format ... disable clang-format on task-manager-bsd, important include order fix compilation freebsd disable clang-format on task-manager-freebsd, important include order typo openbsd include fix segfault on openbsd without permissions fix warning on freebsd : -Wint-to-pointer-cast -Wmissing-declarations -Wshadow fix compilation for "skel" and "solaris" (implementation todo) freebsd iterate over all network interface linux iterate over all network interface and fix some warnings netbsd iterator over all network interface and fix args issue trough kvm_getargv2 fix ptr issue, clang format ide change coding style ? fix close button, hide when "Keep in the notification area" is enable Discard my changes on the README Solaris adding mac adresse, rx/tx/error for the network graph libsocket is in the default package of solaris, it should be linked for getifaddrs adding packet callback for solaris solaris pid to socket mapping (tcp, tcp6, udp, udp6) ! final clang format credit ? Linux adding udp, udp6, icmp, icmp6, raw, raw6. Disable virtual network device on linux. Fix -Wincompatible-pointer-types and -Wdeprecated-declarations use WNCK_CHECK_VERSION and WnckHandle on version >= 43.0.0 asked changes
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
dnl
|
dnl
|
||||||
dnl xfce4-taskmanager - A small taskmanager based on the Xfce 4 libraries.
|
dnl xfce4-taskmanager - A small taskmanager based on the Xfce 4 libraries.
|
||||||
dnl
|
dnl
|
||||||
|
dnl 2024-2024 Jehan-Antoine Vayssade
|
||||||
dnl 2014-2021 Simon Steinbess
|
dnl 2014-2021 Simon Steinbess
|
||||||
dnl 2018-2019 Rozhuk Ivan
|
dnl 2018-2019 Rozhuk Ivan
|
||||||
dnl 2014 Landry Breuil
|
dnl 2014 Landry Breuil
|
||||||
@@ -81,6 +82,9 @@ dnl ***********************************
|
|||||||
XDT_CHECK_OPTIONAL_PACKAGE([LIBX11], [x11], [1.6.7], [libx11], [Libx11 support])
|
XDT_CHECK_OPTIONAL_PACKAGE([LIBX11], [x11], [1.6.7], [libx11], [Libx11 support])
|
||||||
XDT_CHECK_OPTIONAL_PACKAGE([WNCK], [libwnck-3.0], [3.2], [wnck3], [building with libwnck3 for window icons/names], [yes])
|
XDT_CHECK_OPTIONAL_PACKAGE([WNCK], [libwnck-3.0], [3.2], [wnck3], [building with libwnck3 for window icons/names], [yes])
|
||||||
|
|
||||||
|
AC_CHECK_LIB(pcap, [pcap_open_live])
|
||||||
|
AC_CHECK_HEADERS([pcap.h])
|
||||||
|
|
||||||
dnl ***********************************
|
dnl ***********************************
|
||||||
dnl ********** Check for skel *********
|
dnl ********** Check for skel *********
|
||||||
dnl ***********************************
|
dnl ***********************************
|
||||||
@@ -104,12 +108,14 @@ else
|
|||||||
;;
|
;;
|
||||||
dragonfly*|netbsd*|openbsd*|darwin*)
|
dragonfly*|netbsd*|openbsd*|darwin*)
|
||||||
ac_os_implementation="bsd"
|
ac_os_implementation="bsd"
|
||||||
|
AC_CHECK_LIB([kvm], [kvm_openfiles])
|
||||||
AC_CHECK_HEADERS([err.h pwd.h stdlib.h string.h sys/param.h sys/sched.h \
|
AC_CHECK_HEADERS([err.h pwd.h stdlib.h string.h sys/param.h sys/sched.h \
|
||||||
sys/swap.h sys/sysctl.h sys/types.h unistd.h])
|
sys/swap.h sys/sysctl.h sys/types.h unistd.h])
|
||||||
;;
|
;;
|
||||||
solaris*)
|
solaris*)
|
||||||
ac_os_implementation="solaris"
|
ac_os_implementation="solaris"
|
||||||
AC_CHECK_LIB([kstat], [kstat_open])
|
AC_CHECK_LIB([kstat], [kstat_open])
|
||||||
|
AC_CHECK_LIB([socket], [freeifaddrs])
|
||||||
AC_CHECK_HEADERS([fcntl.h kstat.h procfs.h pwd.h stdlib.h string.h \
|
AC_CHECK_HEADERS([fcntl.h kstat.h procfs.h pwd.h stdlib.h string.h \
|
||||||
sys/procfs.h sys/stat.h sys/swap.h sys/types.h])
|
sys/procfs.h sys/stat.h sys/swap.h sys/types.h])
|
||||||
;;
|
;;
|
||||||
|
|||||||
BIN
screenshot.png
Normal file
BIN
screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@@ -8,6 +8,7 @@ bin_PROGRAMS = \
|
|||||||
|
|
||||||
xfce4_taskmanager_CFLAGS = \
|
xfce4_taskmanager_CFLAGS = \
|
||||||
$(CAIRO_CFLAGS) \
|
$(CAIRO_CFLAGS) \
|
||||||
|
$(LIBPCAP_CFLAGS) \
|
||||||
$(LIBX11_CFLAGS) \
|
$(LIBX11_CFLAGS) \
|
||||||
$(LIBXMU_CFLAGS) \
|
$(LIBXMU_CFLAGS) \
|
||||||
$(GTK3_CFLAGS) \
|
$(GTK3_CFLAGS) \
|
||||||
@@ -18,6 +19,7 @@ xfce4_taskmanager_CFLAGS = \
|
|||||||
|
|
||||||
xfce4_taskmanager_LDADD = \
|
xfce4_taskmanager_LDADD = \
|
||||||
$(CAIRO_LIBS) \
|
$(CAIRO_LIBS) \
|
||||||
|
$(LIBPCAP_LIBS) \
|
||||||
$(LIBX11_LIBS) \
|
$(LIBX11_LIBS) \
|
||||||
$(LIBXMU_LIBS) \
|
$(LIBXMU_LIBS) \
|
||||||
$(GTK3_LIBS) \
|
$(GTK3_LIBS) \
|
||||||
@@ -30,6 +32,8 @@ xfce4_taskmanager_SOURCES = \
|
|||||||
main.c \
|
main.c \
|
||||||
process-window_ui.h \
|
process-window_ui.h \
|
||||||
process-window.c process-window.h \
|
process-window.c process-window.h \
|
||||||
|
inode-to-sock.c inode-to-sock.h \
|
||||||
|
network-analyzer.c network-analyzer.h \
|
||||||
process-monitor.c process-monitor.h \
|
process-monitor.c process-monitor.h \
|
||||||
process-tree-model.c process-tree-model.h \
|
process-tree-model.c process-tree-model.h \
|
||||||
process-tree-view.c process-tree-view.h \
|
process-tree-view.c process-tree-view.h \
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ static App *apps_lookup_app (GArray *apps, WnckApplication *application);
|
|||||||
static void application_opened (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager);
|
static void application_opened (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager);
|
||||||
static void application_closed (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager);
|
static void application_closed (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager);
|
||||||
static void scale_factor_changed (GdkMonitor *monitor);
|
static void scale_factor_changed (GdkMonitor *monitor);
|
||||||
|
// static WnckHandle *handle = NULL;
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -59,10 +59,18 @@ static void
|
|||||||
xtm_app_manager_init (XtmAppManager *manager)
|
xtm_app_manager_init (XtmAppManager *manager)
|
||||||
{
|
{
|
||||||
WnckApplication *application;
|
WnckApplication *application;
|
||||||
WnckScreen *screen = wnck_screen_get_default ();
|
WnckScreen *screen;
|
||||||
GdkMonitor *monitor = gdk_display_get_monitor (gdk_display_get_default (), 0);
|
GdkMonitor *monitor;
|
||||||
GList *windows, *l;
|
GList *windows, *l;
|
||||||
|
|
||||||
|
// #if WNCK_CHECK_VERSION(43, 0, 0)
|
||||||
|
// handle = wnck_handle_new (WNCK_CLIENT_TYPE_APPLICATION);
|
||||||
|
// screen = wnck_handle_get_default_screen (handle);
|
||||||
|
// #else
|
||||||
|
screen = wnck_screen_get_default ();
|
||||||
|
// #endif
|
||||||
|
monitor = gdk_display_get_monitor (gdk_display_get_default (), 0);
|
||||||
|
|
||||||
/* Retrieve initial applications */
|
/* Retrieve initial applications */
|
||||||
while (gtk_events_pending ())
|
while (gtk_events_pending ())
|
||||||
gtk_main_iteration ();
|
gtk_main_iteration ();
|
||||||
@@ -210,7 +218,11 @@ application_closed (WnckScreen *screen __unused, WnckApplication *application, X
|
|||||||
static void
|
static void
|
||||||
scale_factor_changed (GdkMonitor *monitor)
|
scale_factor_changed (GdkMonitor *monitor)
|
||||||
{
|
{
|
||||||
|
// #if WNCK_CHECK_VERSION(43, 0, 0)
|
||||||
|
// wnck_handle_set_default_mini_icon_size (handle, WNCK_DEFAULT_MINI_ICON_SIZE * gdk_monitor_get_scale_factor (monitor));
|
||||||
|
// #else
|
||||||
wnck_set_default_mini_icon_size (WNCK_DEFAULT_MINI_ICON_SIZE * gdk_monitor_get_scale_factor (monitor));
|
wnck_set_default_mini_icon_size (WNCK_DEFAULT_MINI_ICON_SIZE * gdk_monitor_get_scale_factor (monitor));
|
||||||
|
// #endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
45
src/inode-to-sock.c
Normal file
45
src/inode-to-sock.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
|
*
|
||||||
|
* This program 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 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "inode-to-sock.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
XtmInodeToSock *
|
||||||
|
xtm_create_inode_to_sock (void)
|
||||||
|
{
|
||||||
|
XtmInodeToSock *its = g_new (XtmInodeToSock, 1);
|
||||||
|
its->hash = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
|
||||||
|
// freebsd only
|
||||||
|
its->pid = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
|
||||||
|
return its;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_destroy_inode_to_sock (XtmInodeToSock *its)
|
||||||
|
{
|
||||||
|
if (its == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_hash_table_destroy (its->hash);
|
||||||
|
g_hash_table_destroy (its->pid);
|
||||||
|
|
||||||
|
free (its);
|
||||||
|
}
|
||||||
|
|
||||||
|
XtmInodeToSock *
|
||||||
|
xtm_inode_to_sock_get_default (void)
|
||||||
|
{
|
||||||
|
static XtmInodeToSock *its = NULL;
|
||||||
|
if (its == NULL)
|
||||||
|
its = xtm_create_inode_to_sock ();
|
||||||
|
return its;
|
||||||
|
}
|
||||||
29
src/inode-to-sock.h
Normal file
29
src/inode-to-sock.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
|
*
|
||||||
|
* This program 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 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INMODE_TO_SOCK_H
|
||||||
|
#define INMODE_TO_SOCK_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
typedef struct _XtmInodeToSock XtmInodeToSock;
|
||||||
|
struct _XtmInodeToSock
|
||||||
|
{
|
||||||
|
// inode to port
|
||||||
|
GHashTable *hash;
|
||||||
|
// inode to pid (freebsd)
|
||||||
|
GHashTable *pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
XtmInodeToSock *xtm_create_inode_to_sock (void);
|
||||||
|
void xtm_refresh_inode_to_sock (XtmInodeToSock *);
|
||||||
|
void xtm_destroy_inode_to_sock (XtmInodeToSock *);
|
||||||
|
XtmInodeToSock *xtm_inode_to_sock_get_default (void);
|
||||||
|
|
||||||
|
#endif
|
||||||
35
src/main.c
35
src/main.c
@@ -12,6 +12,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "process-window.h"
|
#include "process-window.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "task-manager.h"
|
#include "task-manager.h"
|
||||||
@@ -28,6 +29,7 @@ static XtmTaskManager *task_manager;
|
|||||||
static guint timer_id;
|
static guint timer_id;
|
||||||
static gboolean start_hidden = FALSE;
|
static gboolean start_hidden = FALSE;
|
||||||
static gboolean standalone = FALSE;
|
static gboolean standalone = FALSE;
|
||||||
|
static XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
|
||||||
static GOptionEntry main_entries[] = {
|
static GOptionEntry main_entries[] = {
|
||||||
{ "start-hidden", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &start_hidden, "Don't open a task manager window", NULL },
|
{ "start-hidden", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &start_hidden, "Don't open a task manager window", NULL },
|
||||||
@@ -121,15 +123,14 @@ destroy_window (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
delete_window (void)
|
delete_window (GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
||||||
{
|
{
|
||||||
if (!status_icon_get_visible ())
|
if (!status_icon_get_visible ())
|
||||||
{
|
{
|
||||||
if (timer_id > 0)
|
destroy_window ();
|
||||||
g_source_remove (timer_id);
|
|
||||||
gtk_main_quit ();
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_widget_hide (window);
|
gtk_widget_hide (window);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -140,8 +141,10 @@ collect_data (void)
|
|||||||
guint num_processes;
|
guint num_processes;
|
||||||
gfloat cpu, memory_percent, swap_percent;
|
gfloat cpu, memory_percent, swap_percent;
|
||||||
guint64 swap_used, swap_free, swap_total, memory_used, memory_total;
|
guint64 swap_used, swap_free, swap_total, memory_used, memory_total;
|
||||||
|
guint64 tcp_rx, tcp_tx, tcp_error;
|
||||||
gchar *used, *total, tooltip[1024], memory_info[64], swap_info[64];
|
gchar *used, *total, tooltip[1024], memory_info[64], swap_info[64];
|
||||||
|
|
||||||
|
xtm_task_manager_get_network_info (task_manager, &tcp_rx, &tcp_tx, &tcp_error);
|
||||||
xtm_task_manager_get_system_info (task_manager, &num_processes, &cpu, &memory_used, &memory_total, &swap_used, &swap_total);
|
xtm_task_manager_get_system_info (task_manager, &num_processes, &cpu, &memory_used, &memory_total, &swap_used, &swap_total);
|
||||||
|
|
||||||
memory_percent = (memory_total != 0) ? ((memory_used * 100.0f) / (float)memory_total) : 0.0f;
|
memory_percent = (memory_total != 0) ? ((memory_used * 100.0f) / (float)memory_total) : 0.0f;
|
||||||
@@ -159,19 +162,23 @@ collect_data (void)
|
|||||||
g_free (used);
|
g_free (used);
|
||||||
g_free (total);
|
g_free (total);
|
||||||
|
|
||||||
xtm_process_window_set_system_info (XTM_PROCESS_WINDOW (window), num_processes, cpu, memory_percent, memory_info, swap_percent, swap_info);
|
xtm_process_window_set_system_info (XTM_PROCESS_WINDOW (window), num_processes, cpu, memory_percent, memory_info, swap_percent, swap_info, tcp_rx, tcp_tx, tcp_error);
|
||||||
|
|
||||||
xtm_task_manager_get_swap_usage (task_manager, &swap_free, &swap_total);
|
xtm_task_manager_get_swap_usage (task_manager, &swap_free, &swap_total);
|
||||||
xtm_process_window_show_swap_usage (XTM_PROCESS_WINDOW (window), (swap_total > 0));
|
xtm_process_window_show_swap_usage (XTM_PROCESS_WINDOW (window), (swap_total > 0));
|
||||||
|
|
||||||
if (status_icon_get_visible ())
|
if (status_icon_get_visible ())
|
||||||
{
|
{
|
||||||
g_snprintf (tooltip, sizeof (tooltip),
|
g_snprintf (
|
||||||
|
tooltip, sizeof (tooltip),
|
||||||
_("<b>Processes:</b> %u\n"
|
_("<b>Processes:</b> %u\n"
|
||||||
"<b>CPU:</b> %.0f%%\n"
|
"<b>CPU:</b> %.0f%%\n"
|
||||||
"<b>Memory:</b> %s\n"
|
"<b>Memory:</b> %s\n"
|
||||||
"<b>Swap:</b> %s"),
|
"<b>Swap:</b> %s\n"
|
||||||
num_processes, cpu, memory_info, swap_info);
|
"<b>Network:</b> %.2f / %.2f MB/s"),
|
||||||
|
num_processes, cpu, memory_info, swap_info,
|
||||||
|
tcp_rx * 1e-5, tcp_tx * 1e-5);
|
||||||
|
|
||||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||||
gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (status_icon_or_null), tooltip);
|
gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (status_icon_or_null), tooltip);
|
||||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||||
@@ -253,8 +260,7 @@ main (int argc, char *argv[])
|
|||||||
if (!xfconf_init (&error))
|
if (!xfconf_init (&error))
|
||||||
{
|
{
|
||||||
xfce_message_dialog (NULL, _("Xfce Notify Daemon"),
|
xfce_message_dialog (NULL, _("Xfce Notify Daemon"),
|
||||||
"dialog-error",
|
"dialog-error", _("Settings daemon is unavailable"),
|
||||||
_("Settings daemon is unavailable"),
|
|
||||||
error->message,
|
error->message,
|
||||||
"application-exit", GTK_RESPONSE_ACCEPT,
|
"application-exit", GTK_RESPONSE_ACCEPT,
|
||||||
NULL);
|
NULL);
|
||||||
@@ -273,6 +279,8 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
g_signal_connect_swapped (app, "activate", G_CALLBACK (xtm_process_window_show), window);
|
g_signal_connect_swapped (app, "activate", G_CALLBACK (xtm_process_window_show), window);
|
||||||
|
|
||||||
|
//! create net
|
||||||
|
analyzer = xtm_network_analyzer_get_default ();
|
||||||
task_manager = xtm_task_manager_new (xtm_process_window_get_model (XTM_PROCESS_WINDOW (window)));
|
task_manager = xtm_task_manager_new (xtm_process_window_get_model (XTM_PROCESS_WINDOW (window)));
|
||||||
|
|
||||||
collect_data ();
|
collect_data ();
|
||||||
@@ -282,8 +290,11 @@ main (int argc, char *argv[])
|
|||||||
g_signal_connect_after (settings, "notify::full-command-line", G_CALLBACK (collect_data), NULL);
|
g_signal_connect_after (settings, "notify::full-command-line", G_CALLBACK (collect_data), NULL);
|
||||||
g_signal_connect (settings, "notify::show-status-icon", G_CALLBACK (show_hide_status_icon), NULL);
|
g_signal_connect (settings, "notify::show-status-icon", G_CALLBACK (show_hide_status_icon), NULL);
|
||||||
|
|
||||||
g_signal_connect (window, "destroy", G_CALLBACK (destroy_window), NULL);
|
g_signal_connect (xtm_process_window_get (XTM_PROCESS_WINDOW (window)), "destroy", G_CALLBACK (destroy_window), NULL);
|
||||||
|
g_signal_connect (xtm_process_window_get (XTM_PROCESS_WINDOW (window)), "delete-event", G_CALLBACK (delete_window), NULL);
|
||||||
g_signal_connect (window, "delete-event", G_CALLBACK (delete_window), NULL);
|
g_signal_connect (window, "delete-event", G_CALLBACK (delete_window), NULL);
|
||||||
|
g_signal_connect (window, "destroy", G_CALLBACK (destroy_window), NULL);
|
||||||
|
|
||||||
|
|
||||||
if (gtk_widget_get_visible (window) || status_icon_get_visible ())
|
if (gtk_widget_get_visible (window) || status_icon_get_visible ())
|
||||||
gtk_main ();
|
gtk_main ();
|
||||||
@@ -297,5 +308,7 @@ main (int argc, char *argv[])
|
|||||||
g_object_unref (status_icon_or_null);
|
g_object_unref (status_icon_or_null);
|
||||||
xfconf_shutdown ();
|
xfconf_shutdown ();
|
||||||
|
|
||||||
|
xtm_destroy_network_analyzer (analyzer);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
168
src/network-analyzer.c
Normal file
168
src/network-analyzer.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
|
*
|
||||||
|
* This program 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 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "network-analyzer.h"
|
||||||
|
#include "task-manager.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
void *network_analyzer_thread (void *ptr);
|
||||||
|
|
||||||
|
void
|
||||||
|
increament_packet_count (char *mac, char *direction, GHashTable *hash_table, long int port)
|
||||||
|
{
|
||||||
|
gint64 *key = g_new0 (gint64, 1);
|
||||||
|
*key = port;
|
||||||
|
gpointer value = g_hash_table_lookup (hash_table, key);
|
||||||
|
g_hash_table_replace (hash_table, key, (gpointer)(((guint64)value) + 1));
|
||||||
|
// printf ("%s -> %s %ld: %ld\n", mac, direction, port, ((guint64)value) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
network_analyzer_thread (void *ptr)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
XtmNetworkAnalyzer *analyzer = (XtmNetworkAnalyzer *)ptr;
|
||||||
|
pcap_loop (analyzer->handle, -1, packet_callback, (void *)analyzer);
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
XtmNetworkAnalyzer *
|
||||||
|
xtm_create_network_analyzer (void)
|
||||||
|
{
|
||||||
|
XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
XtmNetworkAnalyzer *current = NULL;
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
pcap_if_t *it = NULL;
|
||||||
|
|
||||||
|
if (pcap_findalldevs (&it, errbuf) != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error finding device: %s\n", errbuf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (it)
|
||||||
|
{
|
||||||
|
guint8 mac[6];
|
||||||
|
char *device = it->name;
|
||||||
|
|
||||||
|
//! todo check pcap lib ?
|
||||||
|
if (get_mac_address (device, mac) == 0)
|
||||||
|
{
|
||||||
|
printf (
|
||||||
|
"%s, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||||
|
device, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "No mac adresse for %s\n", device);
|
||||||
|
it = it->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a pcap session
|
||||||
|
pcap_t *handle = pcap_open_live (device, BUFSIZ, 1, 1000, errbuf);
|
||||||
|
|
||||||
|
if (handle == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Could not open device %s: %s\n", device, errbuf);
|
||||||
|
it = it->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (analyzer == NULL)
|
||||||
|
{
|
||||||
|
analyzer = (XtmNetworkAnalyzer *)malloc (sizeof (XtmNetworkAnalyzer));
|
||||||
|
analyzer->next = NULL;
|
||||||
|
current = analyzer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current->next = (XtmNetworkAnalyzer *)malloc (sizeof (XtmNetworkAnalyzer));
|
||||||
|
current = current->next;
|
||||||
|
current->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
current->handle = handle;
|
||||||
|
current->iface = it;
|
||||||
|
current->packetin = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
|
||||||
|
current->packetout = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
|
||||||
|
|
||||||
|
memcpy (current->mac, mac, sizeof (uint8_t) * 6);
|
||||||
|
|
||||||
|
pthread_mutex_init (¤t->lock, NULL);
|
||||||
|
pthread_create (¤t->thread, NULL, network_analyzer_thread, (void *)current);
|
||||||
|
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (analyzer == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Could not open any device %s\n", errbuf);
|
||||||
|
pcap_freealldevs (it);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return analyzer;
|
||||||
|
}
|
||||||
|
|
||||||
|
XtmNetworkAnalyzer *
|
||||||
|
xtm_network_analyzer_get_default (void)
|
||||||
|
{
|
||||||
|
static int initialized = FALSE;
|
||||||
|
static XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
|
||||||
|
if (initialized == FALSE)
|
||||||
|
{
|
||||||
|
initialized = TRUE;
|
||||||
|
// analyzer may be NULL if no device can be opened
|
||||||
|
analyzer = xtm_create_network_analyzer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return analyzer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_destroy_network_analyzer (XtmNetworkAnalyzer *analyzer)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
if (analyzer == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XtmNetworkAnalyzer *previous = analyzer;
|
||||||
|
pcap_if_t *it = analyzer->iface;
|
||||||
|
|
||||||
|
while (analyzer)
|
||||||
|
{
|
||||||
|
pthread_cancel (analyzer->thread);
|
||||||
|
pcap_close (analyzer->handle);
|
||||||
|
g_hash_table_destroy (analyzer->packetin);
|
||||||
|
g_hash_table_destroy (analyzer->packetout);
|
||||||
|
pthread_mutex_destroy (&analyzer->lock);
|
||||||
|
analyzer = analyzer->next;
|
||||||
|
free (previous);
|
||||||
|
previous = analyzer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcap_freealldevs (it);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
45
src/network-analyzer.h
Normal file
45
src/network-analyzer.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
|
*
|
||||||
|
* This program 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 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NETWORK_ANALYZER_H
|
||||||
|
#define NETWORK_ANALYZER_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
#include <pcap.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _XtmNetworkAnalyzer XtmNetworkAnalyzer;
|
||||||
|
struct _XtmNetworkAnalyzer
|
||||||
|
{
|
||||||
|
// interface mac adress
|
||||||
|
guint8 mac[6];
|
||||||
|
|
||||||
|
void *iface; // pcap_if_t
|
||||||
|
void *handle; // pcap_t
|
||||||
|
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
|
||||||
|
// map port and number of packets
|
||||||
|
GHashTable *packetin;
|
||||||
|
GHashTable *packetout;
|
||||||
|
|
||||||
|
// next interface
|
||||||
|
XtmNetworkAnalyzer *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
XtmNetworkAnalyzer *xtm_create_network_analyzer (void);
|
||||||
|
void increament_packet_count (char *mac, char *direction, GHashTable *hash_table, long int port);
|
||||||
|
void xtm_destroy_network_analyzer (XtmNetworkAnalyzer *analyzer);
|
||||||
|
XtmNetworkAnalyzer *xtm_network_analyzer_get_default (void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
|
||||||
|
#define MAX_GRAPH 3
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -34,8 +34,8 @@ struct _XtmProcessMonitor
|
|||||||
/*<private>*/
|
/*<private>*/
|
||||||
gfloat step_size;
|
gfloat step_size;
|
||||||
gint type;
|
gint type;
|
||||||
GArray *history;
|
GArray *history[MAX_GRAPH];
|
||||||
GArray *history_swap;
|
gfloat max[MAX_GRAPH];
|
||||||
gboolean dark_mode;
|
gboolean dark_mode;
|
||||||
};
|
};
|
||||||
G_DEFINE_TYPE (XtmProcessMonitor, xtm_process_monitor, GTK_TYPE_DRAWING_AREA)
|
G_DEFINE_TYPE (XtmProcessMonitor, xtm_process_monitor, GTK_TYPE_DRAWING_AREA)
|
||||||
@@ -76,8 +76,12 @@ xtm_process_monitor_init (XtmProcessMonitor *monitor)
|
|||||||
{
|
{
|
||||||
GtkSettings *settings = gtk_settings_get_default ();
|
GtkSettings *settings = gtk_settings_get_default ();
|
||||||
|
|
||||||
monitor->history = g_array_new (FALSE, TRUE, sizeof (gfloat));
|
for (int graph = 0; graph < MAX_GRAPH; ++graph)
|
||||||
monitor->history_swap = g_array_new (FALSE, TRUE, sizeof (gfloat));
|
{
|
||||||
|
monitor->history[graph] = g_array_new (FALSE, TRUE, sizeof (gfloat));
|
||||||
|
monitor->max[graph] = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
monitor->dark_mode = xtm_gtk_widget_is_dark_mode (GTK_WIDGET (monitor));
|
monitor->dark_mode = xtm_gtk_widget_is_dark_mode (GTK_WIDGET (monitor));
|
||||||
|
|
||||||
g_signal_connect_swapped (settings, "notify::gtk-theme-name", G_CALLBACK (xtm_process_monitor_on_notify_theme_name), monitor);
|
g_signal_connect_swapped (settings, "notify::gtk-theme-name", G_CALLBACK (xtm_process_monitor_on_notify_theme_name), monitor);
|
||||||
@@ -89,8 +93,8 @@ xtm_process_monitor_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
XtmProcessMonitor *monitor = XTM_PROCESS_MONITOR (object);
|
XtmProcessMonitor *monitor = XTM_PROCESS_MONITOR (object);
|
||||||
|
|
||||||
g_array_free (monitor->history, TRUE);
|
for (int graph = 0; graph < MAX_GRAPH; ++graph)
|
||||||
g_array_free (monitor->history_swap, TRUE);
|
g_array_free (monitor->history[graph], TRUE);
|
||||||
|
|
||||||
G_OBJECT_CLASS (xtm_process_monitor_parent_class)->finalize (object);
|
G_OBJECT_CLASS (xtm_process_monitor_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@@ -142,13 +146,10 @@ xtm_process_monitor_draw (GtkWidget *widget, cairo_t *cr)
|
|||||||
guint minimum_history_length;
|
guint minimum_history_length;
|
||||||
|
|
||||||
minimum_history_length = (guint)(gtk_widget_get_allocated_width (widget) / monitor->step_size);
|
minimum_history_length = (guint)(gtk_widget_get_allocated_width (widget) / monitor->step_size);
|
||||||
if (monitor->history->len < minimum_history_length)
|
|
||||||
{
|
|
||||||
g_array_set_size (monitor->history, minimum_history_length + 1);
|
|
||||||
if (monitor->type == 1)
|
|
||||||
g_array_set_size (monitor->history_swap, minimum_history_length + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (int graph = 0; graph < MAX_GRAPH; ++graph)
|
||||||
|
if (monitor->history[graph]->len < minimum_history_length)
|
||||||
|
g_array_set_size (monitor->history[graph], minimum_history_length + 1);
|
||||||
|
|
||||||
xtm_process_monitor_paint (monitor, cr);
|
xtm_process_monitor_paint (monitor, cr);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -172,6 +173,30 @@ xtm_process_monitor_cairo_set_source_rgb (cairo_t *cr, double red, double green,
|
|||||||
cairo_set_source_rgb (cr, red, green, blue);
|
cairo_set_source_rgb (cr, red, green, blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xtm_process_monitor_cairo_set_color (XtmProcessMonitor *monitor, cairo_t *cr, gfloat alpha, guint variant)
|
||||||
|
{
|
||||||
|
if (monitor->type == 0)
|
||||||
|
xtm_process_monitor_cairo_set_source_rgba (cr, 1.0, 0.43, 0.0, alpha, monitor->dark_mode);
|
||||||
|
else if (monitor->type == 1)
|
||||||
|
{
|
||||||
|
// xtm_process_monitor_cairo_set_source_rgba (cr, 0.67, 0.09, 0.32, alpha, monitor->dark_mode);
|
||||||
|
if (variant == 0)
|
||||||
|
xtm_process_monitor_cairo_set_source_rgba (cr, 0.80, 0.22, 0.42, alpha, monitor->dark_mode);
|
||||||
|
else
|
||||||
|
xtm_process_monitor_cairo_set_source_rgba (cr, 0.50, 0.50, 0.50, alpha, monitor->dark_mode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (variant == 0)
|
||||||
|
xtm_process_monitor_cairo_set_source_rgba (cr, 0.00, 0.42, 0.64, alpha, monitor->dark_mode);
|
||||||
|
else if (variant == 1)
|
||||||
|
xtm_process_monitor_cairo_set_source_rgba (cr, 0.02, 0.71, 0.81, alpha, monitor->dark_mode);
|
||||||
|
else
|
||||||
|
xtm_process_monitor_cairo_set_source_rgba (cr, 0.00, 1.00, 1.00, alpha, monitor->dark_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static cairo_surface_t *
|
static cairo_surface_t *
|
||||||
xtm_process_monitor_graph_surface_create (XtmProcessMonitor *monitor, gint width, gint height)
|
xtm_process_monitor_graph_surface_create (XtmProcessMonitor *monitor, gint width, gint height)
|
||||||
{
|
{
|
||||||
@@ -180,69 +205,39 @@ xtm_process_monitor_graph_surface_create (XtmProcessMonitor *monitor, gint width
|
|||||||
gdouble peak, step_size;
|
gdouble peak, step_size;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
if (monitor->history->len <= 1)
|
|
||||||
{
|
|
||||||
g_warning ("Cannot paint graph with n_peak <= 1");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
step_size = (gdouble)monitor->step_size;
|
step_size = (gdouble)monitor->step_size;
|
||||||
|
|
||||||
graph_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
graph_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||||
cr = cairo_create (graph_surface);
|
cr = cairo_create (graph_surface);
|
||||||
|
|
||||||
/* Draw line and area below the line, distinguish between CPU (0) and Mem (1) color-wise */
|
/* Draw line and area below the line, distinguish between CPU (0) and Mem (1) color-wise */
|
||||||
cairo_translate (cr, step_size, 0);
|
|
||||||
cairo_set_line_width (cr, 0.85);
|
cairo_set_line_width (cr, 0.85);
|
||||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
||||||
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
|
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
|
||||||
cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
|
cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
|
||||||
cairo_move_to (cr, width, height);
|
|
||||||
|
|
||||||
/* Create a line before the call to cairo_translate,
|
for (int graph = 0; graph < MAX_GRAPH; ++graph)
|
||||||
* to avoid creating a downward sloping line going off the graph */
|
{
|
||||||
peak = g_array_index (monitor->history, gfloat, 0);
|
if (monitor->history[graph]->len <= 1)
|
||||||
cairo_line_to (cr, width, (1.0 - peak) * height);
|
continue;
|
||||||
|
|
||||||
|
cairo_move_to (cr, width, height);
|
||||||
|
cairo_translate (cr, step_size, 0);
|
||||||
|
xtm_process_monitor_cairo_set_color (monitor, cr, 0.3, graph);
|
||||||
|
|
||||||
for (i = 0; (step_size * (i - 1)) <= width; i++)
|
for (i = 0; (step_size * (i - 1)) <= width; i++)
|
||||||
{
|
{
|
||||||
peak = g_array_index (monitor->history, gfloat, i);
|
peak = g_array_index (monitor->history[graph], gfloat, i) / monitor->max[graph];
|
||||||
cairo_translate (cr, -step_size, 0);
|
cairo_translate (cr, -step_size, 0);
|
||||||
cairo_line_to (cr, width, (1.0 - peak) * height);
|
cairo_line_to (cr, width, (1.0 - peak) * height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monitor->type == 0)
|
|
||||||
xtm_process_monitor_cairo_set_source_rgba (cr, 1.0, 0.43, 0.0, 0.3, monitor->dark_mode);
|
|
||||||
else
|
|
||||||
xtm_process_monitor_cairo_set_source_rgba (cr, 0.67, 0.09, 0.32, 0.3, monitor->dark_mode);
|
|
||||||
cairo_line_to (cr, width, height);
|
cairo_line_to (cr, width, height);
|
||||||
cairo_fill_preserve (cr);
|
cairo_fill_preserve (cr);
|
||||||
|
xtm_process_monitor_cairo_set_color (monitor, cr, 1.0, graph);
|
||||||
if (monitor->type == 0)
|
|
||||||
xtm_process_monitor_cairo_set_source_rgba (cr, 1.0, 0.43, 0.0, 1.0, monitor->dark_mode);
|
|
||||||
else
|
|
||||||
xtm_process_monitor_cairo_set_source_rgba (cr, 0.67, 0.09, 0.32, 1.0, monitor->dark_mode);
|
|
||||||
cairo_stroke (cr);
|
cairo_stroke (cr);
|
||||||
|
|
||||||
/* Draw Swap graph */
|
cairo_translate (cr, width, 0);
|
||||||
if (monitor->type == 1)
|
|
||||||
{
|
|
||||||
cairo_translate (cr, step_size * i, 0);
|
|
||||||
cairo_move_to (cr, width, height);
|
|
||||||
|
|
||||||
peak = g_array_index (monitor->history_swap, gfloat, 0);
|
|
||||||
cairo_line_to (cr, width, (1.0 - peak) * height);
|
|
||||||
|
|
||||||
for (i = 0; (step_size * (i - 1)) <= width; i++)
|
|
||||||
{
|
|
||||||
peak = g_array_index (monitor->history_swap, gfloat, i);
|
|
||||||
cairo_translate (cr, -step_size, 0);
|
|
||||||
cairo_line_to (cr, width, (1.0 - peak) * height);
|
|
||||||
}
|
|
||||||
xtm_process_monitor_cairo_set_source_rgba (cr, 0.33, 0.04, 0.16, 0.3, monitor->dark_mode);
|
|
||||||
cairo_line_to (cr, width, height);
|
|
||||||
cairo_fill_preserve (cr);
|
|
||||||
xtm_process_monitor_cairo_set_source_rgba (cr, 0.33, 0.04, 0.16, 1.0, monitor->dark_mode);
|
|
||||||
cairo_stroke (cr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_destroy (cr);
|
cairo_destroy (cr);
|
||||||
@@ -300,21 +295,17 @@ xtm_process_monitor_new (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xtm_process_monitor_add_peak (XtmProcessMonitor *monitor, gfloat peak, gfloat peak_swap)
|
xtm_process_monitor_add_peak (XtmProcessMonitor *monitor, gfloat peak, gint index)
|
||||||
{
|
{
|
||||||
g_return_if_fail (XTM_IS_PROCESS_MONITOR (monitor));
|
g_return_if_fail (XTM_IS_PROCESS_MONITOR (monitor));
|
||||||
g_return_if_fail (peak >= 0.0f && peak <= 1.0f);
|
// g_return_if_fail (peak >= 0.0f && peak <= 1.0f);
|
||||||
|
|
||||||
g_array_prepend_val (monitor->history, peak);
|
if (peak > monitor->max[index])
|
||||||
if (monitor->history->len > 1)
|
monitor->max[index] = peak;
|
||||||
g_array_remove_index (monitor->history, monitor->history->len - 1);
|
|
||||||
|
|
||||||
if (monitor->type == 1)
|
g_array_prepend_val (monitor->history[index], peak);
|
||||||
{
|
if (monitor->history[index]->len > 1)
|
||||||
g_array_prepend_val (monitor->history_swap, peak_swap);
|
g_array_remove_index (monitor->history[index], monitor->history[index]->len - 1);
|
||||||
if (monitor->history_swap->len > 1)
|
|
||||||
g_array_remove_index (monitor->history_swap, monitor->history_swap->len - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (monitor))))
|
if (GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (monitor))))
|
||||||
gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (monitor)), NULL, FALSE);
|
gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (monitor)), NULL, FALSE);
|
||||||
@@ -340,8 +331,8 @@ void
|
|||||||
xtm_process_monitor_clear (XtmProcessMonitor *monitor)
|
xtm_process_monitor_clear (XtmProcessMonitor *monitor)
|
||||||
{
|
{
|
||||||
g_return_if_fail (XTM_IS_PROCESS_MONITOR (monitor));
|
g_return_if_fail (XTM_IS_PROCESS_MONITOR (monitor));
|
||||||
g_array_set_size (monitor->history, 0);
|
for (int graph = 0; graph < MAX_GRAPH; ++graph)
|
||||||
g_array_set_size (monitor->history_swap, 0);
|
g_array_set_size (monitor->history[graph], 0);
|
||||||
if (GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (monitor))))
|
if (GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (monitor))))
|
||||||
gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (monitor)), NULL, FALSE);
|
gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (monitor)), NULL, FALSE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
* Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
|
* Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -24,7 +25,7 @@ typedef struct _XtmProcessMonitor XtmProcessMonitor;
|
|||||||
|
|
||||||
GType xtm_process_monitor_get_type (void);
|
GType xtm_process_monitor_get_type (void);
|
||||||
GtkWidget *xtm_process_monitor_new (void);
|
GtkWidget *xtm_process_monitor_new (void);
|
||||||
void xtm_process_monitor_add_peak (XtmProcessMonitor *monitor, gfloat peak, gfloat peak_swap);
|
void xtm_process_monitor_add_peak (XtmProcessMonitor *monitor, gfloat peak, gint index);
|
||||||
void xtm_process_monitor_set_step_size (XtmProcessMonitor *monitor, gfloat step_size);
|
void xtm_process_monitor_set_step_size (XtmProcessMonitor *monitor, gfloat step_size);
|
||||||
void xtm_process_monitor_set_type (XtmProcessMonitor *monitor, gint type);
|
void xtm_process_monitor_set_type (XtmProcessMonitor *monitor, gint type);
|
||||||
void xtm_process_monitor_clear (XtmProcessMonitor *monitor);
|
void xtm_process_monitor_clear (XtmProcessMonitor *monitor);
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ enum
|
|||||||
PROP_SWAP,
|
PROP_SWAP,
|
||||||
PROP_SHOW_SWAP,
|
PROP_SHOW_SWAP,
|
||||||
PROP_NUM_PROCESSES,
|
PROP_NUM_PROCESSES,
|
||||||
|
PROP_NETWORK_RX,
|
||||||
|
PROP_NETWORK_TX,
|
||||||
|
PROP_NETWORK_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _XtmProcessStatusbarClass XtmProcessStatusbarClass;
|
typedef struct _XtmProcessStatusbarClass XtmProcessStatusbarClass;
|
||||||
struct _XtmProcessStatusbarClass
|
struct _XtmProcessStatusbarClass
|
||||||
{
|
{
|
||||||
@@ -43,11 +47,19 @@ struct _XtmProcessStatusbar
|
|||||||
GtkWidget *label_memory;
|
GtkWidget *label_memory;
|
||||||
GtkWidget *label_swap;
|
GtkWidget *label_swap;
|
||||||
|
|
||||||
|
GtkWidget *label_net_rx;
|
||||||
|
GtkWidget *label_net_tx;
|
||||||
|
GtkWidget *label_net_error;
|
||||||
|
|
||||||
gfloat cpu;
|
gfloat cpu;
|
||||||
gchar memory[64];
|
gchar memory[64];
|
||||||
gchar swap[64];
|
gchar swap[64];
|
||||||
guint num_processes;
|
guint num_processes;
|
||||||
|
|
||||||
|
gfloat tcp_rx;
|
||||||
|
gfloat tcp_tx;
|
||||||
|
guint64 tcp_error;
|
||||||
|
|
||||||
gboolean dark_mode;
|
gboolean dark_mode;
|
||||||
};
|
};
|
||||||
G_DEFINE_TYPE (XtmProcessStatusbar, xtm_process_statusbar, GTK_TYPE_BOX)
|
G_DEFINE_TYPE (XtmProcessStatusbar, xtm_process_statusbar, GTK_TYPE_BOX)
|
||||||
@@ -74,6 +86,12 @@ xtm_process_statusbar_class_init (XtmProcessStatusbarClass *klass)
|
|||||||
g_param_spec_boolean ("show-swap", "ShowSwap", "Show or hide swap usage", TRUE, G_PARAM_WRITABLE));
|
g_param_spec_boolean ("show-swap", "ShowSwap", "Show or hide swap usage", TRUE, G_PARAM_WRITABLE));
|
||||||
g_object_class_install_property (class, PROP_NUM_PROCESSES,
|
g_object_class_install_property (class, PROP_NUM_PROCESSES,
|
||||||
g_param_spec_uint ("num-processes", "NumProcesses", "Number of processes", 0, G_MAXUINT, 0, G_PARAM_CONSTRUCT | G_PARAM_WRITABLE));
|
g_param_spec_uint ("num-processes", "NumProcesses", "Number of processes", 0, G_MAXUINT, 0, G_PARAM_CONSTRUCT | G_PARAM_WRITABLE));
|
||||||
|
g_object_class_install_property (class, PROP_NETWORK_RX,
|
||||||
|
g_param_spec_float ("network-rx", "RX", "Net rx", 0, 100, 0, G_PARAM_CONSTRUCT | G_PARAM_WRITABLE));
|
||||||
|
g_object_class_install_property (class, PROP_NETWORK_TX,
|
||||||
|
g_param_spec_float ("network-tx", "TX", "Net tx", 0, 100, 0, G_PARAM_CONSTRUCT | G_PARAM_WRITABLE));
|
||||||
|
g_object_class_install_property (class, PROP_NETWORK_ERROR,
|
||||||
|
g_param_spec_uint64 ("network-error", "NetEror", "Number of error since last update", 0, G_MAXUINT64, 0, G_PARAM_CONSTRUCT | G_PARAM_WRITABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -99,13 +117,16 @@ xtm_process_statusbar_on_notify_theme_name (XtmProcessStatusbar *statusbar)
|
|||||||
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_num_processes);
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_num_processes);
|
||||||
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_memory);
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_memory);
|
||||||
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_swap);
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_swap);
|
||||||
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_net_rx);
|
||||||
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_net_tx);
|
||||||
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_net_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xtm_process_statusbar_init (XtmProcessStatusbar *statusbar)
|
xtm_process_statusbar_init (XtmProcessStatusbar *statusbar)
|
||||||
{
|
{
|
||||||
GtkSettings *settings = gtk_settings_get_default ();
|
GtkSettings *settings = gtk_settings_get_default ();
|
||||||
GtkWidget *hbox, *hbox_cpu, *hbox_mem;
|
GtkWidget *hbox, *hbox_cpu, *hbox_net, *hbox_mem;
|
||||||
GtkStyleContext *context;
|
GtkStyleContext *context;
|
||||||
GtkCssProvider *provider;
|
GtkCssProvider *provider;
|
||||||
statusbar->settings = xtm_settings_get_default ();
|
statusbar->settings = xtm_settings_get_default ();
|
||||||
@@ -116,6 +137,7 @@ xtm_process_statusbar_init (XtmProcessStatusbar *statusbar)
|
|||||||
|
|
||||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
||||||
hbox_cpu = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
hbox_cpu = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
||||||
|
hbox_net = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
||||||
hbox_mem = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
hbox_mem = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
|
||||||
|
|
||||||
statusbar->label_cpu = gtk_label_new (NULL);
|
statusbar->label_cpu = gtk_label_new (NULL);
|
||||||
@@ -143,11 +165,39 @@ xtm_process_statusbar_init (XtmProcessStatusbar *statusbar)
|
|||||||
gtk_box_pack_start (GTK_BOX (hbox_mem), statusbar->label_swap, TRUE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (hbox_mem), statusbar->label_swap, TRUE, FALSE, 0);
|
||||||
context = gtk_widget_get_style_context (statusbar->label_swap);
|
context = gtk_widget_get_style_context (statusbar->label_swap);
|
||||||
provider = gtk_css_provider_new ();
|
provider = gtk_css_provider_new ();
|
||||||
gtk_css_provider_load_from_data (provider, "* { color: #75324d; } .dark { color: #8acdb2; }", -1, NULL);
|
gtk_css_provider_load_from_data (provider, "* { color: #808080; } .dark { color: #808080; }", -1, NULL);
|
||||||
|
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
|
g_object_unref (provider);
|
||||||
|
|
||||||
|
statusbar->label_net_rx = gtk_label_new (NULL);
|
||||||
|
gtk_label_set_ellipsize (GTK_LABEL (statusbar->label_net_rx), PANGO_ELLIPSIZE_END);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox_net), statusbar->label_net_rx, TRUE, FALSE, 0);
|
||||||
|
context = gtk_widget_get_style_context (statusbar->label_net_rx);
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_data (provider, "* { color: #006ca2; } .dark { color: #ff935d; }", -1, NULL);
|
||||||
|
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
|
g_object_unref (provider);
|
||||||
|
|
||||||
|
statusbar->label_net_tx = gtk_label_new (NULL);
|
||||||
|
gtk_label_set_ellipsize (GTK_LABEL (statusbar->label_net_tx), PANGO_ELLIPSIZE_END);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox_net), statusbar->label_net_tx, TRUE, FALSE, 0);
|
||||||
|
context = gtk_widget_get_style_context (statusbar->label_net_tx);
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_data (provider, "* { color: #05b6ce; } .dark { color: #fa4931; }", -1, NULL);
|
||||||
|
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
|
g_object_unref (provider);
|
||||||
|
|
||||||
|
statusbar->label_net_error = gtk_label_new (NULL);
|
||||||
|
gtk_label_set_ellipsize (GTK_LABEL (statusbar->label_net_error), PANGO_ELLIPSIZE_END);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox_net), statusbar->label_net_error, TRUE, FALSE, 0);
|
||||||
|
context = gtk_widget_get_style_context (statusbar->label_net_error);
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_data (provider, "* { color: #008080; } .dark { color: #FF0000; }", -1, NULL);
|
||||||
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
g_object_unref (provider);
|
g_object_unref (provider);
|
||||||
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), hbox_cpu, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (hbox), hbox_cpu, TRUE, TRUE, 0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), hbox_net, TRUE, TRUE, 0);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), hbox_mem, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (hbox), hbox_mem, TRUE, TRUE, 0);
|
||||||
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
|
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
|
||||||
|
|
||||||
@@ -157,6 +207,9 @@ xtm_process_statusbar_init (XtmProcessStatusbar *statusbar)
|
|||||||
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_num_processes);
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_num_processes);
|
||||||
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_memory);
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_memory);
|
||||||
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_swap);
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_swap);
|
||||||
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_net_rx);
|
||||||
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_net_tx);
|
||||||
|
xtm_process_statusbar_set_label_style (statusbar, statusbar->label_net_error);
|
||||||
|
|
||||||
gtk_widget_show_all (hbox);
|
gtk_widget_show_all (hbox);
|
||||||
}
|
}
|
||||||
@@ -224,6 +277,31 @@ xtm_process_statusbar_set_property (GObject *object, guint property_id, const GV
|
|||||||
g_free (text);
|
g_free (text);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_NETWORK_RX:
|
||||||
|
statusbar->tcp_rx = g_value_get_float (value);
|
||||||
|
// statusbar->tcp_rx = interval_to_second(statusbar->tcp_rx, statusbar->settings);
|
||||||
|
float_value = rounded_float_value (statusbar->tcp_rx, statusbar->settings);
|
||||||
|
text = g_strdup_printf (_("RX: %s MB/s"), float_value);
|
||||||
|
gtk_label_set_text (GTK_LABEL (statusbar->label_net_rx), text);
|
||||||
|
g_free (text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_NETWORK_TX:
|
||||||
|
statusbar->tcp_tx = g_value_get_float (value);
|
||||||
|
// statusbar->tcp_tx = interval_to_second(statusbar->tcp_tx, statusbar->settings);
|
||||||
|
float_value = rounded_float_value (statusbar->tcp_tx, statusbar->settings);
|
||||||
|
text = g_strdup_printf (_("TX: %s MB/s"), float_value);
|
||||||
|
gtk_label_set_text (GTK_LABEL (statusbar->label_net_tx), text);
|
||||||
|
g_free (text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_NETWORK_ERROR:
|
||||||
|
statusbar->tcp_error = g_value_get_uint64 (value);
|
||||||
|
text = g_strdup_printf (_("Error: %lu"), statusbar->tcp_error);
|
||||||
|
gtk_label_set_text (GTK_LABEL (statusbar->label_net_error), text);
|
||||||
|
g_free (text);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -11,6 +11,15 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cairo-gobject.h>
|
||||||
|
#include <gdk/gdkkeysyms.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <glib/gprintf.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "process-tree-model.h"
|
#include "process-tree-model.h"
|
||||||
#include "process-tree-view.h"
|
#include "process-tree-view.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -37,6 +46,9 @@ enum
|
|||||||
COLUMN_UID,
|
COLUMN_UID,
|
||||||
COLUMN_CPU,
|
COLUMN_CPU,
|
||||||
COLUMN_GROUP_CPU,
|
COLUMN_GROUP_CPU,
|
||||||
|
COLUMN_PACKET_IN,
|
||||||
|
COLUMN_PACKET_OUT,
|
||||||
|
COLUMN_ACTIVE_SOCKET,
|
||||||
COLUMN_PRIORITY,
|
COLUMN_PRIORITY,
|
||||||
N_COLUMNS,
|
N_COLUMNS,
|
||||||
};
|
};
|
||||||
@@ -88,6 +100,7 @@ xtm_process_tree_view_class_init (XtmProcessTreeViewClass *klass)
|
|||||||
static void
|
static void
|
||||||
xtm_process_tree_view_init (XtmProcessTreeView *treeview)
|
xtm_process_tree_view_init (XtmProcessTreeView *treeview)
|
||||||
{
|
{
|
||||||
|
XtmNetworkAnalyzer *network;
|
||||||
GtkCellRenderer *cell_text, *cell_right_aligned;
|
GtkCellRenderer *cell_text, *cell_right_aligned;
|
||||||
GtkTreeViewColumn *column;
|
GtkTreeViewColumn *column;
|
||||||
gboolean visible;
|
gboolean visible;
|
||||||
@@ -122,6 +135,9 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview)
|
|||||||
G_TYPE_STRING, /* XTM_PTV_COLUMN_CPU_STR */
|
G_TYPE_STRING, /* XTM_PTV_COLUMN_CPU_STR */
|
||||||
G_TYPE_FLOAT, /* XTM_PTV_COLUMN_GROUP_CPU */
|
G_TYPE_FLOAT, /* XTM_PTV_COLUMN_GROUP_CPU */
|
||||||
G_TYPE_STRING, /* XTM_PTV_COLUMN_GROUP_CPU_STR */
|
G_TYPE_STRING, /* XTM_PTV_COLUMN_GROUP_CPU_STR */
|
||||||
|
G_TYPE_UINT64, /* XTM_PTV_COLUMN_PACKET_IN */
|
||||||
|
G_TYPE_UINT64, /* XTM_PTV_COLUMN_PACKET_OUT */
|
||||||
|
G_TYPE_UINT64, /* XTM_PTV_COLUMN_ACTIVE_SOCKET */
|
||||||
G_TYPE_INT, /* XTM_PTV_COLUMN_PRIORITY */
|
G_TYPE_INT, /* XTM_PTV_COLUMN_PRIORITY */
|
||||||
G_TYPE_STRING, /* XTM_PTV_COLUMN_BACKGROUND */
|
G_TYPE_STRING, /* XTM_PTV_COLUMN_BACKGROUND */
|
||||||
G_TYPE_STRING, /* XTM_PTV_COLUMN_FOREGROUND */
|
G_TYPE_STRING, /* XTM_PTV_COLUMN_FOREGROUND */
|
||||||
@@ -245,6 +261,43 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview)
|
|||||||
g_signal_connect (column, "clicked", G_CALLBACK (column_clicked), treeview);
|
g_signal_connect (column, "clicked", G_CALLBACK (column_clicked), treeview);
|
||||||
gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), column, treeview->columns_positions[COLUMN_GROUP_CPU]);
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), column, treeview->columns_positions[COLUMN_GROUP_CPU]);
|
||||||
|
|
||||||
|
/*************/
|
||||||
|
|
||||||
|
g_object_get (treeview->settings, "column-packet-in", &visible, NULL);
|
||||||
|
column = gtk_tree_view_column_new_with_attributes (_("PacketIn"), cell_right_aligned, "text", XTM_PTV_COLUMN_PACKET_IN, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL);
|
||||||
|
g_object_set (column, COLUMN_PROPERTIES, NULL);
|
||||||
|
g_object_set_data (G_OBJECT (column), "sort-column-id", GINT_TO_POINTER (XTM_PTV_COLUMN_PACKET_IN));
|
||||||
|
g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_PACKET_IN));
|
||||||
|
g_signal_connect (column, "clicked", G_CALLBACK (column_clicked), treeview);
|
||||||
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), column, treeview->columns_positions[COLUMN_PACKET_IN]);
|
||||||
|
|
||||||
|
g_object_get (treeview->settings, "column-packet-out", &visible, NULL);
|
||||||
|
column = gtk_tree_view_column_new_with_attributes (_("PacketOut"), cell_right_aligned, "text", XTM_PTV_COLUMN_PACKET_OUT, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL);
|
||||||
|
g_object_set (column, COLUMN_PROPERTIES, NULL);
|
||||||
|
g_object_set_data (G_OBJECT (column), "sort-column-id", GINT_TO_POINTER (XTM_PTV_COLUMN_PACKET_OUT));
|
||||||
|
g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_PACKET_OUT));
|
||||||
|
g_signal_connect (column, "clicked", G_CALLBACK (column_clicked), treeview);
|
||||||
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), column, treeview->columns_positions[COLUMN_PACKET_OUT]);
|
||||||
|
|
||||||
|
g_object_get (treeview->settings, "column-active-socket", &visible, NULL);
|
||||||
|
column = gtk_tree_view_column_new_with_attributes (_("ActiveSocket"), cell_right_aligned, "text", XTM_PTV_COLUMN_ACTIVE_SOCKET, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL);
|
||||||
|
g_object_set (column, COLUMN_PROPERTIES, NULL);
|
||||||
|
g_object_set_data (G_OBJECT (column), "sort-column-id", GINT_TO_POINTER (XTM_PTV_COLUMN_ACTIVE_SOCKET));
|
||||||
|
g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_ACTIVE_SOCKET));
|
||||||
|
g_signal_connect (column, "clicked", G_CALLBACK (column_clicked), treeview);
|
||||||
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), column, treeview->columns_positions[COLUMN_ACTIVE_SOCKET]);
|
||||||
|
|
||||||
|
// insufficient permission
|
||||||
|
network = xtm_network_analyzer_get_default ();
|
||||||
|
if (network == NULL)
|
||||||
|
{
|
||||||
|
gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), treeview->columns_positions[COLUMN_PACKET_IN]), FALSE);
|
||||||
|
gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), treeview->columns_positions[COLUMN_PACKET_OUT]), FALSE);
|
||||||
|
gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), treeview->columns_positions[COLUMN_ACTIVE_SOCKET]), FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
|
||||||
g_object_get (treeview->settings, "column-priority", &visible, NULL);
|
g_object_get (treeview->settings, "column-priority", &visible, NULL);
|
||||||
/* TRANSLATORS: “Prio.” is short for Priority, it appears in the tree view header. */
|
/* TRANSLATORS: “Prio.” is short for Priority, it appears in the tree view header. */
|
||||||
column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", XTM_PTV_COLUMN_PRIORITY, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL);
|
column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", XTM_PTV_COLUMN_PRIORITY, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL);
|
||||||
@@ -842,6 +895,12 @@ settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treevi
|
|||||||
column_id = COLUMN_GROUP_CPU;
|
column_id = COLUMN_GROUP_CPU;
|
||||||
else if (!g_strcmp0 (pspec->name, "column-priority"))
|
else if (!g_strcmp0 (pspec->name, "column-priority"))
|
||||||
column_id = COLUMN_PRIORITY;
|
column_id = COLUMN_PRIORITY;
|
||||||
|
else if (!g_strcmp0 (pspec->name, "column-packet-in"))
|
||||||
|
column_id = COLUMN_PACKET_IN;
|
||||||
|
else if (!g_strcmp0 (pspec->name, "column-packet-out"))
|
||||||
|
column_id = COLUMN_PACKET_OUT;
|
||||||
|
else if (!g_strcmp0 (pspec->name, "column-active-socket"))
|
||||||
|
column_id = COLUMN_ACTIVE_SOCKET;
|
||||||
|
|
||||||
g_object_get (object, pspec->name, &visible, NULL);
|
g_object_get (object, pspec->name, &visible, NULL);
|
||||||
gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), treeview->columns_positions[column_id]), visible);
|
gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), treeview->columns_positions[column_id]), visible);
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ enum
|
|||||||
XTM_PTV_COLUMN_CPU_STR,
|
XTM_PTV_COLUMN_CPU_STR,
|
||||||
XTM_PTV_COLUMN_GROUP_CPU,
|
XTM_PTV_COLUMN_GROUP_CPU,
|
||||||
XTM_PTV_COLUMN_GROUP_CPU_STR,
|
XTM_PTV_COLUMN_GROUP_CPU_STR,
|
||||||
|
XTM_PTV_COLUMN_PACKET_IN,
|
||||||
|
XTM_PTV_COLUMN_PACKET_OUT,
|
||||||
|
XTM_PTV_COLUMN_ACTIVE_SOCKET,
|
||||||
XTM_PTV_COLUMN_PRIORITY,
|
XTM_PTV_COLUMN_PRIORITY,
|
||||||
XTM_PTV_COLUMN_BACKGROUND,
|
XTM_PTV_COLUMN_BACKGROUND,
|
||||||
XTM_PTV_COLUMN_FOREGROUND,
|
XTM_PTV_COLUMN_FOREGROUND,
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ struct _XtmProcessWindow
|
|||||||
GtkWidget *filter_searchbar;
|
GtkWidget *filter_searchbar;
|
||||||
GtkWidget *cpu_monitor;
|
GtkWidget *cpu_monitor;
|
||||||
GtkWidget *mem_monitor;
|
GtkWidget *mem_monitor;
|
||||||
|
GtkWidget *net_monitor;
|
||||||
GtkWidget *vpaned;
|
GtkWidget *vpaned;
|
||||||
GtkWidget *treeview;
|
GtkWidget *treeview;
|
||||||
GtkWidget *statusbar;
|
GtkWidget *statusbar;
|
||||||
@@ -347,6 +348,13 @@ xtm_process_window_init (XtmProcessWindow *window)
|
|||||||
gtk_widget_show (window->mem_monitor);
|
gtk_widget_show (window->mem_monitor);
|
||||||
gtk_container_add (GTK_CONTAINER (toolitem), window->mem_monitor);
|
gtk_container_add (GTK_CONTAINER (toolitem), window->mem_monitor);
|
||||||
|
|
||||||
|
toolitem = GTK_WIDGET (gtk_builder_get_object (window->builder, "graph-net"));
|
||||||
|
window->net_monitor = xtm_process_monitor_new ();
|
||||||
|
xtm_process_monitor_set_step_size (XTM_PROCESS_MONITOR (window->net_monitor), refresh_rate / 1000.0f);
|
||||||
|
xtm_process_monitor_set_type (XTM_PROCESS_MONITOR (window->net_monitor), 2);
|
||||||
|
gtk_widget_show (window->net_monitor);
|
||||||
|
gtk_container_add (GTK_CONTAINER (toolitem), window->net_monitor);
|
||||||
|
|
||||||
g_signal_connect_swapped (window->settings, "notify::refresh-rate", G_CALLBACK (monitor_update_step_size), window);
|
g_signal_connect_swapped (window->settings, "notify::refresh-rate", G_CALLBACK (monitor_update_step_size), window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,6 +497,7 @@ monitor_update_step_size (XtmProcessWindow *window)
|
|||||||
g_object_get (window->settings, "refresh-rate", &refresh_rate, NULL);
|
g_object_get (window->settings, "refresh-rate", &refresh_rate, NULL);
|
||||||
g_object_set (window->cpu_monitor, "step-size", refresh_rate / 1000.0, NULL);
|
g_object_set (window->cpu_monitor, "step-size", refresh_rate / 1000.0, NULL);
|
||||||
g_object_set (window->mem_monitor, "step-size", refresh_rate / 1000.0, NULL);
|
g_object_set (window->mem_monitor, "step-size", refresh_rate / 1000.0, NULL);
|
||||||
|
g_object_set (window->net_monitor, "step-size", refresh_rate / 1000.0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -511,6 +520,12 @@ xtm_process_window_show (GtkWidget *widget)
|
|||||||
GTK_WIDGET_CLASS (xtm_process_window_parent_class)->show (widget);
|
GTK_WIDGET_CLASS (xtm_process_window_parent_class)->show (widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GtkWindow *
|
||||||
|
xtm_process_window_get (XtmProcessWindow *window)
|
||||||
|
{
|
||||||
|
return GTK_WINDOW (window->window);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xtm_process_window_hide (GtkWidget *widget)
|
xtm_process_window_hide (GtkWidget *widget)
|
||||||
{
|
{
|
||||||
@@ -533,24 +548,40 @@ xtm_process_window_get_model (XtmProcessWindow *window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xtm_process_window_set_system_info (XtmProcessWindow *window, guint num_processes, gfloat cpu, gfloat memory, gchar *memory_str, gfloat swap, gchar *swap_str)
|
xtm_process_window_set_system_info (XtmProcessWindow *window, guint num_processes, gfloat cpu, gfloat memory, gchar *memory_str, gfloat swap, gchar *swap_str, guint64 tcp_rx, guint64 tcp_tx, guint64 tcp_error)
|
||||||
{
|
{
|
||||||
gchar text[100];
|
gchar text[200];
|
||||||
gchar value[4];
|
gchar value[4];
|
||||||
|
|
||||||
g_return_if_fail (XTM_IS_PROCESS_WINDOW (window));
|
g_return_if_fail (XTM_IS_PROCESS_WINDOW (window));
|
||||||
g_return_if_fail (GTK_IS_BOX (window->statusbar));
|
g_return_if_fail (GTK_IS_BOX (window->statusbar));
|
||||||
|
|
||||||
g_object_set (window->statusbar, "num-processes", num_processes, "cpu", cpu, "memory", memory_str, "swap", swap_str, NULL);
|
g_object_set (
|
||||||
|
window->statusbar,
|
||||||
|
"num-processes", num_processes,
|
||||||
|
"cpu", cpu,
|
||||||
|
"memory", memory_str,
|
||||||
|
"swap", swap_str,
|
||||||
|
"network-rx", tcp_rx * 1e-5,
|
||||||
|
"network-tx", tcp_tx * 1e-5,
|
||||||
|
"network-error", tcp_error,
|
||||||
|
NULL);
|
||||||
|
|
||||||
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->cpu_monitor), cpu / 100.0f, -1.0);
|
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->cpu_monitor), cpu / 100.0f, 0);
|
||||||
g_snprintf (value, sizeof (value), "%.0f", cpu);
|
g_snprintf (value, sizeof (value), "%.0f", cpu);
|
||||||
g_snprintf (text, sizeof (text), _("CPU: %s%%"), value);
|
g_snprintf (text, sizeof (text), _("CPU: %s%%"), value);
|
||||||
gtk_widget_set_tooltip_text (window->cpu_monitor, text);
|
gtk_widget_set_tooltip_text (window->cpu_monitor, text);
|
||||||
|
|
||||||
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->mem_monitor), memory / 100.0f, swap / 100.0f);
|
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->mem_monitor), memory / 100.0f, 0);
|
||||||
|
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->mem_monitor), swap / 100.0f, 1);
|
||||||
g_snprintf (text, sizeof (text), _("Memory: %s"), memory_str);
|
g_snprintf (text, sizeof (text), _("Memory: %s"), memory_str);
|
||||||
gtk_widget_set_tooltip_text (window->mem_monitor, text);
|
gtk_widget_set_tooltip_text (window->mem_monitor, text);
|
||||||
|
|
||||||
|
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->net_monitor), tcp_rx * 1e-5, 0);
|
||||||
|
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->net_monitor), tcp_tx * 1e-5, 1);
|
||||||
|
xtm_process_monitor_add_peak (XTM_PROCESS_MONITOR (window->net_monitor), tcp_error, 2);
|
||||||
|
g_snprintf (text, sizeof (text), _("Network rx=%0.2f MB/s\nNetwork tx=%0.2f MB/s \nNetwork error=%lu error/s"), tcp_rx * 1e-5, tcp_tx * 1e-5, tcp_error);
|
||||||
|
gtk_widget_set_tooltip_text (window->net_monitor, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ typedef struct _XtmProcessWindow XtmProcessWindow;
|
|||||||
|
|
||||||
GType xtm_process_window_get_type (void);
|
GType xtm_process_window_get_type (void);
|
||||||
GtkWidget *xtm_process_window_new (void);
|
GtkWidget *xtm_process_window_new (void);
|
||||||
|
GtkWindow *xtm_process_window_get (XtmProcessWindow *window);
|
||||||
void xtm_process_window_settings_init (XtmProcessWindow *window, XfconfChannel *channel);
|
void xtm_process_window_settings_init (XtmProcessWindow *window, XfconfChannel *channel);
|
||||||
void xtm_process_window_show (GtkWidget *widget);
|
void xtm_process_window_show (GtkWidget *widget);
|
||||||
GtkTreeModel *xtm_process_window_get_model (XtmProcessWindow *window);
|
GtkTreeModel *xtm_process_window_get_model (XtmProcessWindow *window);
|
||||||
void xtm_process_window_set_system_info (XtmProcessWindow *window, guint num_processes, gfloat cpu, gfloat memory, gchar *memory_str, gfloat swap, gchar *swap_str);
|
void xtm_process_window_set_system_info (XtmProcessWindow *window, guint num_processes, gfloat cpu, gfloat memory, gchar *memory_str, gfloat swap, gchar *swap_str, guint64 tcp_rx, guint64 tcp_tx, guint64 tcp_error);
|
||||||
void xtm_process_window_show_swap_usage (XtmProcessWindow *window, gboolean show_swap_usage);
|
void xtm_process_window_show_swap_usage (XtmProcessWindow *window, gboolean show_swap_usage);
|
||||||
|
|
||||||
#endif /* !PROCESS_WINDOW_H */
|
#endif /* !PROCESS_WINDOW_H */
|
||||||
|
|||||||
@@ -198,6 +198,27 @@
|
|||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="graph-net">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child type="label_item">
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <libxfce4ui/libxfce4ui.h>
|
||||||
|
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "settings-dialog.h"
|
#include "settings-dialog.h"
|
||||||
#include "settings-dialog_ui.h"
|
#include "settings-dialog_ui.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -19,8 +22,6 @@
|
|||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libxfce4ui/libxfce4ui.h>
|
|
||||||
|
|
||||||
static void show_about_dialog (GtkWidget *widget, gpointer user_data);
|
static void show_about_dialog (GtkWidget *widget, gpointer user_data);
|
||||||
static GtkWidget *xtm_settings_dialog_new (GtkBuilder *builder, GtkWidget *parent_window);
|
static GtkWidget *xtm_settings_dialog_new (GtkBuilder *builder, GtkWidget *parent_window);
|
||||||
|
|
||||||
@@ -117,18 +118,22 @@ show_about_dialog (GtkWidget *widget, gpointer user_data)
|
|||||||
"(c) 2005-2008 Johannes Zellner",
|
"(c) 2005-2008 Johannes Zellner",
|
||||||
"",
|
"",
|
||||||
"FreeBSD",
|
"FreeBSD",
|
||||||
|
" \342\200\242 Jehan-Antoine Vayssade",
|
||||||
" \342\200\242 Rozhuk Ivan",
|
" \342\200\242 Rozhuk Ivan",
|
||||||
" \342\200\242 Mike Massonnet",
|
" \342\200\242 Mike Massonnet",
|
||||||
" \342\200\242 Oliver Lehmann",
|
" \342\200\242 Oliver Lehmann",
|
||||||
"",
|
"",
|
||||||
"OpenBSD",
|
"OpenBSD",
|
||||||
|
" \342\200\242 Jehan-Antoine Vayssade",
|
||||||
" \342\200\242 Landry Breuil",
|
" \342\200\242 Landry Breuil",
|
||||||
"",
|
"",
|
||||||
"Linux",
|
"Linux",
|
||||||
|
" \342\200\242 Jehan-Antoine Vayssade",
|
||||||
" \342\200\242 Johannes Zellner",
|
" \342\200\242 Johannes Zellner",
|
||||||
" \342\200\242 Mike Massonnet",
|
" \342\200\242 Mike Massonnet",
|
||||||
"",
|
"",
|
||||||
"OpenSolaris",
|
"OpenSolaris",
|
||||||
|
" \342\200\242 Jehan-Antoine Vayssade",
|
||||||
" \342\200\242 Mike Massonnet",
|
" \342\200\242 Mike Massonnet",
|
||||||
" \342\200\242 Peter Tribble",
|
" \342\200\242 Peter Tribble",
|
||||||
NULL
|
NULL
|
||||||
@@ -174,6 +179,7 @@ xtm_settings_dialog_new (GtkBuilder *builder, GtkWidget *parent_window)
|
|||||||
GtkWidget *dialog;
|
GtkWidget *dialog;
|
||||||
GtkWidget *button;
|
GtkWidget *button;
|
||||||
XtmSettings *settings;
|
XtmSettings *settings;
|
||||||
|
XtmNetworkAnalyzer *network;
|
||||||
|
|
||||||
settings = xtm_settings_get_default ();
|
settings = xtm_settings_get_default ();
|
||||||
dialog = GTK_WIDGET (gtk_builder_get_object (builder, "settings-dialog"));
|
dialog = GTK_WIDGET (gtk_builder_get_object (builder, "settings-dialog"));
|
||||||
@@ -214,8 +220,20 @@ xtm_settings_dialog_new (GtkBuilder *builder, GtkWidget *parent_window)
|
|||||||
builder_bind_toggle_button (builder, "uid", settings, "column-uid");
|
builder_bind_toggle_button (builder, "uid", settings, "column-uid");
|
||||||
builder_bind_toggle_button (builder, "cpu", settings, "column-cpu");
|
builder_bind_toggle_button (builder, "cpu", settings, "column-cpu");
|
||||||
builder_bind_toggle_button (builder, "group-cpu", settings, "column-group-cpu");
|
builder_bind_toggle_button (builder, "group-cpu", settings, "column-group-cpu");
|
||||||
|
builder_bind_toggle_button (builder, "packet-in", settings, "column-packet-in");
|
||||||
|
builder_bind_toggle_button (builder, "packet-out", settings, "column-packet-out");
|
||||||
|
builder_bind_toggle_button (builder, "active-socket", settings, "column-active-socket");
|
||||||
builder_bind_toggle_button (builder, "priority", settings, "column-priority");
|
builder_bind_toggle_button (builder, "priority", settings, "column-priority");
|
||||||
|
|
||||||
|
// insufficient permission
|
||||||
|
network = xtm_network_analyzer_get_default ();
|
||||||
|
|
||||||
|
if (network == NULL)
|
||||||
|
{
|
||||||
|
gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "packet-in")));
|
||||||
|
gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "packet-out")));
|
||||||
|
gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "active-socket")));
|
||||||
|
}
|
||||||
|
|
||||||
button = GTK_WIDGET (gtk_builder_get_object (builder, "button-about"));
|
button = GTK_WIDGET (gtk_builder_get_object (builder, "button-about"));
|
||||||
g_signal_connect (button, "clicked", G_CALLBACK (show_about_dialog), dialog);
|
g_signal_connect (button, "clicked", G_CALLBACK (show_about_dialog), dialog);
|
||||||
|
|||||||
@@ -508,6 +508,48 @@
|
|||||||
<property name="position">10</property>
|
<property name="position">10</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="packet-in">
|
||||||
|
<property name="label" translatable="yes">Packet in</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">10</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="packet-out">
|
||||||
|
<property name="label" translatable="yes">Packet out</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">10</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="active-socket">
|
||||||
|
<property name="label" translatable="yes">Active Socket</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">10</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ enum
|
|||||||
PROP_COLUMN_CPU,
|
PROP_COLUMN_CPU,
|
||||||
PROP_COLUMN_GROUP_CPU,
|
PROP_COLUMN_GROUP_CPU,
|
||||||
PROP_COLUMN_PRIORITY,
|
PROP_COLUMN_PRIORITY,
|
||||||
|
PROP_COLUMN_PACKET_IN,
|
||||||
|
PROP_COLUMN_PACKET_OUT,
|
||||||
|
PROP_COLUMN_ACTIVE_SOCKET,
|
||||||
PROP_SORT_COLUMN_ID,
|
PROP_SORT_COLUMN_ID,
|
||||||
PROP_SORT_TYPE,
|
PROP_SORT_TYPE,
|
||||||
PROP_HANDLE_POSITION,
|
PROP_HANDLE_POSITION,
|
||||||
@@ -116,6 +119,14 @@ xtm_settings_class_init (XtmSettingsClass *klass)
|
|||||||
g_param_spec_boolean ("column-cpu", "ColumnCPU", "Show column CPU", TRUE, G_PARAM_READWRITE));
|
g_param_spec_boolean ("column-cpu", "ColumnCPU", "Show column CPU", TRUE, G_PARAM_READWRITE));
|
||||||
g_object_class_install_property (class, PROP_COLUMN_GROUP_CPU,
|
g_object_class_install_property (class, PROP_COLUMN_GROUP_CPU,
|
||||||
g_param_spec_boolean ("column-group-cpu", "ColumnGroupCPU", "Show column Group CPU", TRUE, G_PARAM_READWRITE));
|
g_param_spec_boolean ("column-group-cpu", "ColumnGroupCPU", "Show column Group CPU", TRUE, G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
g_object_class_install_property (class, PROP_COLUMN_PACKET_IN,
|
||||||
|
g_param_spec_boolean ("column-packet-in", "ColumnPacketIn", "Show column packet in", TRUE, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (class, PROP_COLUMN_PACKET_OUT,
|
||||||
|
g_param_spec_boolean ("column-packet-out", "ColumnPacketOut", "Show column packet out", TRUE, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (class, PROP_COLUMN_PACKET_OUT,
|
||||||
|
g_param_spec_boolean ("column-active-socket", "ColumnActiveSocket", "Show number of used socket descriptor", TRUE, G_PARAM_READWRITE));
|
||||||
|
|
||||||
g_object_class_install_property (class, PROP_COLUMN_PRIORITY,
|
g_object_class_install_property (class, PROP_COLUMN_PRIORITY,
|
||||||
g_param_spec_boolean ("column-priority", "ColumnPriority", "Show column priority", FALSE, G_PARAM_READWRITE));
|
g_param_spec_boolean ("column-priority", "ColumnPriority", "Show column priority", FALSE, G_PARAM_READWRITE));
|
||||||
g_object_class_install_property (class, PROP_SORT_COLUMN_ID,
|
g_object_class_install_property (class, PROP_SORT_COLUMN_ID,
|
||||||
@@ -219,6 +230,15 @@ xtm_settings_bind_xfconf (XtmSettings *settings, XfconfChannel *channel)
|
|||||||
G_OBJECT (settings), "column-cpu");
|
G_OBJECT (settings), "column-cpu");
|
||||||
xfconf_g_property_bind (channel, SETTING_COLUMN_GROUP_CPU, G_TYPE_BOOLEAN,
|
xfconf_g_property_bind (channel, SETTING_COLUMN_GROUP_CPU, G_TYPE_BOOLEAN,
|
||||||
G_OBJECT (settings), "column-group-cpu");
|
G_OBJECT (settings), "column-group-cpu");
|
||||||
|
|
||||||
|
|
||||||
|
xfconf_g_property_bind (channel, SETTING_COLUMN_PACKET_IN, G_TYPE_BOOLEAN,
|
||||||
|
G_OBJECT (settings), "column-packet-in");
|
||||||
|
xfconf_g_property_bind (channel, SETTING_COLUMN_PACKET_OUT, G_TYPE_BOOLEAN,
|
||||||
|
G_OBJECT (settings), "column-packet-out");
|
||||||
|
xfconf_g_property_bind (channel, SETTING_COLUMN_ACTIVE_SOCKET, G_TYPE_BOOLEAN,
|
||||||
|
G_OBJECT (settings), "column-active-socket");
|
||||||
|
|
||||||
xfconf_g_property_bind (channel, SETTING_COLUMN_PRIORITY, G_TYPE_BOOLEAN,
|
xfconf_g_property_bind (channel, SETTING_COLUMN_PRIORITY, G_TYPE_BOOLEAN,
|
||||||
G_OBJECT (settings), "column-priority");
|
G_OBJECT (settings), "column-priority");
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
#define SETTING_COLUMN_UID "/columns/column-uid"
|
#define SETTING_COLUMN_UID "/columns/column-uid"
|
||||||
#define SETTING_COLUMN_CPU "/columns/column-cpu"
|
#define SETTING_COLUMN_CPU "/columns/column-cpu"
|
||||||
#define SETTING_COLUMN_GROUP_CPU "/columns/column-group-cpu"
|
#define SETTING_COLUMN_GROUP_CPU "/columns/column-group-cpu"
|
||||||
|
#define SETTING_COLUMN_PACKET_IN "/columns/column-packet-in"
|
||||||
|
#define SETTING_COLUMN_PACKET_OUT "/columns/column-packet-out"
|
||||||
|
#define SETTING_COLUMN_ACTIVE_SOCKET "/columns/column-active-socket"
|
||||||
#define SETTING_COLUMN_PRIORITY "/columns/column-priority"
|
#define SETTING_COLUMN_PRIORITY "/columns/column-priority"
|
||||||
#define SETTING_COLUMN_SORT_ID "/columns/sort-id"
|
#define SETTING_COLUMN_SORT_ID "/columns/sort-id"
|
||||||
#define SETTING_COLUMN_SORT_TYPE "/columns/sort-type"
|
#define SETTING_COLUMN_SORT_TYPE "/columns/sort-type"
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "inode-to-sock.h"
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "task-manager.h"
|
#include "task-manager.h"
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
@@ -40,14 +42,413 @@
|
|||||||
/* for struct vmtotal */
|
/* for struct vmtotal */
|
||||||
#include <sys/vmmeter.h>
|
#include <sys/vmmeter.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
/* errno */
|
/* errno */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
extern int errno;
|
extern int errno;
|
||||||
|
#else
|
||||||
|
// struct file in NetBSD
|
||||||
|
// ugly ! where is defined this ?
|
||||||
|
// plateform dependent
|
||||||
|
typedef long register_t;
|
||||||
|
typedef unsigned long paddr_t;
|
||||||
|
#include <kvm.h>
|
||||||
|
#include <machine/types.h>
|
||||||
|
#include <sys/domain.h>
|
||||||
|
#include <sys/filedesc.h>
|
||||||
|
#include <sys/protosw.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/unpcb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _KERNEL
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#undef _KERNEL
|
||||||
|
|
||||||
char *state_abbrev[] = {
|
char *state_abbrev[] = {
|
||||||
"", "start", "run", "sleep", "stop", "zomb", "dead", "onproc"
|
"", "start", "run", "sleep", "stop", "zomb", "dead", "onproc"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static XtmInodeToSock *inode_to_sock = NULL;
|
||||||
|
static XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
|
||||||
|
gboolean get_if_count (int *data);
|
||||||
|
gboolean get_network_usage_if (int interface, guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error);
|
||||||
|
struct kinfo_file *get_process_fds (int *nfiles, int kern, int arg);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
void list_process_fds (Task *task, struct kinfo_proc *kp);
|
||||||
|
#else
|
||||||
|
void list_process_fds (Task *task, struct kinfo_proc2 *kp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
void
|
||||||
|
packet_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
|
||||||
|
{
|
||||||
|
// Extract source and destination IP addresses and ports from the packet
|
||||||
|
struct ether_header eth_header;
|
||||||
|
struct ip ip_header;
|
||||||
|
struct tcphdr tcp_header;
|
||||||
|
XtmNetworkAnalyzer *iface;
|
||||||
|
long int src_port, dst_port;
|
||||||
|
char local_mac[18];
|
||||||
|
char src_mac[18];
|
||||||
|
char dst_mac[18];
|
||||||
|
|
||||||
|
memcpy (ð_header, packet, sizeof (struct ether_header));
|
||||||
|
memcpy (&ip_header, packet + sizeof (struct ether_header), sizeof (struct ip));
|
||||||
|
memcpy (&tcp_header, packet + sizeof (struct ether_header) + sizeof (struct ip), sizeof (struct ip));
|
||||||
|
|
||||||
|
// cast -> increases required alignment from 1 to 2 [-Wcast-align]
|
||||||
|
// const struct ether_header *eth_header = (const struct ether_header *)packet;
|
||||||
|
// struct ip *ip_header = (struct ip *)(packet + sizeof (struct ether_header));
|
||||||
|
// struct tcphdr *tcp_header = (struct tcphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip));
|
||||||
|
// printf("%d, %d \n", eth_heade.ether_type , ip_header.ip_p);
|
||||||
|
|
||||||
|
// Dropped non-ip packet
|
||||||
|
if (eth_header.ether_type != 8 || ip_header.ip_p != 6)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface = (XtmNetworkAnalyzer *)args;
|
||||||
|
|
||||||
|
src_port = ntohs (tcp_header.th_sport);
|
||||||
|
dst_port = ntohs (tcp_header.th_dport);
|
||||||
|
|
||||||
|
// directly use strcmp on analyzer->mac, eth_header->ether_shost doesnt work
|
||||||
|
|
||||||
|
snprintf (local_mac, sizeof (local_mac),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
iface->mac[0], iface->mac[1],
|
||||||
|
iface->mac[2], iface->mac[3],
|
||||||
|
iface->mac[4], iface->mac[5]);
|
||||||
|
|
||||||
|
snprintf (src_mac, sizeof (local_mac),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header.ether_shost[0], eth_header.ether_shost[1],
|
||||||
|
eth_header.ether_shost[2], eth_header.ether_shost[3],
|
||||||
|
eth_header.ether_shost[4], eth_header.ether_shost[5]);
|
||||||
|
|
||||||
|
snprintf (dst_mac, sizeof (local_mac),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header.ether_dhost[0], eth_header.ether_dhost[1],
|
||||||
|
eth_header.ether_dhost[2], eth_header.ether_dhost[3],
|
||||||
|
eth_header.ether_dhost[4], eth_header.ether_dhost[5]);
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
// pthread_mutex_lock(&iface->lock);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, src_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "in ", iface->packetin, src_port);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, dst_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "out", iface->packetout, dst_port);
|
||||||
|
|
||||||
|
// pthread_mutex_unlock(&iface->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_network_usage (guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
// can also be get trough tcpstat struct
|
||||||
|
// int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS }
|
||||||
|
// sysctl(mib, sizeof(mib) / sizeof(mib[0]), %tcpstat, &len, NULL, 0)
|
||||||
|
// repeat for IPPROTO_UDP or use IPPROTO_ETHERIP
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
|
||||||
|
*tcp_error = 0;
|
||||||
|
*tcp_rx = 0;
|
||||||
|
*tcp_tx = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (getifaddrs (&ifaddr) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (ifa->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the interface is a network interface (AF_PACKET for Linux)
|
||||||
|
if (ifa->ifa_addr->sa_family == AF_LINK)
|
||||||
|
{
|
||||||
|
struct if_data *ifdata = (struct if_data *)ifa->ifa_data;
|
||||||
|
// Check if the interface has a hardware address (MAC address)
|
||||||
|
if (ifdata != NULL)
|
||||||
|
{
|
||||||
|
*tcp_error += ifdata->ifi_oerrors + ifdata->ifi_ierrors;
|
||||||
|
;
|
||||||
|
*tcp_rx += ifdata->ifi_ibytes;
|
||||||
|
*tcp_tx += ifdata->ifi_obytes;
|
||||||
|
}
|
||||||
|
// printf("%d, %d \n", *tcp_rx, *tcp_tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_mac_address (const char *device, uint8_t mac[6])
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
|
||||||
|
if (getifaddrs (&ifaddr) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (ifa->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the interface is a network interface (AF_PACKET for Linux)
|
||||||
|
if (ifa->ifa_addr->sa_family == AF_LINK && strcmp (device, ifa->ifa_name) == 0)
|
||||||
|
{
|
||||||
|
// Check if the interface has a hardware address (MAC address)
|
||||||
|
if (ifa->ifa_data != NULL)
|
||||||
|
{
|
||||||
|
// warning: cast from 'struct sockaddr *' to 'struct sockaddr_dl *' increases required alignment from 1 to 2
|
||||||
|
// struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||||
|
struct sockaddr_dl sdl;
|
||||||
|
memcpy (&sdl, ifa->ifa_addr, sizeof (struct sockaddr_dl));
|
||||||
|
memcpy (mac, sdl.sdl_data + sdl.sdl_nlen, sizeof (uint8_t) * 6);
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct kinfo_file *
|
||||||
|
get_process_fds (int *nfiles, int kern, int arg)
|
||||||
|
{
|
||||||
|
// inspired by NetBSD pstat.c
|
||||||
|
int mib[6];
|
||||||
|
size_t len;
|
||||||
|
struct kinfo_file *kf;
|
||||||
|
|
||||||
|
// Set the MIB (Management Information Base) for the sysctl call
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
mib[1] = KERN_FILE;
|
||||||
|
#else
|
||||||
|
mib[1] = KERN_FILE2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mib[2] = kern;
|
||||||
|
mib[3] = arg;
|
||||||
|
mib[4] = sizeof (struct kinfo_file);
|
||||||
|
mib[5] = 0;
|
||||||
|
|
||||||
|
// Get the number of open files
|
||||||
|
if (sysctl (mib, 6, NULL, &len, NULL, 0) < 0)
|
||||||
|
{
|
||||||
|
printf ("sysctl Get the number of opened fd");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nfiles = len / sizeof (struct kinfo_file);
|
||||||
|
|
||||||
|
// Allocate memory for the kinfo_file structures
|
||||||
|
kf = malloc (len);
|
||||||
|
if (kf == NULL)
|
||||||
|
{
|
||||||
|
printf ("malloc");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mib[5] = len / sizeof (struct kinfo_file);
|
||||||
|
|
||||||
|
// Get the list of open files
|
||||||
|
if (sysctl (mib, 6, kf, &len, NULL, 0) < 0)
|
||||||
|
{
|
||||||
|
printf ("sysctl, enable to get kinfo_file *");
|
||||||
|
free (kf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_refresh_inode_to_sock (XtmInodeToSock *its)
|
||||||
|
{
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
// unneeded
|
||||||
|
#else
|
||||||
|
// unneeded
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
list_process_fds (Task *task, struct kinfo_proc *kp)
|
||||||
|
#else
|
||||||
|
list_process_fds (Task *task, struct kinfo_proc2 *kp)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
// inspired by openbsd netstat/inet.c
|
||||||
|
// inspired by openbsd fstat/fstat.c
|
||||||
|
|
||||||
|
long int nfiles, port;
|
||||||
|
XtmNetworkAnalyzer *current;
|
||||||
|
struct kinfo_file *kf = get_process_fds (&nfiles, KERN_FILE_BYPID, task->pid);
|
||||||
|
|
||||||
|
if (kf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Parse the kinfo_file structures
|
||||||
|
for (int i = 0; i < nfiles; i++)
|
||||||
|
{
|
||||||
|
if (kf[i].f_type == DTYPE_SOCKET)
|
||||||
|
{
|
||||||
|
// interesting properties
|
||||||
|
// task->packet_in += kf[i].f_rxfer;
|
||||||
|
// task->packet_in += kf[i].f_rbytes;
|
||||||
|
// task->packet_out += kf[i].f_rwfer;
|
||||||
|
// task->packet_out += kf[i].f_wbytes;netstat
|
||||||
|
|
||||||
|
current = analyzer;
|
||||||
|
while (current != NULL)
|
||||||
|
{
|
||||||
|
port = ntohs (kf[i].inp_lport);
|
||||||
|
task->packet_in += (guint64)g_hash_table_lookup (current->packetin, &port);
|
||||||
|
task->packet_out += (guint64)g_hash_table_lookup (current->packetout, &port);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
task->active_socket += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free (kf);
|
||||||
|
#else
|
||||||
|
// inspired by netbsd fstat/fstat.c
|
||||||
|
XtmNetworkAnalyzer *current;
|
||||||
|
char *memf, *nlistf;
|
||||||
|
char buf[_POSIX2_LINE_MAX];
|
||||||
|
kvm_t *kd;
|
||||||
|
struct filedesc filed;
|
||||||
|
struct fdtab dt;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
fdfile_t **ofiles;
|
||||||
|
fdfile_t *fp;
|
||||||
|
struct socket *sock;
|
||||||
|
struct socket so;
|
||||||
|
struct file file;
|
||||||
|
fdfile_t fdfile;
|
||||||
|
struct protosw proto;
|
||||||
|
struct domain dom;
|
||||||
|
struct in4pcb in4pcb;
|
||||||
|
struct in6pcb in6pcb;
|
||||||
|
struct inpcb *inp;
|
||||||
|
long int port;
|
||||||
|
|
||||||
|
nlistf = memf = NULL;
|
||||||
|
kd = kvm_openfiles (nlistf, memf, NULL, O_RDONLY, buf);
|
||||||
|
|
||||||
|
kvm_read (kd, kp->p_fd, &filed, sizeof (filed));
|
||||||
|
kvm_read (kd, (u_long)filed.fd_dt, &dt, sizeof (dt));
|
||||||
|
|
||||||
|
len = (filed.fd_lastfile + 1) * sizeof (fdfile_t *);
|
||||||
|
ofiles = malloc (len);
|
||||||
|
kvm_read (kd, (u_long)&filed.fd_dt->dt_ff, ofiles, (filed.fd_lastfile + 1) * (sizeof (fdfile_t *)));
|
||||||
|
|
||||||
|
for (int i = 0; i <= filed.fd_lastfile; i++)
|
||||||
|
{
|
||||||
|
if (ofiles[i] == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fp = ofiles[i];
|
||||||
|
|
||||||
|
kvm_read (kd, (u_long)fp, &fdfile, sizeof (fdfile));
|
||||||
|
|
||||||
|
if (fdfile.ff_file == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
kvm_read (kd, (u_long)fdfile.ff_file, &file, sizeof (file));
|
||||||
|
|
||||||
|
if (file.f_type != DTYPE_SOCKET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sock = (struct socket *)file.f_data;
|
||||||
|
kvm_read (kd, (u_long)sock, &so, sizeof (struct socket));
|
||||||
|
kvm_read (kd, (u_long)so.so_proto, &proto, sizeof (struct protosw));
|
||||||
|
kvm_read (kd, (u_long)proto.pr_domain, &dom, sizeof (struct domain));
|
||||||
|
|
||||||
|
port = 0;
|
||||||
|
|
||||||
|
if (dom.dom_family == AF_INET)
|
||||||
|
{
|
||||||
|
if (proto.pr_protocol == IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
if (so.so_pcb == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
kvm_read (kd, (u_long)so.so_pcb, (char *)&in4pcb, sizeof (in4pcb));
|
||||||
|
inp = (struct inpcb *)&in4pcb;
|
||||||
|
port = ntohs (inp->inp_lport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dom.dom_family == AF_INET6)
|
||||||
|
{
|
||||||
|
if (proto.pr_protocol == IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
if (so.so_pcb == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
kvm_read (kd, (u_long)so.so_pcb, (char *)&in6pcb, sizeof (in6pcb));
|
||||||
|
inp = (struct inpcb *)&in6pcb;
|
||||||
|
port = ntohs (inp->inp_lport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
task->active_socket += 1;
|
||||||
|
|
||||||
|
current = analyzer;
|
||||||
|
if (current != NULL)
|
||||||
|
{
|
||||||
|
task->packet_in += (guint64)g_hash_table_lookup (current->packetin, &port);
|
||||||
|
task->packet_out += (guint64)g_hash_table_lookup (current->packetout, &port);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kvm_close (kd);
|
||||||
|
free (ofiles);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
get_task_list (GArray *task_list)
|
get_task_list (GArray *task_list)
|
||||||
{
|
{
|
||||||
@@ -57,11 +458,22 @@ get_task_list (GArray *task_list)
|
|||||||
struct kinfo_proc *kp;
|
struct kinfo_proc *kp;
|
||||||
#else
|
#else
|
||||||
struct kinfo_proc2 *kp;
|
struct kinfo_proc2 *kp;
|
||||||
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
|
kvm_t *kdp;
|
||||||
#endif
|
#endif
|
||||||
Task t;
|
Task t;
|
||||||
char **args;
|
char **args;
|
||||||
gchar *buf;
|
|
||||||
int nproc, i;
|
int nproc, i;
|
||||||
|
gchar *buf;
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
#else
|
||||||
|
kdp = kvm_open (NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
analyzer = xtm_network_analyzer_get_default ();
|
||||||
|
inode_to_sock = xtm_inode_to_sock_get_default ();
|
||||||
|
xtm_refresh_inode_to_sock (inode_to_sock);
|
||||||
|
|
||||||
mib[0] = CTL_KERN;
|
mib[0] = CTL_KERN;
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
@@ -116,6 +528,8 @@ get_task_list (GArray *task_list)
|
|||||||
t.rss = p.p_vm_rssize * getpagesize ();
|
t.rss = p.p_vm_rssize * getpagesize ();
|
||||||
g_snprintf (t.state, sizeof t.state, "%s", state_abbrev[p.p_stat]);
|
g_snprintf (t.state, sizeof t.state, "%s", state_abbrev[p.p_stat]);
|
||||||
g_strlcpy (t.name, p.p_comm, strlen (p.p_comm) + 1);
|
g_strlcpy (t.name, p.p_comm, strlen (p.p_comm) + 1);
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
/* shamelessly stolen from top/machine.c */
|
/* shamelessly stolen from top/machine.c */
|
||||||
if (!P_ZOMBIE (&p))
|
if (!P_ZOMBIE (&p))
|
||||||
{
|
{
|
||||||
@@ -132,8 +546,10 @@ get_task_list (GArray *task_list)
|
|||||||
mib[1] = KERN_PROC_ARGS;
|
mib[1] = KERN_PROC_ARGS;
|
||||||
mib[2] = t.pid;
|
mib[2] = t.pid;
|
||||||
mib[3] = KERN_PROC_ARGV;
|
mib[3] = KERN_PROC_ARGV;
|
||||||
|
|
||||||
if (sysctl (mib, 4, args, &size, NULL, 0) == 0)
|
if (sysctl (mib, 4, args, &size, NULL, 0) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (errno != ENOMEM)
|
if (errno != ENOMEM)
|
||||||
{ /* ESRCH: process disappeared */
|
{ /* ESRCH: process disappeared */
|
||||||
/* printf ("process with pid %d disappeared, errno=%d\n", t.pid, errno); */
|
/* printf ("process with pid %d disappeared, errno=%d\n", t.pid, errno); */
|
||||||
@@ -142,15 +558,40 @@ get_task_list (GArray *task_list)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = g_strjoinv (" ", args);
|
buf = g_strjoinv (" ", args);
|
||||||
g_assert (g_utf8_validate (buf, -1, NULL));
|
g_assert (g_utf8_validate (buf, -1, NULL));
|
||||||
g_strlcpy (t.cmdline, buf, sizeof t.cmdline);
|
g_strlcpy (t.cmdline, buf, sizeof t.cmdline);
|
||||||
g_free (buf);
|
g_free (buf);
|
||||||
free (args);
|
free (args);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// assuming NetBSD 10.0
|
||||||
|
// https://github.com/NetBSD/src/blob/trunk/lib/libkvm/kvm_proc.c#L1116
|
||||||
|
// https://github.com/NetBSD/pkgsrc/blob/trunk/sysutils/xfce4-taskmanager/files/task-manager-netbsd.c
|
||||||
|
// fixing code used in __OpenBSD__ crash at g_strjoinv due to strlen
|
||||||
|
|
||||||
|
if (!(kp[i].p_stat == SDEAD))
|
||||||
|
{
|
||||||
|
args = kvm_getargv2 (kdp, &kp[i], BUFSIZ);
|
||||||
|
if (args != NULL)
|
||||||
|
{
|
||||||
|
buf = g_strjoinv (" ", args);
|
||||||
|
g_strlcpy (t.cmdline, buf, sizeof (t.cmdline));
|
||||||
|
g_free (buf);
|
||||||
|
// Memory seem stable without that
|
||||||
|
// otherwise i get a segfault
|
||||||
|
// free (args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
t.cpu_user = (100.0f * ((gfloat)p.p_pctcpu / FSCALE));
|
t.cpu_user = (100.0f * ((gfloat)p.p_pctcpu / FSCALE));
|
||||||
t.cpu_system = 0.0f; /* TODO ? */
|
t.cpu_system = 0.0f; /* TODO ? */
|
||||||
|
|
||||||
|
if (analyzer != NULL)
|
||||||
|
list_process_fds (&t, &p);
|
||||||
|
|
||||||
g_array_append_val (task_list, t);
|
g_array_append_val (task_list, t);
|
||||||
}
|
}
|
||||||
free (kp);
|
free (kp);
|
||||||
@@ -201,7 +642,15 @@ get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system)
|
|||||||
static gulong cur_user = 0, cur_system = 0, cur_total = 0;
|
static gulong cur_user = 0, cur_system = 0, cur_total = 0;
|
||||||
static gulong old_user = 0, old_system = 0, old_total = 0;
|
static gulong old_user = 0, old_system = 0, old_total = 0;
|
||||||
|
|
||||||
|
#ifdef KERN_CPTIME
|
||||||
int mib[] = { CTL_KERN, KERN_CPTIME };
|
int mib[] = { CTL_KERN, KERN_CPTIME };
|
||||||
|
#elif defined KERN_CPTIME2
|
||||||
|
int mib[] = { CTL_KERN, KERN_CPTIME2 };
|
||||||
|
#else
|
||||||
|
// NetBSD 10.0
|
||||||
|
int mib[] = { CTL_KERN, KERN_CP_TIME };
|
||||||
|
#endif
|
||||||
|
|
||||||
glong cp_time[CPUSTATES];
|
glong cp_time[CPUSTATES];
|
||||||
gsize size = sizeof (cp_time);
|
gsize size = sizeof (cp_time);
|
||||||
if (sysctl (mib, 2, &cp_time, &size, NULL, 0) < 0)
|
if (sysctl (mib, 2, &cp_time, &size, NULL, 0) < 0)
|
||||||
|
|||||||
@@ -15,21 +15,40 @@
|
|||||||
|
|
||||||
#include "task-manager.h"
|
#include "task-manager.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <kvm.h>
|
#include <kvm.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 900044
|
#if defined(__FreeBSD_version) && __FreeBSD_version >= 900044
|
||||||
#include <sys/vmmeter.h>
|
#include <sys/vmmeter.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <net/if_mib.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "inode-to-sock.h"
|
||||||
|
#include "network-analyzer.h"
|
||||||
|
#include "task-manager.h"
|
||||||
|
|
||||||
static const gchar ki_stat2state[] = {
|
static const gchar ki_stat2state[] = {
|
||||||
' ', /* - */
|
' ', /* - */
|
||||||
'R', /* SIDL */
|
'R', /* SIDL */
|
||||||
@@ -41,6 +60,152 @@ static const gchar ki_stat2state[] = {
|
|||||||
'L' /* SLOCK */
|
'L' /* SLOCK */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static XtmInodeToSock *inode_to_sock = NULL;
|
||||||
|
static XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
|
||||||
|
void list_process_fds (Task *task);
|
||||||
|
gboolean get_if_count (int *data);
|
||||||
|
gboolean get_network_usage_if (int interface, guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
void
|
||||||
|
packet_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
|
||||||
|
{
|
||||||
|
// Extract source and destination IP addresses and ports from the packet
|
||||||
|
struct ether_header *eth_header = (struct ether_header *)packet;
|
||||||
|
struct ip *ip_header = (struct ip *)(packet + sizeof (struct ether_header));
|
||||||
|
struct tcphdr *tcp_header = (struct tcphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip));
|
||||||
|
XtmNetworkAnalyzer *iface = (XtmNetworkAnalyzer *)args;
|
||||||
|
|
||||||
|
// Dropped non-ip packet
|
||||||
|
if (eth_header->ether_type != 8 || ip_header->ip_p != 6)
|
||||||
|
return;
|
||||||
|
|
||||||
|
long int src_port = ntohs (tcp_header->th_sport);
|
||||||
|
long int dst_port = ntohs (tcp_header->th_dport);
|
||||||
|
|
||||||
|
// directly use strcmp on analyzer->mac, eth_header->ether_shost doesnt work
|
||||||
|
|
||||||
|
char local_mac[18];
|
||||||
|
char src_mac[18];
|
||||||
|
char dst_mac[18];
|
||||||
|
|
||||||
|
sprintf (local_mac,
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
iface->mac[0], iface->mac[1],
|
||||||
|
iface->mac[2], iface->mac[3],
|
||||||
|
iface->mac[4], iface->mac[5]);
|
||||||
|
|
||||||
|
sprintf (src_mac,
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header->ether_shost[0], eth_header->ether_shost[1],
|
||||||
|
eth_header->ether_shost[2], eth_header->ether_shost[3],
|
||||||
|
eth_header->ether_shost[4], eth_header->ether_shost[5]);
|
||||||
|
|
||||||
|
sprintf (dst_mac,
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header->ether_dhost[0], eth_header->ether_dhost[1],
|
||||||
|
eth_header->ether_dhost[2], eth_header->ether_dhost[3],
|
||||||
|
eth_header->ether_dhost[4], eth_header->ether_dhost[5]);
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
// pthread_mutex_lock(&iface->lock);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, src_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "in ", iface->packetin, src_port);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, dst_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "out", iface->packetout, dst_port);
|
||||||
|
|
||||||
|
// pthread_mutex_unlock(&iface->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_if_count (int *data)
|
||||||
|
{
|
||||||
|
size_t len = sizeof (*data);
|
||||||
|
|
||||||
|
static int32_t name[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT };
|
||||||
|
name[0] = CTL_NET;
|
||||||
|
name[1] = PF_LINK;
|
||||||
|
name[2] = NETLINK_GENERIC;
|
||||||
|
name[3] = IFMIB_SYSTEM;
|
||||||
|
name[4] = IFMIB_IFCOUNT;
|
||||||
|
|
||||||
|
return sysctl (name, 5, data, &len, 0, 0) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_network_usage_if (int interface, guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
struct ifmibdata data;
|
||||||
|
size_t len = sizeof (data);
|
||||||
|
|
||||||
|
static int32_t name[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, 0, IFDATA_GENERAL };
|
||||||
|
name[4] = interface;
|
||||||
|
|
||||||
|
if (sysctl (name, 6, &data, &len, 0, 0) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
//*tcp_error = data.ifmd_data.ifi_oerrors + data.ifmd_data.ifi_ierrors;
|
||||||
|
*tcp_rx += data.ifmd_data.ifi_ibytes;
|
||||||
|
*tcp_tx += data.ifmd_data.ifi_obytes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_network_usage (guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
int ifcount = 0;
|
||||||
|
|
||||||
|
if (get_if_count (&ifcount))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
*tcp_error = 0;
|
||||||
|
*tcp_rx = 0;
|
||||||
|
*tcp_tx = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < ifcount; ++i)
|
||||||
|
get_network_usage_if (i, tcp_rx, tcp_tx, tcp_error);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_mac_address (const char *device, uint8_t mac[6])
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
|
||||||
|
if (getifaddrs (&ifaddr) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (ifa->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int family = ifa->ifa_addr->sa_family;
|
||||||
|
|
||||||
|
// Check if the interface is a network interface (AF_PACKET for Linux)
|
||||||
|
if (family == AF_LINK && strcmp (device, ifa->ifa_name) == 0)
|
||||||
|
{
|
||||||
|
// Check if the interface has a hardware address (MAC address)
|
||||||
|
if (ifa->ifa_data != NULL)
|
||||||
|
{
|
||||||
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||||
|
memcpy (mac, sdl->sdl_data + sdl->sdl_nlen, sizeof (uint8_t) * 6);
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static guint64
|
static guint64
|
||||||
get_mem_by_bytes (const gchar *name)
|
get_mem_by_bytes (const gchar *name)
|
||||||
@@ -132,6 +297,114 @@ get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO check the OpenBSD version here
|
||||||
|
// (struct sockaddr_in*)kinfo_file.kf_sa_local
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_refresh_inode_to_sock (XtmInodeToSock *its)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char line[2048];
|
||||||
|
char *token;
|
||||||
|
char *delim = " ";
|
||||||
|
|
||||||
|
if (analyzer == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Execute the sockstat command and get the output
|
||||||
|
fp = popen ("sockstat -L -P tcp,udp", "r");
|
||||||
|
if (fp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_hash_table_remove_all (its->hash);
|
||||||
|
g_hash_table_remove_all (its->pid);
|
||||||
|
|
||||||
|
// Skip the header line
|
||||||
|
fgets (line, 2048, fp);
|
||||||
|
|
||||||
|
// Parse the output line by line
|
||||||
|
while (fgets (line, 2048, fp) != NULL)
|
||||||
|
{
|
||||||
|
// Remove the newline character
|
||||||
|
line[strcspn (line, "\n")] = '\0';
|
||||||
|
|
||||||
|
// Split the line into tokens
|
||||||
|
token = strtok (line, delim);
|
||||||
|
|
||||||
|
// Parse the columns
|
||||||
|
char user[50];
|
||||||
|
char command[50];
|
||||||
|
char pid[10];
|
||||||
|
char fd[10];
|
||||||
|
char proto[10];
|
||||||
|
char local_address[50];
|
||||||
|
char foreign_address[50];
|
||||||
|
|
||||||
|
strcpy (user, token);
|
||||||
|
token = strtok (NULL, delim);
|
||||||
|
strcpy (command, token);
|
||||||
|
token = strtok (NULL, delim);
|
||||||
|
strcpy (pid, token);
|
||||||
|
token = strtok (NULL, delim);
|
||||||
|
strcpy (fd, token);
|
||||||
|
token = strtok (NULL, delim);
|
||||||
|
strcpy (proto, token);
|
||||||
|
token = strtok (NULL, delim);
|
||||||
|
strcpy (local_address, token);
|
||||||
|
token = strtok (NULL, delim);
|
||||||
|
strcpy (foreign_address, token);
|
||||||
|
|
||||||
|
long int local_port, assos;
|
||||||
|
gint64 *inode1 = g_new0 (gint64, 1);
|
||||||
|
gint64 *inode2 = g_new0 (gint64, 1);
|
||||||
|
|
||||||
|
*inode1 = atoi (fd);
|
||||||
|
*inode2 = atoi (fd);
|
||||||
|
assos = atoi (pid);
|
||||||
|
|
||||||
|
sscanf (local_address, "%*[^:]:%d", &local_port);
|
||||||
|
// (intptr_t) -> cast to pointer from integer of different size [-Wint-to-pointer-cast]
|
||||||
|
g_hash_table_replace (its->hash, inode1, (gpointer)(intptr_t)local_port);
|
||||||
|
g_hash_table_replace (its->pid, inode2, (gpointer)(intptr_t)assos);
|
||||||
|
|
||||||
|
// Print the parsed values
|
||||||
|
// printf("%d -> %d\n", *inode, local_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the pipe
|
||||||
|
pclose (fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
list_process_fds (Task *task)
|
||||||
|
{
|
||||||
|
XtmNetworkAnalyzer *current;
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
gint64 key_int, value_int;
|
||||||
|
long int port;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, inode_to_sock->pid);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
key_int = *(gint64 *)(key);
|
||||||
|
value_int = GPOINTER_TO_INT (value);
|
||||||
|
if (task->pid == value_int)
|
||||||
|
{
|
||||||
|
port = (long int)g_hash_table_lookup (inode_to_sock->hash, &key_int);
|
||||||
|
task->active_socket += 1;
|
||||||
|
|
||||||
|
current = analyzer;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
task->packet_in += (guint64)g_hash_table_lookup (current->packetin, &port);
|
||||||
|
task->packet_out += (guint64)g_hash_table_lookup (current->packetout, &port);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
get_task_details (struct kinfo_proc *kp, Task *task)
|
get_task_details (struct kinfo_proc *kp, Task *task)
|
||||||
{
|
{
|
||||||
@@ -233,17 +506,25 @@ get_task_details (struct kinfo_proc *kp, Task *task)
|
|||||||
if (kp->ki_flag & P_JAILED)
|
if (kp->ki_flag & P_JAILED)
|
||||||
task->state[i++] = 'J';
|
task->state[i++] = 'J';
|
||||||
|
|
||||||
|
if (analyzer != NULL)
|
||||||
|
list_process_fds (task);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
get_task_list (GArray *task_list)
|
get_task_list (GArray *task_list)
|
||||||
{
|
{
|
||||||
|
analyzer = xtm_network_analyzer_get_default ();
|
||||||
|
|
||||||
kvm_t *kd;
|
kvm_t *kd;
|
||||||
struct kinfo_proc *kp;
|
struct kinfo_proc *kp;
|
||||||
int cnt = 0, i;
|
int cnt = 0, i;
|
||||||
Task task;
|
Task task;
|
||||||
|
|
||||||
|
inode_to_sock = xtm_inode_to_sock_get_default ();
|
||||||
|
xtm_refresh_inode_to_sock (inode_to_sock);
|
||||||
|
|
||||||
if ((kd = kvm_openfiles (_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL)) == NULL)
|
if ((kd = kvm_openfiles (_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL)) == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
* Copyright (c) 2008-2010 Mike Massonnet <mmassonnet@xfce.org>
|
* Copyright (c) 2008-2010 Mike Massonnet <mmassonnet@xfce.org>
|
||||||
* Copyright (c) 2006 Johannes Zellner <webmaster@nebulon.de>
|
* Copyright (c) 2006 Johannes Zellner <webmaster@nebulon.de>
|
||||||
*
|
*
|
||||||
@@ -12,11 +13,368 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "inode-to-sock.h"
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "task-manager.h"
|
#include "task-manager.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
#include <netpacket/packet.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
static XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
static XtmInodeToSock *inode_to_sock = NULL;
|
||||||
static gushort _cpu_count = 0;
|
static gushort _cpu_count = 0;
|
||||||
static gulong jiffies_total_delta = 0;
|
static gulong jiffies_total_delta = 0;
|
||||||
|
|
||||||
|
void list_process_fds (Task *task);
|
||||||
|
void xtm_refresh_inode_to_sock_protocol (XtmInodeToSock *its, char *filename);
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_refresh_inode_to_sock_protocol (XtmInodeToSock *its, char *filename)
|
||||||
|
{
|
||||||
|
char buffer[8192];
|
||||||
|
char rem_addr[128], local_addr[128];
|
||||||
|
int local_port, rem_port, inode, count;
|
||||||
|
gint64 *key;
|
||||||
|
|
||||||
|
FILE *procinfo = fopen (filename, "r");
|
||||||
|
|
||||||
|
if (procinfo == 0)
|
||||||
|
{
|
||||||
|
perror (filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip header
|
||||||
|
if (fgets (buffer, sizeof (buffer), procinfo) == 0)
|
||||||
|
{
|
||||||
|
printf ("%s no header\n", filename);
|
||||||
|
fclose (procinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets (buffer, sizeof (buffer), procinfo))
|
||||||
|
{
|
||||||
|
count = sscanf (
|
||||||
|
buffer,
|
||||||
|
"%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X %*X:%*X %*X:%*X %*X %*d %*d %d",
|
||||||
|
local_addr, &local_port, rem_addr, &rem_port, &inode);
|
||||||
|
|
||||||
|
if (count != 5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
key = g_new0 (gint64, 1);
|
||||||
|
*key = inode;
|
||||||
|
g_hash_table_replace (its->hash, key, (gpointer)(intptr_t)local_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (procinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_refresh_inode_to_sock (XtmInodeToSock *its)
|
||||||
|
{
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/tcp");
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/tcp6");
|
||||||
|
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/udp");
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/udp6");
|
||||||
|
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/udplite");
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/udplite6");
|
||||||
|
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/raw");
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/raw6");
|
||||||
|
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/icmp");
|
||||||
|
xtm_refresh_inode_to_sock_protocol (its, "/proc/net/icmp6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
void
|
||||||
|
packet_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
|
||||||
|
{
|
||||||
|
struct ether_header *eth_header = (struct ether_header *)packet;
|
||||||
|
XtmNetworkAnalyzer *iface = (XtmNetworkAnalyzer *)args;
|
||||||
|
|
||||||
|
char local_mac[18];
|
||||||
|
char src_mac[18];
|
||||||
|
char dst_mac[18];
|
||||||
|
|
||||||
|
int32_t src_port = -1;
|
||||||
|
int32_t dst_port = -1;
|
||||||
|
|
||||||
|
sprintf (local_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
iface->mac[0], iface->mac[1], iface->mac[2],
|
||||||
|
iface->mac[3], iface->mac[4], iface->mac[5]);
|
||||||
|
|
||||||
|
sprintf (src_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header->ether_shost[0], eth_header->ether_shost[1],
|
||||||
|
eth_header->ether_shost[2], eth_header->ether_shost[3],
|
||||||
|
eth_header->ether_shost[4], eth_header->ether_shost[5]);
|
||||||
|
|
||||||
|
sprintf (dst_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header->ether_dhost[0], eth_header->ether_dhost[1],
|
||||||
|
eth_header->ether_dhost[2], eth_header->ether_dhost[3],
|
||||||
|
eth_header->ether_dhost[4], eth_header->ether_dhost[5]);
|
||||||
|
|
||||||
|
// IPv4 handling
|
||||||
|
if (ntohs (eth_header->ether_type) == ETHERTYPE_IP)
|
||||||
|
{
|
||||||
|
struct ip *ip_header = (struct ip *)(packet + sizeof (struct ether_header));
|
||||||
|
|
||||||
|
// TCP handling
|
||||||
|
if (ip_header->ip_p == IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
struct tcphdr *tcp_header = (struct tcphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip));
|
||||||
|
src_port = ntohs (tcp_header->source);
|
||||||
|
dst_port = ntohs (tcp_header->dest);
|
||||||
|
}
|
||||||
|
// UDP handling
|
||||||
|
else if (ip_header->ip_p == IPPROTO_UDP)
|
||||||
|
{
|
||||||
|
struct udphdr *udp_header = (struct udphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip));
|
||||||
|
src_port = ntohs (udp_header->source);
|
||||||
|
dst_port = ntohs (udp_header->dest);
|
||||||
|
}
|
||||||
|
// ICMP handling
|
||||||
|
else if (ip_header->ip_p == IPPROTO_ICMP)
|
||||||
|
{
|
||||||
|
// The Internet Control Message Protocol (ICMP) does not use ports like TCP and UDP
|
||||||
|
// But the ICMP packet is encapsulated in an IPv4 packet
|
||||||
|
// 0x1 Reported by /proc/net/raw using ping
|
||||||
|
src_port = 1;
|
||||||
|
dst_port = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// IPv6 handling
|
||||||
|
else if (ntohs (eth_header->ether_type) == ETHERTYPE_IPV6)
|
||||||
|
{
|
||||||
|
struct ip6_hdr *ip6_header = (struct ip6_hdr *)(packet + sizeof (struct ether_header));
|
||||||
|
|
||||||
|
// TCP handling
|
||||||
|
if (ip6_header->ip6_nxt == IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
struct tcphdr *tcp_header = (struct tcphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip6_hdr));
|
||||||
|
src_port = ntohs (tcp_header->source);
|
||||||
|
dst_port = ntohs (tcp_header->dest);
|
||||||
|
}
|
||||||
|
// UDP handling
|
||||||
|
else if (ip6_header->ip6_nxt == IPPROTO_UDP)
|
||||||
|
{
|
||||||
|
struct udphdr *udp_header = (struct udphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip6_hdr));
|
||||||
|
src_port = ntohs (udp_header->source);
|
||||||
|
dst_port = ntohs (udp_header->dest);
|
||||||
|
}
|
||||||
|
// ICMP handling
|
||||||
|
else if (ip6_header->ip6_nxt == IPPROTO_ICMPV6)
|
||||||
|
{
|
||||||
|
// The Internet Control Message Protocol (ICMP) does not use ports like TCP and UDP
|
||||||
|
// But the ICMP packet is encapsulated in an IPv6 packet
|
||||||
|
// 0x3A Reported by /proc/net/raw6
|
||||||
|
src_port = 0x3A;
|
||||||
|
dst_port = 0x3A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Raw packet handling
|
||||||
|
else
|
||||||
|
{
|
||||||
|
src_port = 1;
|
||||||
|
dst_port = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! ICMP and RAW packet share the same local port
|
||||||
|
//! thus the link port -> count is broken in this case
|
||||||
|
//! since local port become non unique
|
||||||
|
//! However it still allow to see some unexpected program
|
||||||
|
|
||||||
|
if (src_port != -1 && dst_port != -1)
|
||||||
|
{
|
||||||
|
if (strcmp (local_mac, src_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "in ", iface->packetin, src_port);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, dst_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "out", iface->packetout, dst_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
get_mac_address (const char *device, uint8_t mac[6])
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
char device_path[512];
|
||||||
|
char link_path[512];
|
||||||
|
|
||||||
|
snprintf (device_path, 512, "/sys/class/net/%s", device);
|
||||||
|
ssize_t len = readlink (device_path, link_path, 511);
|
||||||
|
|
||||||
|
// disable localhost, docker, vpn, and other virtual device
|
||||||
|
// only physical device should remain
|
||||||
|
if (len == -1 || strstr (link_path, "virtual") != NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (getifaddrs (&ifaddr) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (ifa->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int family = ifa->ifa_addr->sa_family;
|
||||||
|
|
||||||
|
// Check if the interface is a network interface (AF_PACKET for Linux)
|
||||||
|
if (family == AF_PACKET && strcmp (device, ifa->ifa_name) == 0)
|
||||||
|
{
|
||||||
|
// Check if the interface has a hardware address (MAC address)
|
||||||
|
if (ifa->ifa_data != NULL)
|
||||||
|
{
|
||||||
|
struct sockaddr_ll *sll = (struct sockaddr_ll *)ifa->ifa_addr;
|
||||||
|
memcpy (mac, sll->sll_addr, sizeof (uint8_t) * 6);
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_network_usage (guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
gchar buffer[256];
|
||||||
|
char *out;
|
||||||
|
|
||||||
|
*tcp_rx = 0;
|
||||||
|
*tcp_tx = 0;
|
||||||
|
*tcp_error = 0;
|
||||||
|
|
||||||
|
if ((file = fopen ("/proc/net/dev", "r")) == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
out = fgets (buffer, sizeof (buffer), file);
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
{
|
||||||
|
fclose (file);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = fgets (buffer, sizeof (buffer), file);
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
{
|
||||||
|
fclose (file);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets (buffer, sizeof (buffer), file))
|
||||||
|
{
|
||||||
|
unsigned long int dummy = 0;
|
||||||
|
unsigned long int r_bytes = 0;
|
||||||
|
unsigned long int t_bytes = 0;
|
||||||
|
unsigned long int r_packets = 0;
|
||||||
|
unsigned long int t_packets = 0;
|
||||||
|
unsigned long int error = 0;
|
||||||
|
gchar ifname[256];
|
||||||
|
|
||||||
|
int count = sscanf (
|
||||||
|
buffer, "%[^:]: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
|
||||||
|
ifname, &r_bytes, &r_packets, &error,
|
||||||
|
&dummy, &dummy, &dummy, &dummy, &dummy,
|
||||||
|
&t_bytes, &t_packets);
|
||||||
|
|
||||||
|
if (count != 11)
|
||||||
|
{
|
||||||
|
printf ("Something went wrong while reading /proc/net/dev -> expected %d\n", count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*tcp_rx += r_bytes;
|
||||||
|
*tcp_tx += t_bytes;
|
||||||
|
*tcp_error += error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (file);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
list_process_fds (Task *task)
|
||||||
|
{
|
||||||
|
XtmNetworkAnalyzer *current;
|
||||||
|
char path[1024];
|
||||||
|
char link[2048];
|
||||||
|
char target[2048];
|
||||||
|
struct dirent *entry;
|
||||||
|
ssize_t len;
|
||||||
|
long int port;
|
||||||
|
DIR *dir;
|
||||||
|
|
||||||
|
task->packet_in = 0;
|
||||||
|
task->packet_out = 0;
|
||||||
|
|
||||||
|
snprintf (path, sizeof (path), "/proc/%d/fd", (int)task->pid);
|
||||||
|
|
||||||
|
dir = opendir (path);
|
||||||
|
|
||||||
|
if (dir == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((entry = readdir (dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (entry->d_type != DT_LNK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf (link, sizeof (link), "%s/%s", path, entry->d_name);
|
||||||
|
len = readlink (link, target, sizeof (target) - 1);
|
||||||
|
|
||||||
|
if (len == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
target[len] = '\0';
|
||||||
|
if (strncmp (target, "socket:", 7) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int inode;
|
||||||
|
if (sscanf (target, "socket:[%d]", &inode) == 1)
|
||||||
|
{
|
||||||
|
task->active_socket += 1;
|
||||||
|
port = (long int)g_hash_table_lookup (inode_to_sock->hash, &inode);
|
||||||
|
|
||||||
|
current = analyzer;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
// pthread_mutex_lock(&analyzer->lock);
|
||||||
|
task->packet_in += (guint64)g_hash_table_lookup (current->packetin, &port);
|
||||||
|
task->packet_out += (guint64)g_hash_table_lookup (current->packetout, &port);
|
||||||
|
// pthread_mutex_lock(&analyzer->lock);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir (dir);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
|
get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
|
||||||
{
|
{
|
||||||
@@ -304,6 +662,8 @@ get_task_details (GPid pid, Task *task)
|
|||||||
fclose (file);
|
fclose (file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_process_fds (task);
|
||||||
|
|
||||||
/* Read the full command line */
|
/* Read the full command line */
|
||||||
if (!get_task_cmdline (task))
|
if (!get_task_cmdline (task))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -319,6 +679,10 @@ get_task_list (GArray *task_list)
|
|||||||
GPid pid;
|
GPid pid;
|
||||||
Task task;
|
Task task;
|
||||||
|
|
||||||
|
analyzer = xtm_network_analyzer_get_default ();
|
||||||
|
inode_to_sock = xtm_inode_to_sock_get_default ();
|
||||||
|
xtm_refresh_inode_to_sock (inode_to_sock);
|
||||||
|
|
||||||
if ((dir = g_dir_open ("/proc", 0, NULL)) == NULL)
|
if ((dir = g_dir_open ("/proc", 0, NULL)) == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,29 @@
|
|||||||
static gushort _cpu_count = 0;
|
static gushort _cpu_count = 0;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
get_mac_address (const char *device, uint8_t mac[6])
|
||||||
|
{
|
||||||
|
memset (mac, 0, sizeof (uint8_t) * 6);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_network_usage (guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
*tcp_rx = 0;
|
||||||
|
*tcp_tx = 0;
|
||||||
|
*tcp_error = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
void
|
||||||
|
packet_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
|
get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
* Copyright (c) 2010 Mike Massonnet <mmassonnet@xfce.org>
|
* Copyright (c) 2010 Mike Massonnet <mmassonnet@xfce.org>
|
||||||
* Copyright (c) 2009 Peter Tribble <peter.tribble@gmail.com>
|
* Copyright (c) 2009 Peter Tribble <peter.tribble@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -12,29 +13,456 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "inode-to-sock.h"
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "task-manager.h"
|
#include "task-manager.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <inet/common.h> /* typedef int (*pfi_t)() for inet/optcom.h */
|
||||||
|
#include <inet/optcom.h>
|
||||||
#include <kstat.h>
|
#include <kstat.h>
|
||||||
#include <procfs.h>
|
#include <procfs.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/procfs.h>
|
#include <sys/procfs.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/swap.h>
|
#include <sys/swap.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/stropts.h>
|
||||||
|
#include <inet/mib2.h>
|
||||||
|
#include <sys/tihdr.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static XtmInodeToSock *inode_to_sock = NULL;
|
||||||
|
static XtmNetworkAnalyzer *analyzer = NULL;
|
||||||
|
|
||||||
static kstat_ctl_t *kc;
|
static kstat_ctl_t *kc;
|
||||||
static gushort _cpu_count = 0;
|
static gushort _cpu_count = 0;
|
||||||
static gulong ticks_total_delta = 0;
|
static gulong ticks_total_delta = 0;
|
||||||
|
|
||||||
|
void addtoconninode (XtmInodeToSock *its, gint64 pid, char *ip, guint64 port);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_stats (void)
|
init_stats (void)
|
||||||
{
|
{
|
||||||
kc = kstat_open ();
|
kc = kstat_open ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_mac_address (const char *device, uint8_t mac[6])
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBSOCKET
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
|
||||||
|
if (getifaddrs (&ifaddr) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (ifa->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the interface is a network interface (AF_PACKET for Linux)
|
||||||
|
if (ifa->ifa_addr->sa_family == AF_LINK && strcmp (device, ifa->ifa_name) == 0)
|
||||||
|
{
|
||||||
|
// Check if the interface has a hardware address (MAC address)
|
||||||
|
if (ifa->ifa_data != NULL)
|
||||||
|
{
|
||||||
|
// warning: cast from 'struct sockaddr *' to 'struct sockaddr_dl *' increases required alignment from 1 to 2
|
||||||
|
// struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||||
|
struct sockaddr_dl sdl;
|
||||||
|
memcpy (&sdl, ifa->ifa_addr, sizeof (struct sockaddr_dl));
|
||||||
|
memcpy (mac, sdl.sdl_data + sdl.sdl_nlen, sizeof (uint8_t) * 6);
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (ifaddr);
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
memset (mac, 0, sizeof (uint8_t) * 6);
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
get_network_usage (guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
kstat_named_t *knp;
|
||||||
|
kstat_t *ksp;
|
||||||
|
|
||||||
|
if (!kc)
|
||||||
|
init_stats ();
|
||||||
|
|
||||||
|
if (!(ksp = kstat_lookup (kc, "link", -1, NULL)))
|
||||||
|
{
|
||||||
|
printf ("kstat_lookup failed\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
kstat_read (kc, ksp, NULL);
|
||||||
|
*tcp_error = 0;
|
||||||
|
|
||||||
|
if ((knp = kstat_data_lookup (ksp, "rbytes64")) != NULL)
|
||||||
|
*tcp_rx = knp->value.ui64;
|
||||||
|
|
||||||
|
if ((knp = kstat_data_lookup (ksp, "obytes64")) != NULL)
|
||||||
|
*tcp_tx = knp->value.ui64;
|
||||||
|
|
||||||
|
if ((knp = kstat_data_lookup (ksp, "ierrors")) != NULL)
|
||||||
|
*tcp_error += knp->value.ui32;
|
||||||
|
|
||||||
|
if ((knp = kstat_data_lookup (ksp, "oerrors")) != NULL)
|
||||||
|
*tcp_error += knp->value.ui32;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
void
|
||||||
|
packet_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
|
||||||
|
{
|
||||||
|
// Extract source and destination IP addresses and ports from the packet
|
||||||
|
struct ether_header eth_header;
|
||||||
|
struct ip ip_header;
|
||||||
|
struct tcphdr tcp_header;
|
||||||
|
XtmNetworkAnalyzer *iface;
|
||||||
|
long int src_port, dst_port;
|
||||||
|
char local_mac[18];
|
||||||
|
char src_mac[18];
|
||||||
|
char dst_mac[18];
|
||||||
|
|
||||||
|
memcpy (ð_header, packet, sizeof (struct ether_header));
|
||||||
|
memcpy (&ip_header, packet + sizeof (struct ether_header), sizeof (struct ip));
|
||||||
|
memcpy (&tcp_header, packet + sizeof (struct ether_header) + sizeof (struct ip), sizeof (struct ip));
|
||||||
|
|
||||||
|
// cast -> increases required alignment from 1 to 2 [-Wcast-align]
|
||||||
|
// const struct ether_header *eth_header = (const struct ether_header *)packet;
|
||||||
|
// struct ip *ip_header = (struct ip *)(packet + sizeof (struct ether_header));
|
||||||
|
// struct tcphdr *tcp_header = (struct tcphdr *)(packet + sizeof (struct ether_header) + sizeof (struct ip));
|
||||||
|
// printf("%d, %d \n", eth_heade.ether_type , ip_header.ip_p);
|
||||||
|
|
||||||
|
// Dropped non-ip packet
|
||||||
|
if (eth_header.ether_type != 8 || ip_header.ip_p != 6)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface = (XtmNetworkAnalyzer *)args;
|
||||||
|
|
||||||
|
src_port = ntohs (tcp_header.th_sport);
|
||||||
|
dst_port = ntohs (tcp_header.th_dport);
|
||||||
|
|
||||||
|
// directly use strcmp on analyzer->mac, eth_header->ether_shost doesnt work
|
||||||
|
|
||||||
|
snprintf (local_mac, sizeof (local_mac),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
iface->mac[0], iface->mac[1],
|
||||||
|
iface->mac[2], iface->mac[3],
|
||||||
|
iface->mac[4], iface->mac[5]);
|
||||||
|
|
||||||
|
snprintf (src_mac, sizeof (local_mac),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header.ether_shost.ether_addr_octet[0], eth_header.ether_shost.ether_addr_octet[1],
|
||||||
|
eth_header.ether_shost.ether_addr_octet[2], eth_header.ether_shost.ether_addr_octet[3],
|
||||||
|
eth_header.ether_shost.ether_addr_octet[4], eth_header.ether_shost.ether_addr_octet[5]);
|
||||||
|
|
||||||
|
snprintf (dst_mac, sizeof (local_mac),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
eth_header.ether_dhost.ether_addr_octet[0], eth_header.ether_dhost.ether_addr_octet[1],
|
||||||
|
eth_header.ether_dhost.ether_addr_octet[2], eth_header.ether_dhost.ether_addr_octet[3],
|
||||||
|
eth_header.ether_dhost.ether_addr_octet[4], eth_header.ether_dhost.ether_addr_octet[5]);
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
// pthread_mutex_lock(&iface->lock);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, src_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "in ", iface->packetin, src_port);
|
||||||
|
|
||||||
|
if (strcmp (local_mac, dst_mac) == 0)
|
||||||
|
increament_packet_count (local_mac, "out", iface->packetout, dst_port);
|
||||||
|
|
||||||
|
// pthread_mutex_unlock(&iface->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
set_task_network_data (Task *task, guint64 port)
|
||||||
|
{
|
||||||
|
XtmNetworkAnalyzer *current;
|
||||||
|
task->active_socket += 1;
|
||||||
|
|
||||||
|
current = analyzer;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
task->packet_in += (guint64)g_hash_table_lookup (current->packetin, &port);
|
||||||
|
task->packet_out += (guint64)g_hash_table_lookup (current->packetout, &port);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
list_process_fds (Task *task)
|
||||||
|
{
|
||||||
|
XtmNetworkAnalyzer *current;
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
gint64 key_int, value_int;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, inode_to_sock->pid);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
key_int = *(gint64 *)(key);
|
||||||
|
value_int = GPOINTER_TO_INT (value);
|
||||||
|
|
||||||
|
if (task->pid == value_int)
|
||||||
|
set_task_network_data (task, key_int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
addtoconninode (XtmInodeToSock *its, gint64 pid, char *ip, guint64 port)
|
||||||
|
{
|
||||||
|
gint64 *inode;
|
||||||
|
|
||||||
|
if (its == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// seem like idle socket are given back to pid 0 (kernel ?)
|
||||||
|
if (pid <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (strcmp (ip, "0.0.0.0") == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (strcmp (ip, "::") == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (strcmp (ip, "127.0.0.1") == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
inode = g_new0 (gint64, 1);
|
||||||
|
*inode = port;
|
||||||
|
|
||||||
|
g_hash_table_replace (inode_to_sock->pid, inode, (gpointer)(intptr_t)pid);
|
||||||
|
|
||||||
|
printf ("PID %ld: Local Address: [%s]:%ld\n", pid, ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_refresh_inode_to_sock (XtmInodeToSock *its)
|
||||||
|
{
|
||||||
|
// inspired by :
|
||||||
|
// nxsensor/src/sysdeps/solaris.c
|
||||||
|
// net-snmp/agent/mibgroup/mibII/tcpTable.c
|
||||||
|
// net-snmp/agent/mibgroup/mibgroup/kernel_sunos5.c
|
||||||
|
// psutil/psutil/_psutil_sunos.c
|
||||||
|
// illumos-joyent/master/usr/src/uts/common/io/tl.c
|
||||||
|
// nicstat/nicstat.c
|
||||||
|
|
||||||
|
int sd, ret, flags, getcode, num_ent, i;
|
||||||
|
char buf[4096];
|
||||||
|
char lip[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
mib2_tcpConnEntry_t tp;
|
||||||
|
mib2_udpEntry_t ude;
|
||||||
|
|
||||||
|
#if defined(AF_INET6)
|
||||||
|
mib2_tcp6ConnEntry_t tp6;
|
||||||
|
mib2_udp6Entry_t ude6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct strbuf ctlbuf, databuf;
|
||||||
|
struct T_optmgmt_req tor = { 0 };
|
||||||
|
struct T_optmgmt_ack toa = { 0 };
|
||||||
|
struct T_error_ack tea = { 0 };
|
||||||
|
struct opthdr mibhdr = { 0 };
|
||||||
|
|
||||||
|
sd = open ("/dev/arp", O_RDWR);
|
||||||
|
if (sd == -1)
|
||||||
|
{
|
||||||
|
perror ("open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl (sd, I_PUSH, "tcp");
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
perror ("ioctl");
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl (sd, I_PUSH, "udp");
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
perror ("ioctl");
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// g_hash_table_remove_all (its->pid);
|
||||||
|
// g_hash_table_remove_all (its->hash);
|
||||||
|
|
||||||
|
// Set up the request
|
||||||
|
tor.PRIM_type = T_SVR4_OPTMGMT_REQ;
|
||||||
|
tor.OPT_offset = sizeof (struct T_optmgmt_req);
|
||||||
|
tor.OPT_length = sizeof (struct opthdr);
|
||||||
|
tor.MGMT_flags = T_CURRENT;
|
||||||
|
mibhdr.level = MIB2_IP;
|
||||||
|
mibhdr.name = 0;
|
||||||
|
#ifdef NEW_MIB_COMPLIANT
|
||||||
|
mibhdr.len = 1;
|
||||||
|
#else
|
||||||
|
mibhdr.len = 0;
|
||||||
|
#endif
|
||||||
|
memcpy (buf, &tor, sizeof (tor));
|
||||||
|
memcpy (buf + tor.OPT_offset, &mibhdr, sizeof (mibhdr));
|
||||||
|
ctlbuf.buf = buf;
|
||||||
|
ctlbuf.len = tor.OPT_offset + tor.OPT_length;
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
if (putmsg (sd, &ctlbuf, NULL, flags) == -1)
|
||||||
|
{
|
||||||
|
perror ("putmsg");
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctlbuf.maxlen = sizeof (buf);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
getcode = getmsg (sd, &ctlbuf, NULL, &flags);
|
||||||
|
memcpy (&toa, buf, sizeof (toa));
|
||||||
|
memcpy (&tea, buf, sizeof (tea));
|
||||||
|
|
||||||
|
if (getcode != MOREDATA || ctlbuf.len < (int)sizeof (struct T_optmgmt_ack) ||
|
||||||
|
toa.PRIM_type != T_OPTMGMT_ACK || toa.MGMT_flags != T_SUCCESS)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctlbuf.len >= (int)sizeof (struct T_error_ack) && tea.PRIM_type == T_ERROR_ACK)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "ERROR_ACK\n");
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getcode == 0 && ctlbuf.len >= (int)sizeof (struct T_optmgmt_ack) &&
|
||||||
|
toa.PRIM_type == T_OPTMGMT_ACK && toa.MGMT_flags == T_SUCCESS)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "ERROR_T_OPTMGMT_ACK\n");
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (&mibhdr, 0x0, sizeof (mibhdr));
|
||||||
|
memcpy (&mibhdr, buf + toa.OPT_offset, toa.OPT_length);
|
||||||
|
databuf.maxlen = mibhdr.len;
|
||||||
|
databuf.len = 0;
|
||||||
|
databuf.buf = (char *)malloc ((int)mibhdr.len);
|
||||||
|
if (!databuf.buf)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Out of memory\n");
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
getcode = getmsg (sd, NULL, &databuf, &flags);
|
||||||
|
|
||||||
|
if (getcode < 0)
|
||||||
|
{
|
||||||
|
perror ("getmsg");
|
||||||
|
free (databuf.buf);
|
||||||
|
close (sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TCPv4
|
||||||
|
if (mibhdr.level == MIB2_TCP && mibhdr.name == MIB2_TCP_13)
|
||||||
|
{
|
||||||
|
num_ent = mibhdr.len / sizeof (mib2_tcpConnEntry_t);
|
||||||
|
for (i = 0; i < num_ent; i++)
|
||||||
|
{
|
||||||
|
memcpy (&tp, databuf.buf + i * sizeof (tp), sizeof (tp));
|
||||||
|
inet_ntop (AF_INET, &tp.tcpConnLocalAddress, lip, sizeof (lip));
|
||||||
|
addtoconninode (inode_to_sock, tp.tcpConnCreationProcess, lip, tp.tcpConnLocalPort);
|
||||||
|
// interesting properties, allowing to remove pcap
|
||||||
|
// tp.tcpConnEntryInfo.ce_in_data_inorder_segs
|
||||||
|
// tp.tcpConnEntryInfo.ce_in_data_unorder_segs
|
||||||
|
// tp.tcpConnEntryInfo.ce_out_data_segs
|
||||||
|
// tp.tcpConnEntryInfo.ce_out_retrans_segs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(AF_INET6)
|
||||||
|
// TCPv6
|
||||||
|
else if (mibhdr.level == MIB2_TCP6 && mibhdr.name == MIB2_TCP6_CONN)
|
||||||
|
{
|
||||||
|
num_ent = mibhdr.len / sizeof (mib2_tcp6ConnEntry_t);
|
||||||
|
for (i = 0; i < num_ent; i++)
|
||||||
|
{
|
||||||
|
memcpy (&tp6, databuf.buf + i * sizeof (tp6), sizeof (tp6));
|
||||||
|
inet_ntop (AF_INET6, &tp6.tcp6ConnLocalAddress, lip, sizeof (lip));
|
||||||
|
addtoconninode (inode_to_sock, tp6.tcp6ConnCreationProcess, lip, tp6.tcp6ConnLocalPort);
|
||||||
|
// interesting properties, allowing to remove pcap
|
||||||
|
// tp.tcpConnEntryInfo.ce_in_data_inorder_segs
|
||||||
|
// tp.tcpConnEntryInfo.ce_in_data_unorder_segs
|
||||||
|
// tp.tcpConnEntryInfo.ce_out_data_segs
|
||||||
|
// tp.tcpConnEntryInfo.ce_out_retrans_segs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// UDPv4
|
||||||
|
else if (mibhdr.level == MIB2_UDP || mibhdr.level == MIB2_UDP_ENTRY)
|
||||||
|
{
|
||||||
|
num_ent = mibhdr.len / sizeof (mib2_udpEntry_t);
|
||||||
|
for (i = 0; i < num_ent; i++)
|
||||||
|
{
|
||||||
|
memcpy (&ude, databuf.buf + i * sizeof (ude), sizeof (ude));
|
||||||
|
inet_ntop (AF_INET, &ude.udpLocalAddress, lip, sizeof (lip));
|
||||||
|
addtoconninode (inode_to_sock, ude.udpCreationProcess, lip, ude.udpLocalPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(AF_INET6)
|
||||||
|
// UDPv6
|
||||||
|
else if (mibhdr.level == MIB2_UDP6 || mibhdr.level == MIB2_UDP6_ENTRY)
|
||||||
|
{
|
||||||
|
num_ent = mibhdr.len / sizeof (mib2_udp6Entry_t);
|
||||||
|
for (i = 0; i < num_ent; i++)
|
||||||
|
{
|
||||||
|
memcpy (&ude6, databuf.buf + i * sizeof (ude6), sizeof (ude6));
|
||||||
|
inet_ntop (AF_INET6, &ude6.udp6LocalAddress, lip, sizeof (lip));
|
||||||
|
addtoconninode (inode_to_sock, ude6.udp6CreationProcess, lip, ude6.udp6LocalPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
free (databuf.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
close (sd);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
|
get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free)
|
||||||
{
|
{
|
||||||
@@ -201,6 +629,8 @@ get_task_details (GPid pid, Task *task)
|
|||||||
|
|
||||||
fclose (file);
|
fclose (file);
|
||||||
|
|
||||||
|
list_process_fds (task);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +642,11 @@ get_task_list (GArray *task_list)
|
|||||||
GPid pid;
|
GPid pid;
|
||||||
Task task;
|
Task task;
|
||||||
|
|
||||||
|
printf ("------------\n");
|
||||||
|
analyzer = xtm_network_analyzer_get_default ();
|
||||||
|
inode_to_sock = xtm_inode_to_sock_get_default ();
|
||||||
|
xtm_refresh_inode_to_sock (inode_to_sock);
|
||||||
|
|
||||||
if ((dir = g_dir_open ("/proc", 0, NULL)) == NULL)
|
if ((dir = g_dir_open ("/proc", 0, NULL)) == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2024 Jehan-Antoine Vayssade, <javayss@sleek-think.ovh>
|
||||||
* Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
|
* Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
|
||||||
* Copyright (c) 2018 Rozhuk Ivan <rozhuk.im@gmail.com>
|
* Copyright (c) 2018 Rozhuk Ivan <rozhuk.im@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "network-analyzer.h"
|
||||||
#include "process-tree-view.h" /* for the columns of the model */
|
#include "process-tree-view.h" /* for the columns of the model */
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "task-manager.h"
|
#include "task-manager.h"
|
||||||
@@ -22,6 +24,10 @@
|
|||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
#include <pcap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
@@ -42,6 +48,7 @@ struct _XtmTaskManagerClass
|
|||||||
{
|
{
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _XtmTaskManager
|
struct _XtmTaskManager
|
||||||
{
|
{
|
||||||
GObject parent;
|
GObject parent;
|
||||||
@@ -61,6 +68,12 @@ struct _XtmTaskManager
|
|||||||
guint64 memory_buffers;
|
guint64 memory_buffers;
|
||||||
guint64 swap_total;
|
guint64 swap_total;
|
||||||
guint64 swap_free;
|
guint64 swap_free;
|
||||||
|
guint64 tcp_rx;
|
||||||
|
guint64 tcp_tx;
|
||||||
|
guint64 tcp_error;
|
||||||
|
guint64 old_tcp_rx;
|
||||||
|
guint64 old_tcp_tx;
|
||||||
|
guint64 old_tcp_error;
|
||||||
};
|
};
|
||||||
G_DEFINE_TYPE (XtmTaskManager, xtm_task_manager, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (XtmTaskManager, xtm_task_manager, G_TYPE_OBJECT)
|
||||||
|
|
||||||
@@ -101,6 +114,9 @@ xtm_task_manager_init (XtmTaskManager *manager)
|
|||||||
g_object_get (settings, "full-command-line", &full_cmdline, NULL);
|
g_object_get (settings, "full-command-line", &full_cmdline, NULL);
|
||||||
g_signal_connect (settings, "notify::more-precision", G_CALLBACK (setting_changed), manager);
|
g_signal_connect (settings, "notify::more-precision", G_CALLBACK (setting_changed), manager);
|
||||||
g_signal_connect (settings, "notify::full-command-line", G_CALLBACK (setting_changed), manager);
|
g_signal_connect (settings, "notify::full-command-line", G_CALLBACK (setting_changed), manager);
|
||||||
|
manager->old_tcp_rx = 0;
|
||||||
|
manager->old_tcp_tx = 0;
|
||||||
|
manager->old_tcp_error = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -108,6 +124,7 @@ xtm_task_manager_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
XtmTaskManager *manager = XTM_TASK_MANAGER (object);
|
XtmTaskManager *manager = XTM_TASK_MANAGER (object);
|
||||||
g_array_free (manager->tasks, TRUE);
|
g_array_free (manager->tasks, TRUE);
|
||||||
|
|
||||||
#ifdef HAVE_WNCK
|
#ifdef HAVE_WNCK
|
||||||
if (manager->app_manager != NULL)
|
if (manager->app_manager != NULL)
|
||||||
{
|
{
|
||||||
@@ -334,6 +351,9 @@ model_update_tree_iter (XtmTaskManager *manager, GtkTreeIter *iter, glong timest
|
|||||||
XTM_PTV_COLUMN_CPU_STR, cpu,
|
XTM_PTV_COLUMN_CPU_STR, cpu,
|
||||||
XTM_PTV_COLUMN_GROUP_CPU, (task->group_cpu_user + task->group_cpu_system),
|
XTM_PTV_COLUMN_GROUP_CPU, (task->group_cpu_user + task->group_cpu_system),
|
||||||
XTM_PTV_COLUMN_GROUP_CPU_STR, group_cpu,
|
XTM_PTV_COLUMN_GROUP_CPU_STR, group_cpu,
|
||||||
|
XTM_PTV_COLUMN_PACKET_IN, task->packet_in,
|
||||||
|
XTM_PTV_COLUMN_PACKET_OUT, task->packet_out,
|
||||||
|
XTM_PTV_COLUMN_ACTIVE_SOCKET, task->active_socket,
|
||||||
XTM_PTV_COLUMN_PRIORITY, task->prio,
|
XTM_PTV_COLUMN_PRIORITY, task->prio,
|
||||||
XTM_PTV_COLUMN_BACKGROUND, background,
|
XTM_PTV_COLUMN_BACKGROUND, background,
|
||||||
XTM_PTV_COLUMN_FOREGROUND, foreground,
|
XTM_PTV_COLUMN_FOREGROUND, foreground,
|
||||||
@@ -393,6 +413,33 @@ xtm_task_manager_new (GtkTreeModel *model)
|
|||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtm_task_manager_get_network_info (XtmTaskManager *manager, guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error)
|
||||||
|
{
|
||||||
|
g_return_if_fail (XTM_IS_TASK_MANAGER (manager));
|
||||||
|
get_network_usage (&manager->tcp_rx, &manager->tcp_tx, &manager->tcp_error);
|
||||||
|
|
||||||
|
if (manager->old_tcp_rx == 0 && manager->old_tcp_tx == 0 && manager->old_tcp_error == 0)
|
||||||
|
{
|
||||||
|
*tcp_rx = 0;
|
||||||
|
*tcp_tx = 0;
|
||||||
|
*tcp_error = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gint ms;
|
||||||
|
g_object_get (settings, "refresh-rate", &ms, NULL);
|
||||||
|
// ugly approximation in guint64
|
||||||
|
*tcp_rx = (manager->tcp_rx - manager->old_tcp_rx) / ms * 1000;
|
||||||
|
*tcp_tx = (manager->tcp_tx - manager->old_tcp_tx) / ms * 1000;
|
||||||
|
*tcp_error = (manager->tcp_error - manager->old_tcp_error) / ms * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->old_tcp_rx = manager->tcp_rx;
|
||||||
|
manager->old_tcp_tx = manager->tcp_tx;
|
||||||
|
manager->old_tcp_error = manager->tcp_error;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu,
|
xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu,
|
||||||
guint64 *memory_used, guint64 *memory_total,
|
guint64 *memory_used, guint64 *memory_total,
|
||||||
|
|||||||
@@ -10,9 +10,17 @@
|
|||||||
#ifndef TASK_MANAGER_H
|
#ifndef TASK_MANAGER_H
|
||||||
#define TASK_MANAGER_H
|
#define TASK_MANAGER_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
#include <pcap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legend colors
|
* Legend colors
|
||||||
*/
|
*/
|
||||||
@@ -45,6 +53,10 @@ struct _Task
|
|||||||
gfloat group_cpu_system;
|
gfloat group_cpu_system;
|
||||||
guint64 group_vsz;
|
guint64 group_vsz;
|
||||||
guint64 group_rss;
|
guint64 group_rss;
|
||||||
|
|
||||||
|
guint64 packet_in;
|
||||||
|
guint64 packet_out;
|
||||||
|
guint64 active_socket;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,6 +65,12 @@ struct _Task
|
|||||||
* memory_available = free + cache + buffers + an-OS-specific-value
|
* memory_available = free + cache + buffers + an-OS-specific-value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
void packet_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int get_mac_address (const char *device, uint8_t mac[6]);
|
||||||
|
gboolean get_network_usage (guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error);
|
||||||
gboolean get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free);
|
gboolean get_memory_usage (guint64 *memory_total, guint64 *memory_available, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free);
|
||||||
gboolean get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system);
|
gboolean get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system);
|
||||||
gboolean get_task_list (GArray *task_list);
|
gboolean get_task_list (GArray *task_list);
|
||||||
@@ -73,6 +91,7 @@ typedef struct _XtmTaskManager XtmTaskManager;
|
|||||||
|
|
||||||
GType xtm_task_manager_get_type (void);
|
GType xtm_task_manager_get_type (void);
|
||||||
XtmTaskManager *xtm_task_manager_new (GtkTreeModel *model);
|
XtmTaskManager *xtm_task_manager_new (GtkTreeModel *model);
|
||||||
|
void xtm_task_manager_get_network_info (XtmTaskManager *manager, guint64 *tcp_rx, guint64 *tcp_tx, guint64 *tcp_error);
|
||||||
void xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu,
|
void xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu,
|
||||||
guint64 *memory_used, guint64 *memory_total,
|
guint64 *memory_used, guint64 *memory_total,
|
||||||
guint64 *swap_used, guint64 *swap_total);
|
guint64 *swap_used, guint64 *swap_total);
|
||||||
|
|||||||
Reference in New Issue
Block a user