/* This file is part of GNUnet 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. Portions of this code were adopted from the gnome-system-monitor v2.0.5, (C) 2001 Kevin Vandersloot Todo: - add any more StatEntries, update menu accordingly. */ #include "gnunet_afs_esed2.h" #include "statistics.h" #include "helper.h" #include "main.h" #include #define UPDATE_INTERVAL (30 * cronSECONDS) typedef struct { char * statName; long long value; long long lvalue; cron_t delta; } StatPair; static StatPair * lastStatValues; static unsigned int lsv_size; static cron_t lastUpdate; static Mutex lock; static void updateStatValues(GNUNET_TCP_SOCKET * sock) { STATS_CS_MESSAGE * statMsg; CS_HEADER csHdr; unsigned int count; unsigned int i; int j; int mpos; int found; char * optName; cron_t now; cron_t prev; cronTime(&now); MUTEX_LOCK(&lock); if (now - lastUpdate < UPDATE_INTERVAL) { MUTEX_UNLOCK(&lock); return; } prev = lastUpdate; lastUpdate = now; csHdr.size = htons(sizeof(CS_HEADER)); csHdr.tcpType = htons(STATS_CS_PROTO_GET_STATISTICS); if (SYSERR == writeToSocket(sock, &csHdr)) { MUTEX_UNLOCK(&lock); return; } statMsg = MALLOC(MAX_BUFFER_SIZE); statMsg->totalCounters = htonl(1); /* to ensure we enter the loop */ count = 0; while ( count < ntohl(statMsg->totalCounters) ) { if (SYSERR == readFromSocket(sock, (CS_HEADER**)&statMsg)) { FREE(statMsg); MUTEX_UNLOCK(&lock); return; } if (ntohs(statMsg->header.size) < sizeof(STATS_CS_MESSAGE)) { BREAK(); break; } mpos = sizeof(unsigned long long) * ntohl(statMsg->statCounters); if ( ((char*)(((STATS_CS_MESSAGE_GENERIC*)statMsg)->values)) [ntohs(statMsg->header.size) - sizeof(STATS_CS_MESSAGE) - 1] != '\0') { BREAK(); break; } for (i=0;istatCounters);i++) { optName = &((char*)(((STATS_CS_MESSAGE_GENERIC*)statMsg)->values))[mpos]; if ( (mpos > ntohs(statMsg->header.size) - sizeof(STATS_CS_MESSAGE)) || (mpos + strlen(optName) + 1 > ntohs(statMsg->header.size) - sizeof(STATS_CS_MESSAGE)) ) { BREAK(); break; /* out of bounds! */ } found = -1; for (j=0;jvalues[i]); lastStatValues[found].delta = now-prev; mpos += strlen(optName)+1; } count += ntohl(statMsg->statCounters); } /* end while */ FREE(statMsg); MUTEX_UNLOCK(&lock); } static int getStatValue(long long * value, long long * lvalue, cron_t * dtime, GNUNET_TCP_SOCKET * sock, const char * optName) { unsigned int i; *value = 0; if (lvalue != NULL) *lvalue = 0; updateStatValues(sock); MUTEX_LOCK(&lock); for (i=0;i" } }; static gint statWindowMenuItems = sizeof (statWindowMenu) / sizeof (statWindowMenu[0]); /** */ static void addClosePopupMenu(GtkWidget * widget) { GtkWidget * menu; GtkItemFactory * popupFactory; popupFactory = gtk_item_factory_new(GTK_TYPE_MENU, "
", NULL); gtk_item_factory_create_items(popupFactory, statWindowMenuItems, statWindowMenu, NULL); menu = gtk_item_factory_get_widget(popupFactory, "
"); gtk_signal_connect(GTK_OBJECT(widget), "button_press_event", GTK_SIGNAL_FUNC(popupCallback), menu); } typedef struct { gint type; guint count; guint speed; guint draw_width, draw_height; guint num_points; guint allocated; GdkColor *colors; gfloat **data, **odata; guint data_size; gint colors_allocated; GtkWidget *main_widget; GtkWidget *disp; GtkWidget *label; GdkPixmap *pixmap; GdkGC *gc; int timer_index; gboolean draw; GNUNET_TCP_SOCKET * sock; int statIdx; } LoadGraph; #define MAX_COLOR 4 typedef struct { gint graph_update_interval; GdkColor bg_color; GdkColor frame_color; GdkColor mem_color[MAX_COLOR]; } ProcConfig; typedef struct ProcData { ProcConfig config; LoadGraph *mem_graph; int statIdx; } ProcData; #define GNOME_PAD_SMALL 2 #define FRAME_WIDTH 0 /** * Redraws the backing pixmap for the load graph and updates the window */ static void load_graph_draw(LoadGraph *g) { guint i; guint j; gint dely; float delx; if (!g->disp->window) return; g->draw_width = g->disp->allocation.width; g->draw_height = g->disp->allocation.height; if (!g->pixmap) g->pixmap = gdk_pixmap_new (g->disp->window, g->draw_width, g->draw_height, gtk_widget_get_visual (g->disp)->depth); /* Create GC if necessary. */ if (!g->gc) { g->gc = gdk_gc_new (g->disp->window); gdk_gc_copy (g->gc, g->disp->style->white_gc); } /* Allocate colors. */ if (!g->colors_allocated) { GdkColormap *colormap; colormap = gdk_window_get_colormap (g->disp->window); for (i=0;i<2+g->count;i++) gdk_color_alloc (colormap, &(g->colors [i])); g->colors_allocated = 1; } /* Erase Rectangle */ gdk_gc_set_foreground (g->gc, &(g->colors [0])); gdk_draw_rectangle (g->pixmap, g->gc, TRUE, 0, 0, g->disp->allocation.width, g->disp->allocation.height); /* draw frame */ gdk_gc_set_foreground (g->gc, &(g->colors [1])); gdk_draw_rectangle (g->pixmap, g->gc, FALSE, 0, 0, g->draw_width, g->disp->allocation.height); dely = g->draw_height / 5; for (i = 1; i <5; i++) { gint y1 = g->draw_height + 1 - i * dely; gdk_draw_line (g->pixmap, g->gc, 0, y1, g->draw_width, y1); } gdk_gc_set_line_attributes (g->gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER ); delx = (float)g->draw_width / ( g->num_points - 1); for (j=0;jcount;j++) { gdk_gc_set_foreground (g->gc, &(g->colors [j + 2])); for (i = 0; i < g->num_points - 1; i++) { gint x1 = i * delx; gint x2 = (i + 1) * delx; gint y1 = g->data[i][j] * g->draw_height - 1; gint y2 = g->data[i+1][j] * g->draw_height - 1; if ((g->data[i][j] != -1) && (g->data[i+1][j] != -1)) { if (stats[g->statIdx].fill == NO) { gdk_draw_line(g->pixmap, g->gc, g->draw_width - x2, g->draw_height - y2, g->draw_width - x1, g->draw_height - y1); } else { GdkPoint points[4]; points[0].x = g->draw_width - x2; points[0].y = g->draw_height - y2; points[1].x = g->draw_width - x1; points[1].y = g->draw_height - y1; points[2].x = g->draw_width - x1; points[3].x = g->draw_width - x2; if (j == 0) { points[2].y = g->draw_height; points[3].y = g->draw_height; } else { gint ly1 = g->data[i][j-1] * g->draw_height - 1; gint ly2 = g->data[i+1][j-1] * g->draw_height - 1; points[2].y = g->draw_height - ly1; points[3].y = g->draw_height - ly2; } gdk_draw_polygon(g->pixmap, g->gc, 1, points, 4); } } } } gdk_gc_set_line_attributes (g->gc, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER ); gdk_draw_pixmap (g->disp->window, g->disp->style->fg_gc [GTK_WIDGET_STATE(g->disp)], g->pixmap, 0, 0, 0, 0, g->disp->allocation.width, g->disp->allocation.height); } /* Updates the load graph when the timeout expires */ static int load_graph_update(LoadGraph *g) { guint i; guint j; for (i=0;inum_points;i++) memcpy(g->odata[i], g->data[i], g->data_size * g->count); stats[g->statIdx].getData(g->sock, stats[g->statIdx].get_closure, g->data); for (i=0;inum_points-1;i++) for (j=0;jcount;j++) g->data[i+1][j] = g->odata[i][j]; if (g->draw) load_graph_draw (g); return TRUE; } static void load_graph_unalloc (LoadGraph *g) { int i; if (!g->allocated) return; for (i = 0; i < g->num_points; i++) { FREE(g->data[i]); FREE(g->odata[i]); } FREE(g->data); FREE(g->odata); g->data = g->odata = NULL; if (g->pixmap) { gdk_pixmap_unref(g->pixmap); g->pixmap = NULL; } g->allocated = FALSE; } static void load_graph_alloc (LoadGraph *g) { int i; int j; if (g->allocated) return; g->data = MALLOC(sizeof(gfloat *) * g->num_points); g->odata = MALLOC(sizeof(gfloat*) * g->num_points); g->data_size = sizeof (gfloat); for (i = 0; i < g->num_points; i++) { g->data[i] = MALLOC(g->data_size * g->count); g->odata[i] = MALLOC(g->data_size * g->count); } for (i=0;inum_points;i++) for (j=0;jcount;j++) g->data[i][j] = -1; g->allocated = TRUE; } static gint load_graph_configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data_ptr) { LoadGraph *c = (LoadGraph *) data_ptr; if (c->pixmap) { gdk_pixmap_unref (c->pixmap); c->pixmap = NULL; } if (!c->pixmap) c->pixmap = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, gtk_widget_get_visual (c->disp)->depth); gdk_draw_rectangle (c->pixmap, widget->style->black_gc, TRUE, 0,0, widget->allocation.width, widget->allocation.height); gdk_draw_pixmap (widget->window, c->disp->style->fg_gc [GTK_WIDGET_STATE(widget)], c->pixmap, 0, 0, 0, 0, c->disp->allocation.width, c->disp->allocation.height); load_graph_draw (c); return TRUE; } static gint load_graph_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data_ptr) { LoadGraph *g = (LoadGraph *) data_ptr; gdk_draw_pixmap (widget->window, widget->style->fg_gc [GTK_WIDGET_STATE(widget)], g->pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } static void load_graph_stop (LoadGraph *g) { if (g->timer_index != -1) { gtk_timeout_remove (g->timer_index); g->timer_index = -1; } if (!g) return; g->draw = FALSE; } static void load_graph_destroy(GtkWidget *widget, gpointer data_ptr) { LoadGraph *g = (LoadGraph *) data_ptr; load_graph_stop(g); if (g->timer_index != -1) gtk_timeout_remove (g->timer_index); if (g->sock != NULL) releaseClientSocket(g->sock); load_graph_unalloc(g); FREE(g->colors); FREE(g); } static LoadGraph * load_graph_new(ProcData *procdata) { LoadGraph *g; unsigned int i; if ( (procdata->statIdx < 0) || (procdata->statIdx >= STATS_COUNT) ) { BREAK(); return NULL; } if (stats[procdata->statIdx].count > MAX_COLOR) { BREAK(); return NULL; } g = MALLOC(sizeof(LoadGraph)); g->sock = getClientSocket(); g->statIdx = procdata->statIdx; g->count = stats[g->statIdx].count; g->speed = procdata->config.graph_update_interval; g->num_points = 600; g->colors = MALLOC(sizeof(GdkColor) * (2+g->count)); g->colors[0] = procdata->config.bg_color; g->colors[1] = procdata->config.frame_color; for (i=0;icount;i++) g->colors[2+i] = procdata->config.mem_color[i]; g->timer_index = -1; g->draw = FALSE; g->main_widget = gtk_vbox_new (FALSE, FALSE); gtk_widget_show (g->main_widget); g->disp = gtk_drawing_area_new(); gtk_widget_show (g->disp); gtk_signal_connect (GTK_OBJECT (g->disp), "expose_event", GTK_SIGNAL_FUNC (load_graph_expose), g); gtk_signal_connect (GTK_OBJECT(g->disp), "configure_event", GTK_SIGNAL_FUNC (load_graph_configure), g); gtk_signal_connect (GTK_OBJECT(g->disp), "destroy", GTK_SIGNAL_FUNC (load_graph_destroy), g); gtk_widget_add_events(g->disp, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); gtk_box_pack_start(GTK_BOX (g->main_widget), g->disp, TRUE, TRUE, 0); load_graph_alloc(g); gtk_widget_show_all (g->main_widget); g->timer_index = gtk_timeout_add(g->speed, (GtkFunction) load_graph_update, g); return g; } static void load_graph_start(LoadGraph *g) { if (!g) return; if (g->timer_index == -1) g->timer_index = gtk_timeout_add(g->speed, (GtkFunction) load_graph_update, g); g->draw = TRUE; } static GtkWidget * create_sys_view(ProcData * procdata) { GtkWidget * mem_frame; LoadGraph * mem_graph; mem_graph = load_graph_new(procdata); procdata->mem_graph = mem_graph; if (mem_graph == NULL) return NULL; /* oops */ mem_frame = gtk_frame_new(_(stats[procdata->statIdx].frameName)); gtk_container_add(GTK_CONTAINER(mem_frame), mem_graph->main_widget); gtk_container_set_border_width(GTK_CONTAINER(mem_graph->main_widget), GNOME_PAD_SMALL); gtk_container_set_border_width (GTK_CONTAINER(mem_frame), GNOME_PAD_SMALL); gtk_widget_show(mem_frame); addClosePopupMenu(mem_frame); return mem_frame; } static GtkWidget * create_main_window(int stat) { GtkWidget *sys_box; ProcData procdata; memset(&procdata, 0, sizeof(ProcData)); procdata.config.graph_update_interval = UPDATE_INTERVAL / cronMILLIS; procdata.statIdx = stat; gdk_color_parse("black", &procdata.config.bg_color); gdk_color_parse("gray", &procdata.config.frame_color); gdk_color_parse("red", &procdata.config.mem_color[0]); gdk_color_parse("green", &procdata.config.mem_color[1]); gdk_color_parse("yellow", &procdata.config.mem_color[2]); gdk_color_parse("blue", &procdata.config.mem_color[3]); GNUNET_ASSERT(MAX_COLOR == 4); sys_box = create_sys_view(&procdata); if (sys_box == NULL) return NULL; load_graph_start(procdata.mem_graph); return sys_box; } /** * Display the statistics. */ void displayStatistics(GtkWidget * widget, gpointer data) { int dptr; GtkWidget * wid; dptr = (int) data; if ( (dptr < 0) || (dptr >= STATS_COUNT) ) { BREAK(); } else { wid = create_main_window(dptr); if (wid != NULL) addToNotebook(_(stats[dptr].paneName), wid); } } void initGTKStatistics() { MUTEX_CREATE_RECURSIVE(&lock); } void doneGTKStatistics() { unsigned int i; for (i=0;i