/* This file is part of GNUnet. (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet 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, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/statistics/gnunet-statistics-gtk.c * @brief Main function of gnunet-statistics-gtk * @author Christian Grothoff */ #include "gnunet_gtk.h" #include #include #include #include "gtk_statistics.h" #define MAX_HISTORY 1280 /** * Information about how to plot certain values. */ struct PlotInfo { /** * Subsystem originating the value to plot. */ const char *subsystem; /** * Name of the value to plot. */ const char *name; /** * Label to use in legend. */ const char *label; /** * Name of color to use when plotting. */ const char *color_name; }; static const struct PlotInfo connection_data[] = { {"fs", "# peers connected", "file-sharing connections", "blue"}, {"core", "# entries in session map", "encrypted connections (core)", "green"}, {"core", "# neighbour entries allocated", "transport connections (core)", "yellow"}, {"transport", "# peers connected", "total connections (transport)", "orange"}, {"transport", "# TCP sessions active", "tcp connections", "red"}, {"peerinfo", "# peers known", "peers known", "brown"}, {"nse", "# nodes in the network (estimate)", "network size (estimate)", "purple"}, {NULL, NULL, NULL} }; static const struct PlotInfo traffic_data[] = { {"core", "# bytes encrypted", "bytes encrypted", "blue"}, {"core", "# bytes decrypted", "bytes decrypted", "green"}, {"transport", "# bytes received via TCP", "received via tcp", "yellow"}, {"transport", "# bytes transmitted via TCP", "sent via tcp", "brown"}, {NULL, NULL, NULL} }; static const struct PlotInfo storage_data[] = { {"datastore", "# quota", "datastore capacity", "blue"}, {"datastore", "# utilization by current datastore", "datastore utilization", "yellow"}, {"datastore", "# cache size", "reservation for datastore cache", "green"}, {"datastore", "# bytes purged (low-priority)", "discarded due to limited space", "red"}, {NULL, NULL, NULL} }; /** * Handle to our main loop. */ static struct GNUNET_GTK_MainLoop *ml; /** * Should gnunet-peerinfo-gtk start in tray mode? */ static int tray_only; /** * Handle to statistics subsystem. */ static struct GNUNET_STATISTICS_Handle *statistics; /** * Task that refreshes connection graphic. */ static GNUNET_SCHEDULER_TaskIdentifier connection_task; /** * When did this process start? */ static struct GNUNET_TIME_Absolute start_time; /** * Callback function to process statistic values. * * @param cls the 'struct ValueHistory' to update * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue */ static int process_value_update (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GtkStatistics *stats = cls; char *id; GNUNET_asprintf (&id, "%s: %s", subsystem, name); gtk_statistics_update_value (stats, id, GNUNET_TIME_absolute_get_duration (start_time).rel_value / 1000LL, value); GNUNET_free (id); return GNUNET_OK; } /** * Get an object from the main window. * * @param name name of the object * @return NULL on error */ static GObject * get_object (const char *name) { return GNUNET_GTK_main_loop_get_object (ml, name); } /** * Actually draw a plot based on collected data. * * @param widget size and style information for the plot * @param info what to draw */ static void create_plot (const char *box_name, const struct PlotInfo *info) { GtkBox *box; GtkStatistics *ret; unsigned int i; char *id; ret = GTK_STATISTICS (gtk_statistics_new ()); box = GTK_BOX (get_object (box_name)); for (i = 0; NULL != info[i].subsystem; i++) { GNUNET_asprintf (&id, "%s: %s", info[i].subsystem, info[i].name); gtk_statistics_add_line (ret, id, info[i].label, info[i].color_name); GNUNET_free (id); GNUNET_STATISTICS_watch (statistics, info[i].subsystem, info[i].name, &process_value_update, ret); } gtk_widget_show (GTK_WIDGET (ret)); gtk_box_pack_start (box, GTK_WIDGET (ret), TRUE, TRUE, 0); } /** * Task run on shutdown. * * @param cls unused * @param tc scheduler context, unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); statistics = NULL; } /** * Callback invoked if the application is supposed to exit. */ void GNUNET_STATISTICS_GTK_quit_cb (GObject * object, gpointer user_data) { GNUNET_GTK_tray_icon_destroy (); GNUNET_GTK_main_loop_quit (ml); if (connection_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (connection_task); connection_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } /** * Callback invoked if the application is supposed to exit from the tray. */ void GNUNET_GTK_quit_cb (GObject * object, gpointer user_data) { GNUNET_STATISTICS_GTK_quit_cb (object, user_data); } /** * Actual main function run right after GNUnet's scheduler * is initialized. Initializes up GTK and Glade. */ static void run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GtkWidget *main_window; ml = cls; if (GNUNET_OK != GNUNET_GTK_main_loop_build_window (ml, NULL)) { return; } statistics = GNUNET_STATISTICS_create ("gnunet-statistics-gtk", GNUNET_GTK_main_loop_get_configuration (ml)); if (NULL == statistics) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to initiate connection with statistics service\n")); return; } GNUNET_GTK_set_icon_search_path (); GNUNET_GTK_setup_nls (); /* setup main window */ main_window = GTK_WIDGET (get_object ("GNUNET_STATISTICS_GTK_main_window")); gtk_window_maximize (GTK_WINDOW (main_window)); GNUNET_GTK_tray_icon_create (GTK_WINDOW (main_window), "gnunet-gtk" /* FIXME: different icon? */ , "gnunet-statistics-gtk"); create_plot ("GNUNET_STATISTICS_GTK_connectivity_box", connection_data); create_plot ("GNUNET_STATISTICS_GTK_traffic_box", traffic_data); create_plot ("GNUNET_STATISTICS_GTK_storage_box", storage_data); /* make GUI visible */ if (!tray_only) { gtk_widget_show (main_window); gtk_window_present (GTK_WINDOW (main_window)); } } int main (int argc, char *const *argv) { static struct GNUNET_GETOPT_CommandLineOption options[] = { {'t', "tray", NULL, gettext_noop ("start in tray mode"), 0, &GNUNET_GETOPT_set_one, &tray_only}, GNUNET_GETOPT_OPTION_END }; start_time = GNUNET_TIME_absolute_get (); if (GNUNET_OK != GNUNET_GTK_main_loop_start ("gnunet-statistics-gtk", "GTK GUI for viewing GNUnet statistics", argc, argv, options, "gnunet_statistics_gtk_main_window.glade", &run)) return 1; return 0; } /* end of gnunet-statistics-gtk.c */