2 * TCP graph drawing code
3 * By Pavel Mores <pvl@uh.cz>
4 * Win32 port: rwh@unifiedtech.com
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <gdk/gdkkeysyms.h>
36 #include <epan/ipproto.h>
38 #include <epan/packet.h>
39 #include <epan/emem.h>
40 #include <epan/etypes.h>
41 #include <epan/ppptypes.h>
42 #include <epan/epan_dissect.h>
43 #include <epan/dissectors/packet-tcp.h>
44 #include <epan/address.h>
47 #include "../globals.h"
48 #include "../simple_dialog.h"
50 #include "../stat_menu.h"
52 #include "gtk/gui_utils.h"
53 #include "gtk/dlg_utils.h"
54 #include "gtk/gui_stat_menu.h"
64 #define TCP_SYN(flags) ( flags & TH_SYN )
65 #define TCP_ACK(flags) ( flags & TH_ACK )
66 #define TCP_FIN(flags) ( flags & TH_FIN )
69 #define TXT_HEIGHT 550
71 /* for compare_headers() */
72 /* segment went the same direction as the currently selected one */
73 #define COMPARE_CURR_DIR 0
74 #define COMPARE_ANY_DIR 1
76 /* initalize_axis() */
77 #define AXIS_HORIZONTAL 0
78 #define AXIS_VERTICAL 1
92 guint32 th_win; /* make it 32 bits so we can handle some scaling */
101 double x, y, width, height;
105 double x1, y1, x2, y2;
109 int x, y, width, height;
141 struct segment *parent;
143 struct arc_params arc;
144 struct rect_params rect;
145 struct line_params line;
149 struct element_list {
150 struct element_list *next;
151 struct element *elements;
155 struct graph *g; /* which graph we belong to */
156 GtkWidget *drawing_area;
157 GdkPixmap *pixmap[2];
159 #define AXIS_ORIENTATION 1 << 0
161 /* dim and orig (relative to origin of window) of axis' pixmap */
163 /* dim and orig (relative to origin of axis' pixmap) of scale itself */
166 gdouble major, minor; /* major and minor ticks */
170 #define HAXIS_INIT_HEIGHT 70
171 #define VAXIS_INIT_WIDTH 100
172 #define TITLEBAR_HEIGHT 50
173 #define RMARGIN_WIDTH 30
175 struct style_tseq_tcptrace {
181 struct style_tseq_stevens {
199 #define SEQ_ORIGIN 0x1
200 /* show absolute sequence numbers (not differences from isn) */
201 #define SEQ_ORIGIN_ZERO 0x1
202 #define SEQ_ORIGIN_ISN 0x0
203 #define TIME_ORIGIN 0x10
204 /* show time from beginning of capture as opposed to time from beginning
205 * of the connection */
206 #define TIME_ORIGIN_CAP 0x10
207 #define TIME_ORIGIN_CONN 0x0
209 /* this is used by rtt module only */
218 int draw; /* indicates whether we should draw cross at all */
220 GtkToggleButton *on_toggle;
221 GtkToggleButton *off_toggle;
225 double x0, y0, width, height;
234 double step_x, step_y;
236 #define ZOOM_OUT (1 << 0)
237 #define ZOOM_HLOCK (1 << 1)
238 #define ZOOM_VLOCK (1 << 2)
239 #define ZOOM_STEPS_SAME (1 << 3)
240 #define ZOOM_STEPS_KEEP_RATIO (1 << 4)
242 /* unfortunately, we need them both because gtk_toggle_button_set_active ()
243 * with second argument FALSE doesn't do anything, somehow */
245 GtkToggleButton *in_toggle;
246 GtkToggleButton *out_toggle;
249 GtkSpinButton *h_step;
250 GtkSpinButton *v_step;
262 struct ipoint offset;
266 #define MAGZOOMS_SAME (1U << 0)
267 #define MAGZOOMS_SAME_RATIO (1U << 1)
268 #define MAGZOOMS_IGNORE (1U << 31)
271 GtkSpinButton *h_zoom, *v_zoom;
277 #define GRAPH_TSEQ_STEVENS 0
278 #define GRAPH_TSEQ_TCPTRACE 1
279 #define GRAPH_THROUGHPUT 2
282 #define GRAPH_DESTROYED (1 << 0)
283 #define GRAPH_INIT_ON_TYPE_CHANGE (1 << 1)
285 GtkWidget *toplevel; /* keypress handler needs this */
286 GtkWidget *drawing_area;
287 GtkWidget *text; /* text widget for seg list - probably
289 PangoFontDescription *font; /* font used for annotations etc. */
292 GdkPixmap *title_pixmap;
293 GdkPixmap *pixmap[2];
294 int displayed; /* which of both pixmaps is on screen right now */
296 GtkWidget *control_panel;
297 /* this belongs to style structs of graph types that make use of it */
298 GtkToggleButton *time_orig_conn, *seq_orig_isn;
301 /* Next 4 attribs describe the graph in natural units, before any scaling.
302 * For example, if we want to display graph of TCP conversation that
303 * started 112.309845 s after beginning of the capture and ran until
304 * 479.093582 s, 237019 B went through the connection (in one direction)
305 * starting with isn 31934022, then (bounds.x0, bounds.y0)=(112.309845,
306 * 31934022) and (bounds.width, bounds.height)=(366.783737, 237019). */
307 struct bounds bounds;
308 /* dimensions and position of the graph, both expressed already in pixels.
309 * x and y give the position of upper left corner of the graph relative
310 * to origin of the graph window, size is basically bounds*zoom */
312 /* viewport (=graph window area which is reserved for graph itself), its
313 * size and position relative to origin of the graph window */
316 /* If we need to display 237019 sequence numbers (=bytes) onto say 500
317 * pixels, we have to scale the graph down by factor of 0.002109. This
318 * number would be zoom.y. Obviously, both directions have separate zooms.*/
321 struct magnify magnify;
322 struct axis *x_axis, *y_axis;
323 struct segment *segments;
324 struct segment *current;
325 struct element_list *elists; /* element lists */
327 struct style_tseq_stevens tseq_stevens;
328 struct style_tseq_tcptrace tseq_tcptrace;
329 struct style_tput tput;
330 struct style_rtt rtt;
334 static GdkGC *xor_gc = NULL;
337 #define debug(section) if (debugging & section)
338 /* print function entry points */
339 #define DBS_FENTRY (1 << 0)
340 #define DBS_AXES_TICKS (1 << 1)
341 #define DBS_AXES_DRAWING (1 << 2)
342 #define DBS_GRAPH_DRAWING (1 << 3)
343 #define DBS_TPUT_ELMTS (1 << 4)
344 /*int debugging = DBS_FENTRY;*/
345 static int debugging = 0;
346 /*int debugging = DBS_AXES_TICKS;*/
347 /*int debugging = DBS_AXES_DRAWING;*/
348 /*int debugging = DBS_GRAPH_DRAWING;*/
349 /*int debugging = DBS_TPUT_ELMTS;*/
351 static void create_gui (struct graph * );
353 static void create_text_widget (struct graph * );
354 static void display_text (struct graph * );
356 static void create_drawing_area (struct graph * );
357 static void control_panel_create (struct graph * );
358 static GtkWidget *control_panel_create_zoom_group (struct graph * );
359 static GtkWidget *control_panel_create_magnify_group (struct graph * );
360 static GtkWidget *control_panel_create_cross_group (struct graph * );
361 static GtkWidget *control_panel_create_zoomlock_group (struct graph * );
362 static GtkWidget *control_panel_create_graph_type_group (struct graph * );
363 static void control_panel_add_zoom_page (struct graph * , GtkWidget * );
364 static void control_panel_add_magnify_page (struct graph * , GtkWidget * );
365 static void control_panel_add_origin_page (struct graph * , GtkWidget * );
366 static void control_panel_add_cross_page (struct graph * , GtkWidget * );
367 static void control_panel_add_graph_type_page (struct graph * , GtkWidget * );
368 static void callback_toplevel_destroy (GtkWidget * , gpointer );
369 static gboolean callback_delete_event(GtkWidget * , GdkEvent * , gpointer);
370 static void callback_close (GtkWidget * , gpointer );
371 static void callback_time_origin (GtkWidget * , gpointer );
372 static void callback_seq_origin (GtkWidget * , gpointer );
373 static void callback_zoomlock_h (GtkWidget * , gpointer );
374 static void callback_zoomlock_v (GtkWidget * , gpointer );
375 static void callback_zoom_inout (GtkWidget * , gpointer );
376 static void callback_zoom_step (GtkWidget * , gpointer );
377 static void callback_zoom_flags (GtkWidget * , gpointer );
378 static void callback_cross_on_off (GtkWidget * , gpointer );
379 static void callback_mag_width (GtkWidget * , gpointer );
380 static void callback_mag_height (GtkWidget * , gpointer );
381 static void callback_mag_x (GtkWidget * , gpointer );
382 static void callback_mag_y (GtkWidget * , gpointer );
383 static void callback_mag_zoom (GtkWidget * , gpointer );
384 static void callback_mag_flags (GtkWidget * , gpointer );
385 static void callback_graph_type (GtkWidget * , gpointer );
386 static void callback_graph_init_on_typechg (GtkWidget * , gpointer );
387 static void callback_create_help (GtkWidget * , gpointer );
388 static void update_zoom_spins (struct graph * );
389 static struct tcpheader *select_tcpip_session (capture_file *, struct segment * );
390 static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, address *saddr2, address *daddr2, guint16 sport2, guint16 dport2, int dir);
391 static int get_num_dsegs (struct graph * );
392 static int get_num_acks (struct graph * );
393 static void graph_type_dependent_initialize (struct graph * );
394 static struct graph *graph_new (void);
395 static void graph_destroy (struct graph * );
396 static void graph_initialize_values (struct graph * );
397 static void graph_init_sequence (struct graph * );
398 static void draw_element_line (struct graph * , struct element * );
399 static void draw_element_arc (struct graph * , struct element * );
400 static void graph_display (struct graph * );
401 static void graph_pixmaps_create (struct graph * );
402 static void graph_pixmaps_switch (struct graph * );
403 static void graph_pixmap_draw (struct graph * );
404 static void graph_pixmap_display (struct graph * );
405 static void graph_element_lists_make (struct graph * );
406 static void graph_element_lists_free (struct graph * );
407 static void graph_element_lists_initialize (struct graph * );
408 static void graph_title_pixmap_create (struct graph * );
409 static void graph_title_pixmap_draw (struct graph * );
410 static void graph_title_pixmap_display (struct graph * );
411 static void graph_segment_list_get (struct graph * );
412 static void graph_segment_list_free (struct graph * );
413 static void graph_select_segment (struct graph * , int , int );
414 static int line_detect_collision (struct element * , int , int );
415 static int arc_detect_collision (struct element * , int , int );
416 static void axis_pixmaps_create (struct axis * );
417 static void axis_pixmaps_switch (struct axis * );
418 static void axis_display (struct axis * );
419 static void v_axis_pixmap_draw (struct axis * );
420 static void h_axis_pixmap_draw (struct axis * );
421 static void axis_pixmap_display (struct axis * );
422 static void axis_compute_ticks (struct axis * , double , double , int );
423 static double axis_zoom_get (struct axis * , int );
424 static void axis_ticks_up (int * , int * );
425 static void axis_ticks_down (int * , int * );
426 static void axis_destroy (struct axis * );
427 static int get_label_dim (struct axis * , int , double );
428 static void toggle_time_origin (struct graph * );
429 static void toggle_seq_origin (struct graph * );
430 static void cross_xor (struct graph * , int , int );
431 static void cross_draw (struct graph * , int , int );
432 static void cross_erase (struct graph * );
433 static void magnify_create (struct graph * , int , int );
434 static void magnify_move (struct graph * , int , int );
435 static void magnify_destroy (struct graph * );
436 static void magnify_draw (struct graph * );
437 static void magnify_get_geom (struct graph * , int , int );
438 static gint configure_event (GtkWidget * , GdkEventConfigure * );
439 static gint expose_event (GtkWidget * , GdkEventExpose * );
440 static gint button_press_event (GtkWidget * , GdkEventButton * );
441 static gint button_release_event (GtkWidget * , GdkEventButton * );
442 static gint motion_notify_event (GtkWidget * , GdkEventMotion * );
443 static gint key_press_event (GtkWidget * , GdkEventKey * );
444 static gint key_release_event (GtkWidget * , GdkEventKey * );
445 static gint leave_notify_event (GtkWidget * , GdkEventCrossing * );
446 static gint enter_notify_event (GtkWidget * , GdkEventCrossing * );
447 static void tseq_initialize (struct graph * );
448 static void tseq_get_bounds (struct graph * );
449 static void tseq_stevens_read_config (struct graph * );
450 static void tseq_stevens_make_elmtlist (struct graph * );
451 static void tseq_stevens_toggle_seq_origin (struct graph * );
452 static void tseq_stevens_toggle_time_origin (struct graph * );
453 static void tseq_tcptrace_read_config (struct graph * );
454 static void tseq_tcptrace_make_elmtlist (struct graph * );
455 static void tseq_tcptrace_toggle_seq_origin (struct graph * );
456 static void tseq_tcptrace_toggle_time_origin (struct graph * );
457 static void tput_initialize (struct graph * );
458 static void tput_read_config (struct graph * );
459 static void tput_make_elmtlist (struct graph * );
460 static void tput_toggle_time_origin (struct graph * );
461 static void rtt_read_config (struct graph * );
462 static void rtt_initialize (struct graph * );
463 static int rtt_is_retrans (struct unack * , unsigned int );
464 static struct unack *rtt_get_new_unack (double , unsigned int );
465 static void rtt_put_unack_on_list (struct unack ** , struct unack * );
466 static void rtt_delete_unack_from_list (struct unack ** , struct unack * );
467 static void rtt_make_elmtlist (struct graph * );
468 static void rtt_toggle_seq_origin (struct graph * );
469 #if defined(_WIN32) && !defined(__MINGW32__)
470 static int rint (double ); /* compiler template for Windows */
473 /* XXX - what about OS X? */
474 static char helptext[] =
476 "Here's what you can do:\n\
477 - Left Mouse Button selects segment in Wireshark's packet list\n\
478 - Middle Mouse Button zooms in\n\
479 - <shift>-Middle Button zooms out\n\
480 - Right Mouse Button moves the graph (if zoomed in)\n\
481 - <ctrl>-Right Mouse Button displays a portion of graph magnified\n\
482 - Space toggles crosshairs\n\
483 - 's' toggles relative/absolute sequence numbers\n\
484 - 't' toggles time origin\n\
487 "Here's what you can do:\n\
488 - <ctrl>-Left Mouse Button selects segment in Wireshark's packet list\n\
489 - Left Mouse Button zooms in\n\
490 - <shift>-Left Mouse Button zooms out\n\
491 - Right Mouse Button moves the graph (if zoomed in)\n\
492 - <ctrl>-Right Mouse Button displays a portion of graph magnified\n\
494 - Space bar toggles crosshairs\n\
495 - 's' - Toggles relative/absolute sequence numbers\n\
496 - 't' - Toggles time origin\n\
500 static void tcp_graph_cb (GtkWidget *w _U_, gpointer data, guint callback_action /*graph_type*/ _U_)
502 struct segment current;
504 struct tcpheader *thdr;
506 guint graph_type = GPOINTER_TO_INT(data);
508 debug(DBS_FENTRY) puts ("tcp_graph_cb()");
510 if (! (g = graph_new()))
514 graph_initialize_values (g);
516 g->type = graph_type;
517 if (!(thdr=select_tcpip_session (&cfile, ¤t))) {
521 graph_segment_list_get(g);
523 /* display_text(g); */
524 graph_init_sequence(g);
527 static void create_gui (struct graph *g)
529 debug(DBS_FENTRY) puts ("create_gui()");
530 /* create_text_widget(g); */
531 control_panel_create (g);
532 create_drawing_area(g);
536 static void create_text_widget (struct graph *g)
538 GtkWidget *streamwindow, *txt_scrollw, *box;
540 debug(DBS_FENTRY) puts ("create_text_widget()");
541 streamwindow = dlg_window_new ("Wireshark: Packet chain");
542 gtk_widget_set_name (streamwindow, "Packet chain");
543 gtk_widget_set_size_request(streamwindow, TXT_WIDTH, TXT_HEIGHT);
544 gtk_container_border_width (GTK_CONTAINER(streamwindow), 2);
546 box = gtk_vbox_new (FALSE, 0);
547 gtk_container_add (GTK_CONTAINER (streamwindow), box);
548 gtk_widget_show (box);
550 txt_scrollw = scrolled_window_new (NULL, NULL);
551 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scrollw),
553 gtk_box_pack_start (GTK_BOX (box), txt_scrollw, TRUE, TRUE, 0);
554 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (txt_scrollw),
555 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
556 gtk_widget_show (txt_scrollw);
558 g->text = gtk_text_view_new();
559 gtk_text_view_set_editable(GTK_TEXT_VIEW(g->text), FALSE);
560 gtk_container_add (GTK_CONTAINER (txt_scrollw), g->text);
561 gtk_widget_show (g->text);
562 gtk_widget_show (streamwindow);
564 static void display_text (struct graph *g)
568 double first_time, prev_time;
569 unsigned int isn_this=0, isn_opposite=0, seq_this_prev, seq_opposite_prev;
574 debug(DBS_FENTRY) puts ("display_text()");
575 if (!gdk_color_parse ("SlateGray", &color)) {
577 * XXX - do more than just warn.
579 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
580 "Could not parse color SlateGray.");
582 g_snprintf ((char * )line, 256, "%10s%15s%15s%15s%15s%15s%15s%10s\n",
583 "pkt num", "time", "delta first", "delta prev",
584 "seqno", "delta first", "delta prev", "data (B)");
585 gtk_text_insert (GTK_TEXT (g->text), g->font, NULL, NULL,
586 (const char *)line, -1);
588 first_time = g->segments->rel_secs + g->segments->rel_usecs/1000000.0;
589 prev_time = first_time;
590 /* we have to find Initial Sequence Number for both ends of connection */
591 for (ptr=g->segments; ptr; ptr=ptr->next) {
592 if (compare_headers (g->current, ptr, COMPARE_CURR_DIR)) {
593 isn_this = ptr->th_seq;
597 for (ptr=g->segments; ptr; ptr=ptr->next) {
598 if (!compare_headers (g->current, ptr, COMPARE_CURR_DIR)) {
599 isn_opposite = ptr->th_seq;
603 seq_this_prev = isn_this;
604 seq_opposite_prev = isn_opposite;
605 for (ptr=g->segments; ptr; ptr=ptr->next) {
606 double time=ptr->rel_secs + ptr->rel_usecs/1000000.0;
607 unsigned int seq = ptr->th_seq;
608 int seq_delta_isn, seq_delta_prev;
610 if (compare_headers (g->current, ptr, COMPARE_CURR_DIR)) {
611 seq_delta_isn = seq - isn_this;
612 seq_delta_prev = seq - seq_this_prev;
616 seq_delta_isn = seq - isn_opposite;
617 seq_delta_prev = seq - seq_opposite_prev;
618 seq_opposite_prev = seq;
621 g_snprintf ((char *)line, 256, "%10d%15.6f%15.6f%15.6f%15u%15d%15d%10u\n",
622 ptr->num, time, time-first_time, time-prev_time,
623 seq, seq_delta_isn, seq_delta_prev,
625 gtk_text_buffer_insert(buf, &iter, (const char *)line, -1);
631 static void create_drawing_area (struct graph *g)
633 GdkColormap *colormap;
635 #define WINDOW_TITLE_LENGTH 64
636 char window_title[WINDOW_TITLE_LENGTH];
637 struct segment current;
638 struct tcpheader *thdr;
640 debug(DBS_FENTRY) puts ("create_drawing_area()");
642 g->font = gdk_font_load ("-sony-fixed-medium-r-normal--16-150-75-75"
644 g->font = gdk_font_load ("-biznet-fotinostypewriter-medium-r-normal-*-*-120"
645 "-*-*-m-*-iso8859-2");
647 thdr=select_tcpip_session (&cfile, ¤t);
648 g_snprintf (window_title, WINDOW_TITLE_LENGTH, "TCP Graph %d: %s %s:%d -> %s:%d",
650 cf_get_display_name(&cfile),
651 address_to_str(&(thdr->ip_src)),
653 address_to_str(&(thdr->ip_dst)),
656 g->toplevel = dlg_window_new ("Tcp Graph");
657 gtk_window_set_title(GTK_WINDOW(g->toplevel), window_title);
658 gtk_widget_set_name (g->toplevel, "Test Graph");
659 g_object_set_data(G_OBJECT(g->toplevel), "graph", g);
661 /* Create the drawing area */
662 g->drawing_area = gtk_drawing_area_new ();
663 g_object_set_data(G_OBJECT(g->drawing_area), "graph", g);
664 g->x_axis->drawing_area = g->y_axis->drawing_area = g->drawing_area;
665 gtk_drawing_area_size (GTK_DRAWING_AREA (g->drawing_area),
666 g->wp.width + g->wp.x + RMARGIN_WIDTH,
667 g->wp.height + g->wp.y + g->x_axis->s.height);
668 gtk_widget_show (g->drawing_area);
670 g_signal_connect(g->drawing_area, "expose_event", G_CALLBACK(expose_event), NULL);
671 /* this has to be done later, after the widget has been shown */
673 g_signal_connect(g->drawing_area,"configure_event", G_CALLBACK(configure_event),
676 g_signal_connect(g->drawing_area, "motion_notify_event",
677 G_CALLBACK(motion_notify_event), NULL);
678 g_signal_connect(g->drawing_area, "button_press_event",
679 G_CALLBACK(button_press_event), NULL);
680 g_signal_connect(g->drawing_area, "button_release_event",
681 G_CALLBACK(button_release_event), NULL);
682 g_signal_connect(g->drawing_area, "leave_notify_event",
683 G_CALLBACK(leave_notify_event), NULL);
684 g_signal_connect(g->drawing_area, "enter_notify_event",
685 G_CALLBACK(enter_notify_event), NULL);
686 g_signal_connect(g->toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g);
687 /* why doesn't drawing area send key_press_signals? */
688 g_signal_connect(g->toplevel, "key_press_event", G_CALLBACK(key_press_event), NULL);
689 g_signal_connect(g->toplevel, "key_release_event", G_CALLBACK(key_release_event),
691 gtk_widget_set_events(g->toplevel,
692 GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
694 gtk_widget_set_events (g->drawing_area,
696 | GDK_LEAVE_NOTIFY_MASK
697 | GDK_ENTER_NOTIFY_MASK
698 | GDK_BUTTON_PRESS_MASK
699 | GDK_BUTTON_RELEASE_MASK
700 | GDK_POINTER_MOTION_MASK
701 | GDK_POINTER_MOTION_HINT_MASK);
704 frame = gtk_frame_new (NULL);
705 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
706 gtk_container_add (GTK_CONTAINER (frame), g->drawing_area);
708 box = gtk_hbox_new (FALSE, 0);
709 gtk_box_pack_start (GTK_BOX (box), g->gui.control_panel, FALSE, FALSE, 0);
710 gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
711 gtk_container_add (GTK_CONTAINER (g->toplevel), box);
712 gtk_container_set_border_width (GTK_CONTAINER (g->toplevel), 5);
713 gtk_widget_show (frame);
714 gtk_widget_show (box);
717 gtk_container_add (GTK_CONTAINER (g->toplevel), g->drawing_area);
718 gtk_widget_show (g->toplevel);
720 /* in case we didn't get what we asked for */
721 g->wp.width = GTK_WIDGET (g->drawing_area)->allocation.width -
722 g->wp.x - RMARGIN_WIDTH;
723 g->wp.height = GTK_WIDGET (g->drawing_area)->allocation.height -
724 g->wp.y - g->x_axis->s.height;
726 g->font = g->drawing_area->style->font_desc;
728 colormap = gdk_window_get_colormap (g->drawing_area->window);
730 xor_gc = gdk_gc_new (g->drawing_area->window);
731 gdk_gc_set_function (xor_gc, GDK_XOR);
732 if (!gdk_color_parse ("gray15", &color)) {
734 * XXX - do more than just warn.
736 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
737 "Could not parse color gray15.");
739 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
741 * XXX - do more than just warn.
743 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
744 "Could not allocate color gray15.");
746 gdk_gc_set_foreground (xor_gc, &color);
748 g->fg_gc = gdk_gc_new (g->drawing_area->window);
749 g->bg_gc = gdk_gc_new (g->drawing_area->window);
750 if (!gdk_color_parse ("white", &color)) {
752 * XXX - do more than just warn.
754 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
755 "Could not parse color white.");
757 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
759 * XXX - do more than just warn.
761 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
762 "Could not allocate color white.");
764 gdk_gc_set_foreground (g->bg_gc, &color);
766 /* this is probably quite an ugly way to get rid of the first configure
768 * immediatelly after gtk_widget_show (window) drawing_area gets a configure
769 * event which is handled during the next return to gtk_main which is
770 * probably the gdk_gc_new() call. configure handler calls
771 * graph_element_lists_make() which is not good because the graph struct is
772 * not fully set up yet - namely we're not sure about actual geometry
773 * and we don't have the GC's at all. so we just postpone installation
774 * of configure handler until we're ready to deal with it.
776 * !!! NEMÌLO BY TO BÝT NA KONCI graph_init_sequence()? !!!
779 g_signal_connect(g->drawing_area,"configure_event", G_CALLBACK(configure_event),
782 /* puts ("exiting create_drawing_area()"); */
785 static void callback_toplevel_destroy (GtkWidget *widget _U_, gpointer data)
787 struct graph *g = (struct graph * )data;
789 if (!(g->flags & GRAPH_DESTROYED)) {
790 g->flags |= GRAPH_DESTROYED;
791 graph_destroy ((struct graph * )data);
795 static void control_panel_create (struct graph *g)
797 GtkWidget *toplevel, *notebook;
799 GtkWidget *help_bt, *close_bt, *bbox;
800 #define WINDOW_TITLE_LENGTH 64
801 char window_title[WINDOW_TITLE_LENGTH];
803 debug(DBS_FENTRY) puts ("control_panel_create()");
805 notebook = gtk_notebook_new ();
806 control_panel_add_zoom_page (g, notebook);
807 control_panel_add_magnify_page (g, notebook);
808 control_panel_add_origin_page (g, notebook);
809 control_panel_add_cross_page (g, notebook);
810 control_panel_add_graph_type_page (g, notebook);
812 g_snprintf (window_title, WINDOW_TITLE_LENGTH,
813 "Graph %d - Control - Wireshark", refnum);
814 toplevel = dlg_window_new ("tcp-graph-control");
815 gtk_window_set_title(GTK_WINDOW(toplevel), window_title);
817 table = gtk_table_new (2, 1, FALSE);
818 gtk_container_add (GTK_CONTAINER (toplevel), table);
820 gtk_table_attach (GTK_TABLE (table), notebook, 0, 1, 0, 1,
821 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
824 bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_CLOSE, NULL);
825 gtk_table_attach (GTK_TABLE (table), bbox, 0, 1, 1, 2,
826 GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 5);
828 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
829 g_signal_connect(help_bt, "clicked", G_CALLBACK(callback_create_help), g);
831 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
832 window_set_cancel_button(toplevel, close_bt, NULL);
833 g_signal_connect(close_bt, "clicked", G_CALLBACK(callback_close), g);
835 g_signal_connect(toplevel, "delete_event", G_CALLBACK(callback_delete_event), g);
836 g_signal_connect(toplevel, "destroy", G_CALLBACK(callback_toplevel_destroy), g);
838 /* gtk_widget_show_all (table); */
839 /* g->gui.control_panel = table; */
840 gtk_widget_show_all (toplevel);
841 window_present(toplevel);
843 g->gui.control_panel = toplevel;
846 static void control_panel_add_zoom_page (struct graph *g, GtkWidget *n)
848 GtkWidget *zoom_frame;
849 GtkWidget *zoom_lock_frame;
853 zoom_frame = control_panel_create_zoom_group (g);
854 gtk_container_set_border_width (GTK_CONTAINER (zoom_frame), 5);
855 zoom_lock_frame = control_panel_create_zoomlock_group (g);
856 gtk_container_set_border_width (GTK_CONTAINER (zoom_lock_frame), 5);
857 box = gtk_vbox_new (FALSE, 0);
858 gtk_box_pack_start (GTK_BOX (box), zoom_frame, TRUE, TRUE, 0);
859 gtk_box_pack_start (GTK_BOX (box), zoom_lock_frame, TRUE, TRUE, 0);
860 gtk_widget_show (box);
861 label = gtk_label_new ("Zoom");
862 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
865 static void control_panel_add_magnify_page (struct graph *g, GtkWidget *n)
867 GtkWidget *mag_frame, *label;
869 mag_frame = control_panel_create_magnify_group (g);
870 gtk_container_set_border_width (GTK_CONTAINER (mag_frame), 5);
871 label = gtk_label_new ("Magnify");
872 gtk_notebook_append_page (GTK_NOTEBOOK (n), mag_frame, label);
875 static void control_panel_add_origin_page (struct graph *g, GtkWidget *n)
877 GtkWidget *time_orig_cap, *time_orig_conn, *time_orig_box, *time_orig_frame;
878 GtkWidget *seq_orig_isn, *seq_orig_zero, *seq_orig_box, *seq_orig_frame;
879 GtkWidget *box, *label;
881 /* time origin box */
883 gtk_radio_button_new_with_label (NULL, "beginning of capture");
884 time_orig_conn = gtk_radio_button_new_with_label (
885 gtk_radio_button_group (GTK_RADIO_BUTTON (time_orig_cap)),
886 "beginning of this TCP connection");
887 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (time_orig_conn), TRUE);
888 time_orig_box = gtk_vbox_new (TRUE, 0);
889 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_conn, TRUE, TRUE, 0);
890 gtk_box_pack_start (GTK_BOX (time_orig_box), time_orig_cap, TRUE, TRUE, 0);
891 time_orig_frame = gtk_frame_new ("Time origin");
892 gtk_container_set_border_width (GTK_CONTAINER (time_orig_frame), 5);
893 gtk_container_add (GTK_CONTAINER (time_orig_frame), time_orig_box);
895 /* sequence number origin group */
897 gtk_radio_button_new_with_label (NULL, "initial sequence number");
898 seq_orig_zero = gtk_radio_button_new_with_label (gtk_radio_button_group (
899 GTK_RADIO_BUTTON (seq_orig_isn)), "0 (=absolute)");
900 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seq_orig_isn), TRUE);
901 seq_orig_box = gtk_vbox_new (TRUE, 0);
902 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_isn, TRUE, TRUE, 0);
903 gtk_box_pack_start (GTK_BOX (seq_orig_box), seq_orig_zero, TRUE, TRUE, 0);
904 seq_orig_frame = gtk_frame_new ("Sequence number origin");
905 gtk_container_set_border_width (GTK_CONTAINER (seq_orig_frame), 5);
906 gtk_container_add (GTK_CONTAINER (seq_orig_frame), seq_orig_box);
908 g->gui.time_orig_conn = (GtkToggleButton * )time_orig_conn;
909 g->gui.seq_orig_isn = (GtkToggleButton * )seq_orig_isn;
911 g_signal_connect(time_orig_conn, "toggled", G_CALLBACK(callback_time_origin), g);
912 g_signal_connect(seq_orig_isn, "toggled", G_CALLBACK(callback_seq_origin), g);
914 box = gtk_vbox_new (FALSE, 0);
915 gtk_container_set_border_width (GTK_CONTAINER (box), 5);
916 gtk_box_pack_start (GTK_BOX (box), time_orig_frame, TRUE, TRUE, 0);
917 gtk_box_pack_start (GTK_BOX (box), seq_orig_frame, TRUE, TRUE, 0);
918 gtk_widget_show (box);
919 label = gtk_label_new ("Origin");
920 gtk_notebook_append_page (GTK_NOTEBOOK (n), box, label);
923 static void control_panel_add_cross_page (struct graph *g, GtkWidget *n)
925 GtkWidget *cross_frame, *label;
927 cross_frame = control_panel_create_cross_group (g);
928 gtk_container_set_border_width (GTK_CONTAINER (cross_frame), 5);
929 label = gtk_label_new ("Cross");
930 gtk_notebook_append_page (GTK_NOTEBOOK (n), cross_frame, label);
933 static void control_panel_add_graph_type_page (struct graph *g, GtkWidget *n)
935 GtkWidget *frame, *label;
937 frame = control_panel_create_graph_type_group (g);
938 gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
939 label = gtk_label_new ("Graph type");
940 gtk_notebook_append_page (GTK_NOTEBOOK (n), frame, label);
943 /* Treat this as a cancel, by calling "callback_close()" */
945 callback_delete_event(GtkWidget *widget _U_, GdkEvent *event _U_,
948 callback_close(NULL, data);
952 static void callback_close (GtkWidget *widget _U_, gpointer data)
954 struct graph *g = (struct graph * )data;
956 if (!(g->flags & GRAPH_DESTROYED)) {
957 g->flags |= GRAPH_DESTROYED;
958 graph_destroy ((struct graph * )data);
962 static void callback_create_help(GtkWidget *widget _U_, gpointer data _U_)
964 GtkWidget *toplevel, *vbox, *text, *scroll, *bbox, *close_bt;
967 toplevel = dlg_window_new ("Help for TCP graphing");
968 gtk_window_set_default_size(GTK_WINDOW(toplevel), 500, 400);
970 vbox = gtk_vbox_new (FALSE, 3);
971 gtk_container_border_width(GTK_CONTAINER(vbox), 12);
972 gtk_container_add (GTK_CONTAINER (toplevel), vbox);
974 scroll = scrolled_window_new (NULL, NULL);
975 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
977 gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
978 text = gtk_text_view_new();
979 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
980 buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
981 gtk_text_buffer_set_text(buf, helptext, -1);
982 gtk_container_add (GTK_CONTAINER (scroll), text);
985 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
986 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
987 gtk_widget_show(bbox);
989 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
990 window_set_cancel_button(toplevel, close_bt, window_cancel_button_cb);
992 g_signal_connect(toplevel, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
994 gtk_widget_show_all (toplevel);
995 window_present(toplevel);
998 static void callback_time_origin (GtkWidget *toggle _U_, gpointer data)
1000 toggle_time_origin ((struct graph * )data);
1003 static void callback_seq_origin (GtkWidget *toggle _U_, gpointer data)
1005 toggle_seq_origin ((struct graph * )data);
1008 static GtkWidget *control_panel_create_zoom_group (struct graph *g)
1010 GtkWidget *zoom_in, *zoom_out, *zoom_box, *zoom_frame;
1011 GtkAdjustment *zoom_h_adj, *zoom_v_adj;
1012 GtkWidget *zoom_inout_box, *zoom_h_step_label, *zoom_h_step;
1013 GtkWidget *zoom_v_step_label, *zoom_v_step;
1014 GtkWidget *zoom_separator1, *zoom_separator2, *zoom_step_table, *zoom_table;
1015 GtkWidget *zoom_ratio_toggle, *zoom_same_toggle;
1016 GtkWidget *zoom_h_entry, *zoom_v_entry;
1017 GtkWidget *zoom_h_label, *zoom_v_label;
1019 zoom_in = gtk_radio_button_new_with_label (NULL, "in");
1020 zoom_out = gtk_radio_button_new_with_label (
1021 gtk_radio_button_group (GTK_RADIO_BUTTON (zoom_in)), "out");
1022 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_in), TRUE);
1023 zoom_inout_box = gtk_hbox_new (FALSE, 0);
1024 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_in, FALSE, FALSE, 10);
1025 gtk_box_pack_start (GTK_BOX (zoom_inout_box), zoom_out, FALSE, FALSE, 0);
1027 zoom_separator1 = gtk_hseparator_new ();
1029 zoom_h_entry = gtk_entry_new ();
1030 gtk_entry_set_text (GTK_ENTRY (zoom_h_entry), "1.000");
1031 gtk_editable_set_editable (GTK_EDITABLE (zoom_h_entry), FALSE);
1032 zoom_h_label = gtk_label_new ("Horizontal:");
1034 zoom_v_entry = gtk_entry_new ();
1035 gtk_entry_set_text (GTK_ENTRY (zoom_v_entry), "1.000");
1036 gtk_editable_set_editable (GTK_EDITABLE (zoom_v_entry), FALSE);
1037 zoom_v_label = gtk_label_new ("Vertical:");
1039 g->zoom.widget.h_zoom = (GtkEntry * )zoom_h_entry;
1040 g->zoom.widget.v_zoom = (GtkEntry * )zoom_v_entry;
1042 zoom_table = gtk_table_new (2, 2, FALSE);
1043 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_label, 0,1,0,1,
1044 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1045 gtk_table_attach (GTK_TABLE (zoom_table), zoom_h_entry, 1, 2, 0, 1,
1046 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1047 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_label, 0,1,1,2,
1048 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1049 gtk_table_attach (GTK_TABLE (zoom_table), zoom_v_entry, 1, 2, 1, 2,
1050 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1052 zoom_separator2 = gtk_hseparator_new ();
1054 zoom_h_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0);
1055 zoom_h_step = gtk_spin_button_new (zoom_h_adj, 0, 1);
1056 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_h_step), TRUE);
1057 zoom_h_step_label = gtk_label_new ("Horizontal step:");
1059 zoom_v_adj = (GtkAdjustment * )gtk_adjustment_new ((gfloat)1.2, 1.0, 5, (gfloat)0.1, 1, 0);
1060 zoom_v_step = gtk_spin_button_new (zoom_v_adj, 0, 1);
1061 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (zoom_v_step), TRUE);
1062 zoom_v_step_label = gtk_label_new ("Vertical step:");
1064 g->zoom.widget.h_step = (GtkSpinButton * )zoom_h_step;
1065 g->zoom.widget.v_step = (GtkSpinButton * )zoom_v_step;
1067 zoom_same_toggle = gtk_check_button_new_with_label("Keep them the same");
1068 zoom_ratio_toggle = gtk_check_button_new_with_label("Preserve their ratio");
1069 g_object_set_data(G_OBJECT(zoom_same_toggle), "flag", (gpointer)ZOOM_STEPS_SAME);
1070 g_object_set_data(G_OBJECT(zoom_ratio_toggle), "flag",
1071 (gpointer)ZOOM_STEPS_KEEP_RATIO);
1072 g_signal_connect(zoom_same_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g);
1073 g_signal_connect(zoom_ratio_toggle, "clicked", G_CALLBACK(callback_zoom_flags), g);
1075 zoom_step_table = gtk_table_new (4, 2, FALSE);
1076 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step_label, 0,1,0,1,
1077 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1078 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_h_step, 1, 2, 0, 1,
1079 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1080 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step_label, 0,1,1,2,
1081 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1082 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_v_step, 1, 2, 1, 2,
1083 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1084 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_same_toggle, 0,2,2,3,
1085 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1086 gtk_table_attach (GTK_TABLE (zoom_step_table), zoom_ratio_toggle, 0,2,3,4,
1087 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1089 zoom_box = gtk_vbox_new (FALSE, 0);
1090 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_inout_box, TRUE, TRUE, 0);
1091 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator1, TRUE, TRUE, 0);
1092 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_table, TRUE, TRUE, 0);
1093 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_separator2, TRUE, TRUE, 0);
1094 gtk_box_pack_start (GTK_BOX (zoom_box), zoom_step_table, TRUE, TRUE, 0);
1095 zoom_frame = gtk_frame_new ("Zoom");
1096 gtk_container_add (GTK_CONTAINER (zoom_frame), zoom_box);
1098 g_object_set_data(G_OBJECT(zoom_h_step), "direction", GINT_TO_POINTER(0));
1099 g_object_set_data(G_OBJECT(zoom_v_step), "direction", GINT_TO_POINTER(1));
1101 g_signal_connect(zoom_in, "toggled", G_CALLBACK(callback_zoom_inout), g);
1102 g_signal_connect(zoom_h_step, "changed", G_CALLBACK(callback_zoom_step), g);
1103 g_signal_connect(zoom_v_step, "changed", G_CALLBACK(callback_zoom_step), g);
1105 g->zoom.widget.in_toggle = (GtkToggleButton * )zoom_in;
1106 g->zoom.widget.out_toggle = (GtkToggleButton * )zoom_out;
1110 static void callback_zoom_inout (GtkWidget *toggle, gpointer data)
1112 struct graph *g = (struct graph * )data;
1114 if (GTK_TOGGLE_BUTTON (toggle)->active)
1115 g->zoom.flags &= ~ZOOM_OUT;
1117 g->zoom.flags |= ZOOM_OUT;
1120 static void callback_zoom_step (GtkWidget *spin, gpointer data)
1122 struct graph *g = (struct graph * )data;
1125 double *zoom_this, *zoom_other;
1126 GtkSpinButton *widget_this, *widget_other;
1129 direction = (long)g_object_get_data(G_OBJECT(spin), "direction");
1130 value = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (spin));
1133 zoom_this = &g->zoom.step_y;
1134 zoom_other = &g->zoom.step_x;
1135 widget_this = g->zoom.widget.v_step;
1136 widget_other = g->zoom.widget.h_step;
1138 zoom_this = &g->zoom.step_x;
1139 zoom_other = &g->zoom.step_y;
1140 widget_this = g->zoom.widget.h_step;
1141 widget_other = g->zoom.widget.v_step;
1144 old_this = *zoom_this;
1146 if (g->zoom.flags & ZOOM_STEPS_SAME) {
1147 *zoom_other = value;
1148 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1149 } else if (g->zoom.flags & ZOOM_STEPS_KEEP_RATIO) {
1150 double old_other = *zoom_other;
1151 *zoom_other *= value / old_this;
1152 if (*zoom_other < 1.0) {
1154 *zoom_this = old_this * 1.0 / old_other;
1155 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1156 } else if (*zoom_other > 5.0) {
1158 *zoom_this = old_this * 5.0 / old_other;
1159 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1161 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1165 static void callback_zoom_flags (GtkWidget *toggle, gpointer data)
1167 struct graph *g = (struct graph * )data;
1168 int flag = (long)g_object_get_data(G_OBJECT(toggle), "flag");
1170 if (GTK_TOGGLE_BUTTON (toggle)->active)
1171 g->zoom.flags |= flag;
1173 g->zoom.flags &= ~flag;
1176 static void update_zoom_spins (struct graph *g)
1180 g_snprintf (s, 32, "%.3f", g->zoom.x / g->zoom.initial.x);
1181 gtk_entry_set_text (g->zoom.widget.h_zoom, s);
1182 g_snprintf (s, 32, "%.3f", g->zoom.y / g->zoom.initial.y);
1183 gtk_entry_set_text (g->zoom.widget.v_zoom, s);
1186 static GtkWidget *control_panel_create_magnify_group (struct graph *g)
1188 GtkWidget *mag_width_label, *mag_width;
1189 GtkWidget *mag_height_label, *mag_height;
1190 GtkWidget *mag_x_label, *mag_x;
1191 GtkWidget *mag_y_label, *mag_y;
1192 GtkWidget *mag_wh_table, *mag_zoom_frame, *mag_zoom_table;
1193 GtkWidget *mag_h_zoom_label, *mag_h_zoom;
1194 GtkWidget *mag_v_zoom_label, *mag_v_zoom;
1195 GtkWidget *mag_zoom_same, *mag_zoom_ratio;
1196 GtkAdjustment *mag_width_adj, *mag_height_adj, *mag_x_adj, *mag_y_adj;
1197 GtkAdjustment *mag_h_zoom_adj, *mag_v_zoom_adj;
1198 GtkWidget *mag_box, *mag_frame;
1200 mag_width_label = gtk_label_new ("Width:");
1201 mag_width_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1202 mag_width = gtk_spin_button_new (mag_width_adj, 0, 0);
1204 mag_height_label = gtk_label_new ("Height:");
1205 mag_height_adj = (GtkAdjustment * )gtk_adjustment_new (250,100,600,1,10,0);
1206 mag_height = gtk_spin_button_new (mag_height_adj, 0, 0);
1208 mag_x_label = gtk_label_new ("X:");
1209 mag_x_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1210 mag_x = gtk_spin_button_new (mag_x_adj, 0, 0);
1212 mag_y_label = gtk_label_new ("Y:");
1213 mag_y_adj = (GtkAdjustment * )gtk_adjustment_new (0,-1000,1000,1,10,0);
1214 mag_y = gtk_spin_button_new (mag_y_adj, 0, 0);
1216 mag_wh_table = gtk_table_new (4, 2, FALSE);
1217 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width_label, 0,1,0,1,
1218 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1219 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_width, 1,2,0,1,
1220 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1221 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height_label, 0,1,1,2,
1222 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1223 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_height, 1,2,1,2,
1224 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1225 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x_label, 0,1,2,3,
1226 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1227 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_x, 1,2,2,3,
1228 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1229 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y_label, 0,1,3,4,
1230 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1231 gtk_table_attach (GTK_TABLE (mag_wh_table), mag_y, 1,2,3,4,
1232 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 0);
1234 mag_h_zoom_label = gtk_label_new ("Horizontal:");
1235 mag_h_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0);
1236 mag_h_zoom = gtk_spin_button_new (mag_h_zoom_adj, 0, 1);
1238 mag_v_zoom_label = gtk_label_new ("Vertical:");
1239 mag_v_zoom_adj = (GtkAdjustment *)gtk_adjustment_new(10.0, 1.0, 25.0, (gfloat)0.1, 1, 0);
1240 mag_v_zoom = gtk_spin_button_new (mag_v_zoom_adj, 0, 1);
1242 mag_zoom_same = gtk_check_button_new_with_label ("Keep them the same");
1243 mag_zoom_ratio = gtk_check_button_new_with_label("Preserve their ratio");
1245 mag_zoom_table = gtk_table_new (4, 2, FALSE);
1246 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom_label, 0,1,0,1,
1247 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1248 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_h_zoom, 1,2,0,1,
1249 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1250 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom_label, 0,1,1,2,
1251 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1252 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_v_zoom, 1,2,1,2,
1253 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1254 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_same, 0,2,2,3,
1255 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1256 gtk_table_attach (GTK_TABLE (mag_zoom_table), mag_zoom_ratio, 0,2,3,4,
1257 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1259 mag_zoom_frame = gtk_frame_new ("Magnify zoom");
1260 gtk_container_add (GTK_CONTAINER (mag_zoom_frame), mag_zoom_table);
1261 gtk_container_set_border_width (GTK_CONTAINER (mag_zoom_frame), 3);
1263 mag_box = gtk_vbox_new (FALSE, 0);
1264 gtk_box_pack_start (GTK_BOX (mag_box), mag_wh_table, TRUE, TRUE, 0);
1265 gtk_box_pack_start (GTK_BOX (mag_box), mag_zoom_frame, TRUE, TRUE, 0);
1266 mag_frame = gtk_frame_new ("Magnify");
1267 gtk_container_add (GTK_CONTAINER (mag_frame), mag_box);
1269 g->magnify.widget.h_zoom = (GtkSpinButton * )mag_h_zoom;
1270 g->magnify.widget.v_zoom = (GtkSpinButton * )mag_v_zoom;
1271 g_object_set_data(G_OBJECT(mag_h_zoom), "direction", GINT_TO_POINTER(0));
1272 g_object_set_data(G_OBJECT(mag_v_zoom), "direction", GINT_TO_POINTER(1));
1273 g_object_set_data(G_OBJECT(mag_zoom_same), "flag", (gpointer)MAGZOOMS_SAME);
1274 g_object_set_data(G_OBJECT(mag_zoom_ratio), "flag", (gpointer)MAGZOOMS_SAME_RATIO);
1276 g_signal_connect(mag_width, "changed", G_CALLBACK(callback_mag_width), g);
1277 g_signal_connect(mag_height, "changed", G_CALLBACK(callback_mag_height), g);
1278 g_signal_connect(mag_x, "changed", G_CALLBACK(callback_mag_x), g);
1279 g_signal_connect(mag_y, "changed", G_CALLBACK(callback_mag_y), g);
1280 g_signal_connect(mag_h_zoom, "changed", G_CALLBACK(callback_mag_zoom), g);
1281 g_signal_connect(mag_v_zoom, "changed", G_CALLBACK(callback_mag_zoom), g);
1282 g_signal_connect(mag_zoom_same, "clicked", G_CALLBACK(callback_mag_flags), g);
1283 g_signal_connect(mag_zoom_ratio, "clicked", G_CALLBACK(callback_mag_flags), g);
1288 static void callback_mag_width (GtkWidget *spin, gpointer data)
1290 struct graph *g = (struct graph * )data;
1292 g->magnify.width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin));
1295 static void callback_mag_height (GtkWidget *spin, gpointer data)
1297 struct graph *g = (struct graph * )data;
1299 g->magnify.height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1302 static void callback_mag_x (GtkWidget *spin, gpointer data)
1304 struct graph *g = (struct graph * )data;
1306 g->magnify.offset.x=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1309 static void callback_mag_y (GtkWidget *spin, gpointer data)
1311 struct graph *g = (struct graph * )data;
1313 g->magnify.offset.y=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
1316 static void callback_mag_zoom (GtkWidget *spin, gpointer data)
1318 struct graph *g = (struct graph * )data;
1321 double *zoom_this, *zoom_other;
1322 GtkSpinButton *widget_this, *widget_other;
1325 if (g->magnify.flags & MAGZOOMS_IGNORE) {
1326 printf ("refusing callback for %s zoom widget.\n", (GtkSpinButton * )spin==g->magnify.widget.h_zoom ? "horizontal" : "vertical");
1327 g->magnify.flags &= ~MAGZOOMS_IGNORE;
1330 direction = (long)g_object_get_data(G_OBJECT(spin), "direction");
1331 value = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (spin));
1334 zoom_this = &g->magnify.zoom.y;
1335 zoom_other = &g->magnify.zoom.x;
1336 widget_this = g->magnify.widget.v_zoom;
1337 widget_other = g->magnify.widget.h_zoom;
1339 zoom_this = &g->magnify.zoom.x;
1340 zoom_other = &g->magnify.zoom.y;
1341 widget_this = g->magnify.widget.h_zoom;
1342 widget_other = g->magnify.widget.v_zoom;
1345 old_this = *zoom_this;
1347 if (g->magnify.flags & MAGZOOMS_SAME) {
1348 *zoom_other = value;
1349 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1350 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1351 } else if (g->magnify.flags & MAGZOOMS_SAME_RATIO) {
1352 double old_other = *zoom_other;
1353 *zoom_other *= value / old_this;
1354 if (*zoom_other < 1.0) {
1356 *zoom_this = old_this * 1.0 / old_other;
1357 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1358 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1359 } else if (*zoom_other > 25.0) {
1361 *zoom_this = old_this * 25.0 / old_other;
1362 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1363 gtk_spin_button_set_value (widget_this, (gfloat) *zoom_this);
1365 /* g->magnify.flags |= MAGZOOMS_IGNORE; */
1366 gtk_spin_button_set_value (widget_other, (gfloat) *zoom_other);
1370 static void callback_mag_flags (GtkWidget *toggle, gpointer data)
1372 struct graph *g = (struct graph * )data;
1373 int flag = (long)g_object_get_data(G_OBJECT(toggle), "flag");
1375 if (GTK_TOGGLE_BUTTON (toggle)->active)
1376 g->magnify.flags |= flag;
1378 g->magnify.flags &= ~flag;
1381 static GtkWidget *control_panel_create_zoomlock_group (struct graph *g)
1383 GtkWidget *zoom_lock_h, *zoom_lock_v, *zoom_lock_none, *zoom_lock_box;
1384 GtkWidget *zoom_lock_frame;
1386 zoom_lock_none = gtk_radio_button_new_with_label (NULL, "none");
1387 zoom_lock_h = gtk_radio_button_new_with_label (
1388 gtk_radio_button_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1390 zoom_lock_v = gtk_radio_button_new_with_label (
1391 gtk_radio_button_group (GTK_RADIO_BUTTON (zoom_lock_none)),
1393 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (zoom_lock_none), TRUE);
1394 zoom_lock_box = gtk_hbox_new (FALSE, 0);
1395 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_none,
1397 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_h, TRUE, TRUE, 0);
1398 gtk_box_pack_start(GTK_BOX(zoom_lock_box), zoom_lock_v, TRUE, TRUE, 0);
1399 zoom_lock_frame = gtk_frame_new ("Zoom lock:");
1400 gtk_container_add (GTK_CONTAINER (zoom_lock_frame), zoom_lock_box);
1402 g_signal_connect(zoom_lock_h, "toggled", G_CALLBACK(callback_zoomlock_h), g);
1403 g_signal_connect(zoom_lock_v, "toggled", G_CALLBACK(callback_zoomlock_v), g);
1405 return zoom_lock_frame;
1408 static void callback_zoomlock_h (GtkWidget *toggle, gpointer data)
1410 struct graph *g = (struct graph * )data;
1412 if (GTK_TOGGLE_BUTTON (toggle)->active)
1413 g->zoom.flags |= ZOOM_HLOCK;
1415 g->zoom.flags &= ~ZOOM_HLOCK;
1418 static void callback_zoomlock_v (GtkWidget *toggle, gpointer data)
1420 struct graph *g = (struct graph * )data;
1422 if (GTK_TOGGLE_BUTTON (toggle)->active)
1423 g->zoom.flags |= ZOOM_VLOCK;
1425 g->zoom.flags &= ~ZOOM_VLOCK;
1428 static GtkWidget *control_panel_create_cross_group (struct graph *g)
1430 GtkWidget *on, *off, *box, *frame, *vbox, *label;
1432 label = gtk_label_new ("Crosshairs:");
1433 off = gtk_radio_button_new_with_label (NULL, "off");
1434 on = gtk_radio_button_new_with_label (
1435 gtk_radio_button_group (GTK_RADIO_BUTTON (off)), "on");
1436 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (off), TRUE);
1437 box = gtk_hbox_new (FALSE, 0);
1438 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 10);
1439 gtk_box_pack_start (GTK_BOX (box), off, FALSE, FALSE, 10);
1440 gtk_box_pack_start (GTK_BOX (box), on, FALSE, FALSE, 0);
1441 vbox = gtk_vbox_new (FALSE, 0);
1442 gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 15);
1443 /* frame = gtk_frame_new ("Cross:"); */
1444 frame = gtk_frame_new (NULL);
1445 gtk_container_add (GTK_CONTAINER (frame), vbox);
1447 g_signal_connect(on, "toggled", G_CALLBACK(callback_cross_on_off), g);
1449 g->cross.on_toggle = (GtkToggleButton * )on;
1450 g->cross.off_toggle = (GtkToggleButton * )off;
1455 static void callback_cross_on_off (GtkWidget *toggle, gpointer data)
1457 struct graph *g = (struct graph * )data;
1459 if (GTK_TOGGLE_BUTTON (toggle)->active) {
1461 g->cross.draw = TRUE;
1462 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
1463 cross_draw (g, x, y);
1465 g->cross.draw = FALSE;
1470 static GtkWidget *control_panel_create_graph_type_group (struct graph *g)
1472 GtkWidget *graph_tseqttrace, *graph_tseqstevens;
1473 GtkWidget *graph_tput, *graph_rtt, *graph_sep, *graph_init, *graph_box;
1474 GtkWidget *graph_frame;
1476 graph_tput = gtk_radio_button_new_with_label (NULL, "Throughput");
1477 graph_tseqttrace = gtk_radio_button_new_with_label (
1478 gtk_radio_button_group (GTK_RADIO_BUTTON (graph_tput)),
1479 "Time/Sequence (tcptrace-style)");
1480 graph_tseqstevens = gtk_radio_button_new_with_label (
1481 gtk_radio_button_group (GTK_RADIO_BUTTON (graph_tput)),
1482 "Time/Sequence (Stevens'-style)");
1483 graph_rtt = gtk_radio_button_new_with_label (
1484 gtk_radio_button_group (GTK_RADIO_BUTTON (graph_tput)),
1487 case GRAPH_TSEQ_STEVENS:
1488 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(graph_tseqstevens),TRUE);
1490 case GRAPH_TSEQ_TCPTRACE:
1491 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(graph_tseqttrace),TRUE);
1493 case GRAPH_THROUGHPUT:
1494 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_tput), TRUE);
1497 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (graph_rtt), TRUE);
1500 graph_init = gtk_check_button_new_with_label ("Init on change");
1501 graph_sep = gtk_hseparator_new ();
1502 graph_box = gtk_vbox_new (FALSE, 0);
1503 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqttrace, TRUE, TRUE, 0);
1504 gtk_box_pack_start (GTK_BOX (graph_box), graph_tseqstevens, TRUE, TRUE, 0);
1505 gtk_box_pack_start (GTK_BOX (graph_box), graph_tput, TRUE, TRUE, 0);
1506 gtk_box_pack_start (GTK_BOX (graph_box), graph_rtt, TRUE, TRUE, 0);
1507 gtk_box_pack_start (GTK_BOX (graph_box), graph_sep, TRUE, TRUE, 0);
1508 gtk_box_pack_start (GTK_BOX (graph_box), graph_init, TRUE, TRUE, 0);
1509 graph_frame = gtk_frame_new ("Graph type:");
1510 gtk_container_add (GTK_CONTAINER (graph_frame), graph_box);
1512 g_object_set_data(G_OBJECT(graph_tseqstevens), "new-graph-type",
1513 GINT_TO_POINTER(0));
1514 g_object_set_data(G_OBJECT(graph_tseqttrace), "new-graph-type", GINT_TO_POINTER(1));
1515 g_object_set_data(G_OBJECT(graph_tput), "new-graph-type", GINT_TO_POINTER(2));
1516 g_object_set_data(G_OBJECT(graph_rtt), "new-graph-type", GINT_TO_POINTER(3));
1518 g_signal_connect(graph_tseqttrace, "toggled", G_CALLBACK(callback_graph_type), g);
1519 g_signal_connect(graph_tseqstevens, "toggled", G_CALLBACK(callback_graph_type), g);
1520 g_signal_connect(graph_tput, "toggled", G_CALLBACK(callback_graph_type), g);
1521 g_signal_connect(graph_rtt, "toggled", G_CALLBACK(callback_graph_type), g);
1522 g_signal_connect(graph_init, "toggled", G_CALLBACK(callback_graph_init_on_typechg),
1528 static void callback_graph_type (GtkWidget *toggle, gpointer data)
1530 int old_type, new_type;
1531 struct graph *g = (struct graph * )data;
1533 new_type = (long)g_object_get_data(G_OBJECT(toggle),"new-graph-type");
1535 if (!GTK_TOGGLE_BUTTON (toggle)->active)
1541 graph_element_lists_free (g);
1542 graph_element_lists_initialize (g);
1544 if (old_type == GRAPH_THROUGHPUT || new_type == GRAPH_THROUGHPUT) {
1545 /* throughput graph uses differently constructed segment list so we
1546 * need to recreate it */
1547 graph_segment_list_free (g);
1548 graph_segment_list_get (g);
1551 if (g->flags & GRAPH_INIT_ON_TYPE_CHANGE) {
1552 g->geom.width = g->wp.width;
1553 g->geom.height = g->wp.height;
1554 g->geom.x = g->wp.x;
1555 g->geom.y = g->wp.y;
1557 g->x_axis->min = g->y_axis->min = 0;
1558 gtk_toggle_button_set_active (g->gui.time_orig_conn, TRUE);
1559 gtk_toggle_button_set_active (g->gui.seq_orig_isn, TRUE);
1560 graph_init_sequence (g);
1563 static void callback_graph_init_on_typechg (GtkWidget *toggle _U_, gpointer data)
1565 ((struct graph * )data)->flags ^= GRAPH_INIT_ON_TYPE_CHANGE;
1568 static struct graph *graph_new (void)
1572 g = (struct graph * )g_malloc0 (sizeof (struct graph));
1573 graph_element_lists_initialize (g);
1575 g->x_axis = (struct axis * )g_malloc0 (sizeof (struct axis));
1576 g->y_axis = (struct axis * )g_malloc0 (sizeof (struct axis));
1578 g->x_axis->flags = 0;
1579 g->x_axis->flags |= AXIS_ORIENTATION;
1580 g->x_axis->s.x = g->x_axis->s.y = 0;
1581 g->x_axis->s.height = HAXIS_INIT_HEIGHT;
1582 g->x_axis->p.x = VAXIS_INIT_WIDTH;
1583 g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1585 g->y_axis->flags = 0;
1586 g->y_axis->flags &= ~AXIS_ORIENTATION;
1587 g->y_axis->p.x = g->y_axis->p.y = 0;
1588 g->y_axis->p.width = VAXIS_INIT_WIDTH;
1590 g->y_axis->s.y = TITLEBAR_HEIGHT;
1591 g->y_axis->s.width = VAXIS_INIT_WIDTH;
1596 static void graph_initialize_values (struct graph *g)
1598 g->geom.width = g->wp.width = 750;
1599 g->geom.height = g->wp.height = 550;
1600 g->geom.x = g->wp.x = VAXIS_INIT_WIDTH;
1601 g->geom.y = g->wp.y = TITLEBAR_HEIGHT;
1603 /* g->zoom.x = g->zoom.y = 1.0; */
1604 g->zoom.step_x = g->zoom.step_y = 1.2;
1606 g->cross.draw = g->cross.erase_needed = 0;
1607 g->grab.grabbed = 0;
1608 g->magnify.active = 0;
1609 g->magnify.offset.x = g->magnify.offset.y = 0;
1610 g->magnify.width = g->magnify.height = 250;
1611 g->magnify.zoom.x = g->magnify.zoom.y = 10.0;
1612 g->magnify.flags = 0;
1615 static void graph_init_sequence (struct graph *g)
1617 debug(DBS_FENTRY) puts ("graph_init_sequence()");
1619 graph_type_dependent_initialize (g);
1620 g->zoom.initial.x = g->zoom.x;
1621 g->zoom.initial.y = g->zoom.y;
1622 graph_element_lists_make (g);
1623 g->x_axis->s.width = g->wp.width;
1624 g->x_axis->p.width = g->x_axis->s.width + RMARGIN_WIDTH;
1625 g->x_axis->p.y = TITLEBAR_HEIGHT + g->wp.height;
1626 g->x_axis->s.height = g->x_axis->p.height = HAXIS_INIT_HEIGHT;
1627 g->y_axis->s.height = g->wp.height;
1628 g->y_axis->p.height = g->wp.height + TITLEBAR_HEIGHT;
1629 graph_pixmaps_create (g);
1630 axis_pixmaps_create (g->y_axis);
1631 axis_pixmaps_create (g->x_axis);
1632 graph_title_pixmap_create (g);
1633 graph_title_pixmap_draw (g);
1634 graph_title_pixmap_display (g);
1636 axis_display (g->y_axis);
1637 axis_display (g->x_axis);
1640 static void graph_type_dependent_initialize (struct graph *g)
1643 case GRAPH_TSEQ_STEVENS:
1644 case GRAPH_TSEQ_TCPTRACE:
1645 tseq_initialize (g);
1647 case GRAPH_THROUGHPUT:
1648 tput_initialize (g);
1658 static void graph_destroy (struct graph *g)
1660 debug(DBS_FENTRY) puts ("graph_destroy()");
1662 axis_destroy (g->x_axis);
1663 axis_destroy (g->y_axis);
1664 /* window_destroy (g->drawing_area); */
1665 window_destroy (g->gui.control_panel);
1666 window_destroy (g->toplevel);
1667 /* window_destroy (g->text); */
1668 gdk_gc_unref (g->fg_gc);
1669 gdk_gc_unref (g->bg_gc);
1670 gdk_pixmap_unref (g->pixmap[0]);
1671 gdk_pixmap_unref (g->pixmap[1]);
1674 g_free ( (gpointer) (g->title) );
1675 graph_segment_list_free (g);
1676 graph_element_lists_free (g);
1682 typedef struct _tcp_scan_t {
1683 struct segment *current;
1686 struct segment *last;
1690 tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
1692 static struct segment *segment=NULL;
1693 tcp_scan_t *ts=(tcp_scan_t *)pct;
1694 struct tcpheader *tcphdr=(struct tcpheader *)vip;
1697 segment=g_malloc(sizeof (struct segment));
1699 perror ("malloc failed");
1704 if (compare_headers(&ts->current->ip_src, &ts->current->ip_dst,
1705 ts->current->th_sport, ts->current->th_dport,
1706 &tcphdr->ip_src, &tcphdr->ip_dst,
1707 tcphdr->th_sport, tcphdr->th_dport,
1709 segment->next = NULL;
1710 segment->num = pinfo->fd->num;
1711 segment->rel_secs = (guint32) pinfo->fd->rel_ts.secs;
1712 segment->rel_usecs = pinfo->fd->rel_ts.nsecs/1000;
1713 segment->abs_secs = (guint32) pinfo->fd->abs_ts.secs;
1714 segment->abs_usecs = pinfo->fd->abs_ts.nsecs/1000;
1715 segment->th_seq=tcphdr->th_seq;
1716 segment->th_ack=tcphdr->th_ack;
1717 segment->th_win=tcphdr->th_win;
1718 segment->th_flags=tcphdr->th_flags;
1719 segment->th_sport=tcphdr->th_sport;
1720 segment->th_dport=tcphdr->th_dport;
1721 segment->th_seglen=tcphdr->th_seglen;
1722 COPY_ADDRESS(&segment->ip_src, &tcphdr->ip_src);
1723 COPY_ADDRESS(&segment->ip_dst, &tcphdr->ip_dst);
1724 if (ts->g->segments) {
1725 ts->last->next = segment;
1727 ts->g->segments = segment;
1730 if(pinfo->fd->num==ts->current->num){
1731 ts->g->current = segment;
1742 /* here we collect all the external data we will ever need */
1743 static void graph_segment_list_get (struct graph *g)
1745 struct segment current;
1746 GString *error_string;
1750 debug(DBS_FENTRY) puts ("graph_segment_list_get()");
1751 select_tcpip_session (&cfile, ¤t);
1752 if (g->type == GRAPH_THROUGHPUT)
1753 ts.direction = COMPARE_CURR_DIR;
1755 ts.direction = COMPARE_ANY_DIR;
1757 /* rescan all the packets and pick up all interesting tcp headers.
1758 * we only filter for TCP here for speed and do the actual compare
1759 * in the tap listener
1761 ts.current=¤t;
1764 error_string=register_tap_listener("tcp", &ts, "tcp", NULL, tapall_tcpip_packet, NULL);
1766 fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
1768 g_string_free(error_string, TRUE);
1771 cf_retap_packets(&cfile, FALSE);
1772 remove_tap_listener(&ts);
1776 typedef struct _th_t {
1778 struct tcpheader *tcphdr;
1782 tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
1787 th->tcphdr=(struct tcpheader *)vip;
1794 /* XXX should be enhanced so that if we have multiple TCP layers in the trace
1795 * then present the user with a dialog where the user can select WHICH tcp
1798 static struct tcpheader *select_tcpip_session (capture_file *cf, struct segment *hdrs)
1803 epan_dissect_t *edt;
1805 GString *error_string;
1806 th_t th = {0, NULL};
1808 fdata = cf->current_frame;
1810 /* no real filter yet */
1811 if (!dfilter_compile("tcp", &sfcode)) {
1812 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, dfilter_error_msg);
1816 /* dissect the current frame */
1817 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
1818 cf->pd, fdata->cap_len, &err, &err_info)) {
1819 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1820 cf_read_error_message(err, err_info), cf->filename);
1825 error_string=register_tap_listener("tcp", &th, NULL, NULL, tap_tcpip_packet, NULL);
1827 fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
1829 g_string_free(error_string, TRUE);
1833 edt = epan_dissect_new(TRUE, FALSE);
1834 epan_dissect_prime_dfilter(edt, sfcode);
1835 tap_queue_init(edt);
1836 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
1837 tap_push_tapped_queue(edt);
1838 epan_dissect_free(edt);
1839 remove_tap_listener(&th);
1842 /* This "shouldn't happen", as our menu items shouldn't
1843 * even be enabled if the selected packet isn't a TCP
1844 * segment, as tcp_graph_selected_packet_enabled() is used
1845 * to determine whether to enable any of our menu items. */
1846 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1847 "Selected packet isn't a TCP segment");
1850 /* XXX fix this later, we should show a dialog allowing the user
1851 to select which session he wants here
1854 /* can only handle a single tcp layer yet */
1855 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1856 "The selected packet has more than one TCP"
1861 hdrs->num = fdata->num;
1862 hdrs->rel_secs = (guint32) fdata->rel_ts.secs;
1863 hdrs->rel_usecs = fdata->rel_ts.nsecs/1000;
1864 hdrs->abs_secs = (guint32) fdata->abs_ts.secs;
1865 hdrs->abs_usecs = fdata->abs_ts.nsecs/1000;
1866 hdrs->th_seq=th.tcphdr->th_seq;
1867 hdrs->th_ack=th.tcphdr->th_ack;
1868 hdrs->th_win=th.tcphdr->th_win;
1869 hdrs->th_flags=th.tcphdr->th_flags;
1870 hdrs->th_sport=th.tcphdr->th_sport;
1871 hdrs->th_dport=th.tcphdr->th_dport;
1872 hdrs->th_seglen=th.tcphdr->th_seglen;
1873 COPY_ADDRESS(&hdrs->ip_src, &th.tcphdr->ip_src);
1874 COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdr->ip_dst);
1879 static int compare_headers (address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, address *saddr2, address *daddr2, guint16 sport2, guint16 dport2, int dir)
1883 dir1 = ((!(CMP_ADDRESS(saddr1, saddr2))) &&
1884 (!(CMP_ADDRESS(daddr1, daddr2))) &&
1888 if(dir==COMPARE_CURR_DIR){
1891 dir2 = ((!(CMP_ADDRESS(saddr1, daddr2))) &&
1892 (!(CMP_ADDRESS(daddr1, saddr2))) &&
1895 return dir1 || dir2;
1899 static void graph_segment_list_free (struct graph *g)
1901 struct segment *segment;
1903 while (g->segments) {
1904 segment = g->segments->next;
1905 g_free (g->segments);
1906 g->segments = segment;
1911 static void graph_element_lists_initialize (struct graph *g)
1913 g->elists = (struct element_list *)g_malloc0 (sizeof (struct element_list));
1916 static void graph_element_lists_make (struct graph *g)
1918 debug(DBS_FENTRY) puts ("graph_element_lists_make()");
1921 case GRAPH_TSEQ_STEVENS:
1922 tseq_stevens_make_elmtlist (g);
1924 case GRAPH_TSEQ_TCPTRACE:
1925 tseq_tcptrace_make_elmtlist (g);
1927 case GRAPH_THROUGHPUT:
1928 tput_make_elmtlist (g);
1931 rtt_make_elmtlist (g);
1934 printf ("graph_element_lists_make: unknown graph type: %d\n", g->type);
1939 static void graph_element_lists_free (struct graph *g)
1941 struct element_list *list, *next_list;
1944 for (list=g->elists; list; list=list->next)
1945 g_free (list->elements);
1946 while (g->elists->next) {
1947 list = g->elists->next->next;
1948 g_free (g->elists->next);
1949 g->elists->next = list;
1953 for (list=g->elists; list; list=next_list) {
1954 g_free (list->elements);
1955 next_list = list->next;
1958 g->elists = NULL; /* just to make debugging easier */
1961 static void graph_title_pixmap_create (struct graph *g)
1963 if (g->title_pixmap)
1964 gdk_pixmap_unref (g->title_pixmap);
1966 g->title_pixmap = gdk_pixmap_new (g->drawing_area->window,
1967 g->x_axis->p.width, g->wp.y, -1);
1970 static void graph_title_pixmap_draw (struct graph *g)
1974 gdk_draw_rectangle(g->title_pixmap, g->bg_gc, TRUE, 0, 0,
1975 g->x_axis->p.width, g->wp.y);
1976 for (i=0; g->title[i]; i++) {
1978 PangoLayout *layout;
1979 layout = gtk_widget_create_pango_layout(g->drawing_area,
1981 pango_layout_get_pixel_size(layout, &w, &h);
1982 gdk_draw_layout(g->title_pixmap, g->fg_gc,
1983 g->wp.width/2 - w/2, 20 + i*(h+3), layout);
1984 g_object_unref(G_OBJECT(layout));
1988 static void graph_title_pixmap_display (struct graph *g)
1990 gdk_draw_pixmap (g->drawing_area->window, g->fg_gc, g->title_pixmap,
1991 0, 0, g->wp.x, 0, g->x_axis->p.width, g->wp.y);
1994 static void graph_pixmaps_create (struct graph *g)
1996 debug(DBS_FENTRY) puts ("graph_pixmaps_create()");
1999 gdk_pixmap_unref (g->pixmap[0]);
2001 gdk_pixmap_unref (g->pixmap[1]);
2003 g->pixmap[0] = gdk_pixmap_new (g->drawing_area->window,
2004 g->wp.width, g->wp.height, -1);
2005 g->pixmap[1] = gdk_pixmap_new (g->drawing_area->window,
2006 g->wp.width, g->wp.height, -1);
2011 static void graph_display (struct graph *g)
2013 graph_pixmap_draw (g);
2014 graph_pixmaps_switch (g);
2015 graph_pixmap_display (g);
2018 static void graph_pixmap_display (struct graph *g)
2020 gdk_draw_pixmap (g->drawing_area->window, g->fg_gc,
2021 g->pixmap[g->displayed], 0, 0, g->wp.x, g->wp.y,
2022 g->wp.width, g->wp.height);
2023 if (g->cross.erase_needed) {
2024 cross_xor(g, g->cross.x, g->cross.y);
2028 static void graph_pixmaps_switch (struct graph *g)
2030 g->displayed = 1 ^ g->displayed;
2033 static void graph_pixmap_draw (struct graph *g)
2035 struct element_list *list;
2039 debug(DBS_FENTRY) puts ("graph_display()");
2040 not_disp = 1 ^ g->displayed;
2042 gdk_draw_rectangle (g->pixmap[not_disp], g->bg_gc, TRUE,
2043 0, 0, g->wp.width, g->wp.height);
2045 for (list=g->elists; list; list=list->next)
2046 for (e=list->elements; e->type != ELMT_NONE; e++) {
2051 draw_element_line (g, e);
2054 draw_element_arc (g, e);
2062 static void draw_element_line (struct graph *g, struct element *e)
2066 debug(DBS_GRAPH_DRAWING) printf ("line element: (%.2f,%.2f)->(%.2f,%.2f), "
2067 "seg %d ... ", e->p.line.dim.x1, e->p.line.dim.y1,
2068 e->p.line.dim.x2, e->p.line.dim.y2, e->parent->num);
2069 x1 = (int )rint (e->p.line.dim.x1 + g->geom.x - g->wp.x);
2070 x2 = (int )rint (e->p.line.dim.x2 + g->geom.x - g->wp.x);
2071 y1 = (int )rint ((g->geom.height-1-e->p.line.dim.y1) + g->geom.y-g->wp.y);
2072 y2 = (int )rint ((g->geom.height-1-e->p.line.dim.y2) + g->geom.y-g->wp.y);
2083 if ((x1<0 && x2<0) || (x1>=g->wp.width && x2>=g->wp.width) ||
2084 (y1<0 && y2<0) || (y1>=g->wp.height && y2>=g->wp.height)) {
2085 debug(DBS_GRAPH_DRAWING) printf (" refusing: (%d,%d)->(%d,%d)\n",
2089 if (x2 > g->wp.width-1)
2093 if (y2 > g->wp.height-1)
2094 y2 = g->wp.height-1;
2097 debug(DBS_GRAPH_DRAWING) printf ("line: (%d,%d)->(%d,%d)\n", x1, y1, x2,y2);
2098 gdk_draw_line (g->pixmap[1^g->displayed], e->gc, x1, y1, x2, y2);
2101 static void draw_element_arc (struct graph *g, struct element *e)
2105 x1 = (int )rint (e->p.arc.dim.x + g->geom.x - g->wp.x);
2106 x2 = (int )e->p.arc.dim.width;
2107 y1 = (int )rint (g->geom.height-1 - e->p.arc.dim.y + g->geom.y - g->wp.y);
2108 y2 = (int )e->p.arc.dim.height;
2109 if (x1<-x2 || x1>=g->wp.width || y1<-y2 || y1>=g->wp.height)
2111 debug(DBS_GRAPH_DRAWING) printf ("arc: (%d,%d)->(%d,%d)\n", x1, y1, x2, y2);
2112 gdk_draw_arc (g->pixmap[1^g->displayed], e->gc, e->p.arc.filled, x1,
2113 y1, x2, y2, e->p.arc.angle1, e->p.arc.angle2);
2116 static void axis_pixmaps_create (struct axis *axis)
2118 debug(DBS_FENTRY) puts ("axis_pixmaps_create()");
2119 if (axis->pixmap[0])
2120 gdk_pixmap_unref (axis->pixmap[0]);
2121 if (axis->pixmap[1])
2122 gdk_pixmap_unref (axis->pixmap[1]);
2124 axis->pixmap[0] = gdk_pixmap_new (axis->drawing_area->window,
2125 axis->p.width, axis->p.height, -1);
2126 axis->pixmap[1] = gdk_pixmap_new (axis->drawing_area->window,
2127 axis->p.width, axis->p.height, -1);
2129 axis->displayed = 0;
2132 static void axis_destroy (struct axis *axis)
2134 gdk_pixmap_unref (axis->pixmap[0]);
2135 gdk_pixmap_unref (axis->pixmap[1]);
2136 g_free ( (gpointer) (axis->label) );
2139 static void axis_display (struct axis *axis)
2141 if (axis->flags & AXIS_ORIENTATION)
2142 h_axis_pixmap_draw (axis);
2144 v_axis_pixmap_draw (axis);
2145 axis_pixmaps_switch (axis);
2146 axis_pixmap_display (axis);
2149 static void v_axis_pixmap_draw (struct axis *axis)
2151 struct graph *g = axis->g;
2154 int not_disp, rdigits, offset, imin, imax;
2155 double bottom, top, j, fl, corr;
2156 PangoLayout *layout;
2158 debug(DBS_FENTRY) puts ("v_axis_pixmap_draw()");
2159 bottom = (g->geom.height - (g->wp.height + g->wp.y + (-g->geom.y))) /
2160 (double )g->geom.height * g->bounds.height;
2161 bottom += axis->min;
2162 top = (g->geom.height - (g->wp.y + (-g->geom.y))) /
2163 (double )g->geom.height * g->bounds.height;
2165 axis_compute_ticks (axis, bottom, top, AXIS_VERTICAL);
2167 j = axis->major - floor (axis->major);
2168 for (rdigits=0; rdigits<=6; rdigits++) {
2175 not_disp = 1 ^ axis->displayed;
2176 gdk_draw_rectangle (axis->pixmap[not_disp], g->bg_gc, TRUE, 0, 0,
2177 axis->p.width, axis->p.height);
2179 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, axis->p.width - 1,
2180 (gint) ((axis->p.height-axis->s.height)/2.0), axis->s.width - 1,
2183 offset = g->wp.y + (-g->geom.y);
2184 fl = floor (axis->min / axis->major) * axis->major;
2185 corr = rint ((axis->min - fl) * g->zoom.y);
2188 major_tick = axis->major * g->zoom.y;
2189 imin = (int) ((g->geom.height - offset + corr - g->wp.height) / major_tick + 1);
2190 imax = (int) ((g->geom.height - offset + corr) / major_tick);
2191 for (i=imin; i <= imax; i++) {
2194 int y = (int) (g->geom.height-1 - (int )rint (i * major_tick) -
2195 offset + corr + axis->s.y);
2197 debug(DBS_AXES_DRAWING) printf("%f @ %d\n",
2198 i*axis->major + fl, y);
2199 if (y < 0 || y > axis->p.height)
2201 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc,
2202 axis->s.width - 15, y, axis->s.width - 1, y);
2203 g_snprintf (desc, 32, "%.*f", rdigits, i*axis->major + fl);
2204 layout = gtk_widget_create_pango_layout(g->drawing_area, desc);
2205 pango_layout_get_pixel_size(layout, &w, &h);
2206 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2207 axis->s.width-14-4-w, y - h/2, layout);
2208 g_object_unref(G_OBJECT(layout));
2212 double minor_tick = axis->minor * g->zoom.y;
2213 imin = (int) ((g->geom.height - offset + corr - g->wp.height)/minor_tick + 1);
2214 imax = (int) ((g->geom.height - offset + corr) / minor_tick);
2215 for (i=imin; i <= imax; i++) {
2216 int y = (int) (g->geom.height-1 - (int )rint (i*minor_tick) -
2217 offset + corr + axis->s.y);
2219 debug (DBS_AXES_DRAWING) printf ("%f @ %d\n", i*axis->minor+fl, y);
2220 if (y > 0 && y < axis->p.height)
2221 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc,
2222 axis->s.width - 8, y,
2223 axis->s.width - 1, y);
2226 for (i=0; axis->label[i]; i++) {
2228 layout = gtk_widget_create_pango_layout(g->drawing_area,
2230 pango_layout_get_pixel_size(layout, &w, &h);
2231 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2232 (axis->p.width - w)/2,
2233 TITLEBAR_HEIGHT-10 - i*(h+3) - h,
2235 g_object_unref(G_OBJECT(layout));
2239 static void h_axis_pixmap_draw (struct axis *axis)
2241 struct graph *g = axis->g;
2243 double major_tick, minor_tick;
2244 int not_disp, rdigits, offset, imin, imax;
2245 double left, right, j, fl, corr;
2246 PangoLayout *layout;
2248 debug(DBS_FENTRY) puts ("h_axis_pixmap_draw()");
2249 left = (g->wp.x-g->geom.x) /
2250 (double )g->geom.width * g->bounds.width;
2252 right = (g->wp.x-g->geom.x+g->wp.width) /
2253 (double )g->geom.width * g->bounds.width;
2255 axis_compute_ticks (axis, left, right, AXIS_HORIZONTAL);
2257 j = axis->major - floor (axis->major);
2258 for (rdigits=0; rdigits<=6; rdigits++) {
2265 not_disp = 1 ^ axis->displayed;
2266 gdk_draw_rectangle (axis->pixmap[not_disp], g->bg_gc, TRUE, 0, 0,
2267 axis->p.width, axis->p.height);
2269 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, 0, 0,
2270 (gint) (axis->s.width + (axis->p.width-axis->s.width)/2.0), 0);
2271 offset = g->wp.x - g->geom.x;
2273 fl = floor (axis->min / axis->major) * axis->major;
2274 corr = rint ((axis->min - fl) * g->zoom.x);
2277 major_tick = axis->major*g->zoom.x;
2278 imin = (int) ((offset + corr) / major_tick + 1);
2279 imax = (int) ((offset + corr + axis->s.width) / major_tick);
2280 for (i=imin; i <= imax; i++) {
2283 int x = (int ) (rint (i * major_tick) - offset - corr);
2285 /* printf ("%f @ %d\n", i*axis->major + fl, x); */
2286 if (x < 0 || x > axis->s.width)
2288 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, x, 0, x, 15);
2289 g_snprintf (desc, 32, "%.*f", rdigits, i*axis->major + fl);
2290 layout = gtk_widget_create_pango_layout(g->drawing_area, desc);
2291 pango_layout_get_pixel_size(layout, &w, &h);
2292 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2293 x - w/2, 15+4, layout);
2294 g_object_unref(G_OBJECT(layout));
2296 if (axis->minor > 0) {
2298 minor_tick = axis->minor*g->zoom.x;
2299 imin = (int) ((offset + corr) / minor_tick + 1);
2300 imax = (int) ((offset + corr + g->wp.width) / minor_tick);
2301 for (i=imin; i <= imax; i++) {
2302 int x = (int) (rint (i * minor_tick) - offset - corr);
2303 if (x > 0 && x < axis->s.width)
2304 gdk_draw_line (axis->pixmap[not_disp], g->fg_gc, x, 0, x, 8);
2307 for (i=0; axis->label[i]; i++) {
2309 layout = gtk_widget_create_pango_layout(g->drawing_area,
2311 pango_layout_get_pixel_size(layout, &w, &h);
2312 gdk_draw_layout(axis->pixmap[not_disp], g->fg_gc,
2313 axis->s.width - w - 50, 15+h+15 + i*(h+3),
2315 g_object_unref(G_OBJECT(layout));
2319 static void axis_pixmaps_switch (struct axis *axis)
2321 axis->displayed = 1 ^ axis->displayed;
2324 static void axis_pixmap_display (struct axis *axis)
2326 gdk_draw_pixmap (axis->drawing_area->window, axis->g->fg_gc,
2327 axis->pixmap[axis->displayed], 0, 0, axis->p.x, axis->p.y,
2328 axis->p.width, axis->p.height);
2331 static void axis_compute_ticks (struct axis *axis, double x0, double xmax, int dir)
2333 int i, j, ii, jj, ms;
2334 double zoom, x, steps[3]={ 0.1, 0.5 };
2335 int dim, check_needed, diminished;
2336 double majthresh[2]={2.0, 3.0};
2338 debug((DBS_FENTRY | DBS_AXES_TICKS)) puts ("axis_compute_ticks()");
2339 debug(DBS_AXES_TICKS)
2340 printf ("x0=%f xmax=%f dir=%s\n", x0,xmax, dir?"VERTICAL":"HORIZONTAL");
2342 zoom = axis_zoom_get (axis, dir);
2344 for (i=-9; i<=12; i++) {
2345 if (x / pow (10, i) < 1)
2349 ms = (int )(x / pow (10, i));
2359 axis->major = steps[j] * pow (10, i);
2361 debug(DBS_AXES_TICKS) printf ("zoom=%.1f, x=%f -> i=%d -> ms=%d -> j=%d ->"
2362 " axis->major=%f\n", zoom, x, i, ms, j, axis->major);
2364 /* let's compute minor ticks */
2367 axis_ticks_down (&ii, &jj);
2368 axis->minor = steps[jj] * pow (10, ii);
2369 /* we don't want minors if they would be less than 10 pixels apart */
2370 if (axis->minor*zoom < 10) {
2371 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2372 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2376 check_needed = TRUE;
2378 while (check_needed) {
2379 check_needed = FALSE;
2380 dim = get_label_dim (axis, dir, xmax);
2381 debug(DBS_AXES_TICKS) printf ("axis->major==%.1f, axis->minor==%.1f =>"
2382 " axis->major*zoom/dim==%f, axis->minor*zoom/dim==%f\n",
2383 axis->major, axis->minor, axis->major*zoom/dim,
2384 axis->minor*zoom/dim);
2386 /* corrections: if majors are less than majthresh[dir] times label
2387 * dimension apart, we need to use bigger ones */
2388 if (axis->major*zoom / dim < majthresh[dir]) {
2389 axis_ticks_up (&ii, &jj);
2390 axis->minor = axis->major;
2391 axis_ticks_up (&i, &j);
2392 axis->major = steps[j] * pow (10, i);
2393 check_needed = TRUE;
2394 debug(DBS_AXES_TICKS) printf ("axis->major enlarged to %.1f\n",
2397 /* if minor ticks are bigger than majthresh[dir] times label dimension,
2398 * we could promote them to majors as well */
2399 if (axis->minor*zoom / dim > majthresh[dir] && !diminished) {
2400 axis_ticks_down (&i, &j);
2401 axis->major = axis->minor;
2402 axis_ticks_down (&ii, &jj);
2403 axis->minor = steps[jj] * pow (10, ii);
2404 check_needed = TRUE;
2407 debug(DBS_AXES_TICKS) printf ("axis->minor diminished to %.1f\n",
2410 if (axis->minor*zoom < 10) {
2411 debug(DBS_AXES_TICKS) printf ("refusing axis->minor of %f: "
2412 "axis->minor*zoom == %f\n", axis->minor, axis->minor*zoom);
2418 debug(DBS_AXES_TICKS) printf ("corrected: axis->major == %.1f -> "
2419 "axis->minor == %.1f\n", axis->major, axis->minor);
2422 static void axis_ticks_up (int *i, int *j)
2431 static void axis_ticks_down (int *i, int *j)
2440 static int get_label_dim (struct axis *axis, int dir, double label)
2445 PangoLayout *layout;
2447 /* First, let's compute how many digits to the right of radix
2448 * we need to print */
2449 y = axis->major - floor (axis->major);
2450 for (rdigits=0; rdigits<=6; rdigits++) {
2456 g_snprintf (str, 32, "%.*f", rdigits, label);
2458 case AXIS_HORIZONTAL:
2459 layout = gtk_widget_create_pango_layout(axis->g->drawing_area,
2461 pango_layout_get_pixel_size(layout, &dim, NULL);
2462 g_object_unref(G_OBJECT(layout));
2465 layout = gtk_widget_create_pango_layout(axis->g->drawing_area,
2467 pango_layout_get_pixel_size(layout, NULL, &dim);
2468 g_object_unref(G_OBJECT(layout));
2471 puts ("initialize axis: an axis must be either horizontal or vertical");
2477 static double axis_zoom_get (struct axis *axis, int dir)
2480 case AXIS_HORIZONTAL:
2481 return axis->g->zoom.x;
2483 return axis->g->zoom.y;
2489 static void graph_select_segment (struct graph *g, int x, int y)
2491 struct element_list *list;
2494 debug(DBS_FENTRY) puts ("graph_select_segment()");
2497 y = g->geom.height-1 - (y - g->geom.y);
2499 for (list=g->elists; list; list=list->next)
2500 for (e=list->elements; e->type != ELMT_NONE; e++) {
2505 if (line_detect_collision (e, x, y))
2506 cf_goto_frame(&cfile, e->parent->num);
2509 if (arc_detect_collision (e, x, y))
2510 cf_goto_frame(&cfile, e->parent->num);
2518 static int line_detect_collision (struct element *e, int x, int y)
2522 if (e->p.line.dim.x1 < e->p.line.dim.x2) {
2523 x1 = (int )rint (e->p.line.dim.x1);
2524 x2 = (int )rint (e->p.line.dim.x2);
2526 x1 = (int )rint (e->p.line.dim.x2);
2527 x2 = (int )rint (e->p.line.dim.x1);
2529 if (e->p.line.dim.y1 < e->p.line.dim.y2) {
2530 y1 = (int )rint (e->p.line.dim.y1);
2531 y2 = (int )rint (e->p.line.dim.y2);
2533 y1 = (int )rint (e->p.line.dim.y2);
2534 y2 = (int )rint (e->p.line.dim.y1);
2537 printf ("line: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", x1, y1, x2, y2, x, y);
2539 if ((x1==x && x2==x && y1<=y && y<=y2)||(y1==y && y2==y && x1<=x && x<=x2))
2545 static int arc_detect_collision (struct element *e, int x, int y)
2549 x1 = (int )rint (e->p.arc.dim.x);
2550 x2 = (int )rint (e->p.arc.dim.x + e->p.arc.dim.width);
2551 y1 = (int )rint (e->p.arc.dim.y - e->p.arc.dim.height);
2552 y2 = (int )rint (e->p.arc.dim.y);
2554 printf ("arc: (%d,%d)->(%d,%d), clicked: (%d,%d)\n", x1, y1, x2, y2, x, y);
2556 if (x1<=x && x<=x2 && y1<=y && y<=y2)
2562 static void cross_xor (struct graph *g, int x, int y)
2564 if (x > g->wp.x && x < g->wp.x+g->wp.width &&
2565 y >= g->wp.y && y < g->wp.y+g->wp.height) {
2566 gdk_draw_line (g->drawing_area->window, xor_gc, g->wp.x,
2567 y, g->wp.x + g->wp.width, y);
2568 gdk_draw_line (g->drawing_area->window, xor_gc, x,
2569 g->wp.y, x, g->wp.y + g->wp.height);
2573 static void cross_draw (struct graph *g, int x, int y)
2575 cross_xor (g, x, y);
2578 g->cross.erase_needed = 1;
2581 static void cross_erase (struct graph *g)
2583 cross_xor (g, g->cross.x, g->cross.y);
2584 g->cross.erase_needed = 0;
2587 static void magnify_create (struct graph *g, int x, int y)
2590 struct element_list *list, *new_list;
2591 struct ipoint pos, offsetpos;
2594 mg = g->magnify.g = (struct graph * )g_malloc (sizeof (struct graph));
2595 memcpy ((void * )mg, (void * )g, sizeof (struct graph));
2597 mg->toplevel = dlg_window_new("tcp graph magnify");
2598 mg->drawing_area = mg->toplevel;
2599 gtk_window_set_default_size(GTK_WINDOW(mg->toplevel), g->magnify.width, g->magnify.height);
2600 gtk_widget_set_events (mg->drawing_area, GDK_EXPOSURE_MASK
2601 /* | GDK_ENTER_NOTIFY_MASK */
2602 /* | GDK_ALL_EVENTS_MASK */
2607 mg->wp.width = g->magnify.width;
2608 mg->wp.height = g->magnify.height;
2609 mg->geom.width = (int )rint (g->geom.width * g->magnify.zoom.x);
2610 mg->geom.height = (int )rint (g->geom.height * g->magnify.zoom.y);
2611 mg->zoom.x = (mg->geom.width - 1) / g->bounds.width;
2612 mg->zoom.y = (mg->geom.height- 1) / g->bounds.height;
2614 /* in order to keep original element lists intact we need our own */
2615 graph_element_lists_initialize (mg);
2616 list = g->elists->next;
2617 new_list = mg->elists;
2618 for ( ; list; list=list->next) {
2620 (struct element_list * )g_malloc (sizeof (struct element_list));
2621 new_list = new_list->next;
2622 new_list->next = NULL;
2623 new_list->elements = NULL;
2625 graph_element_lists_make (mg);
2627 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &pos.x, &pos.y);
2628 g->magnify.x = pos.x + x - g->magnify.width/2;
2629 g->magnify.y = pos.y + y - g->magnify.height/2;
2630 offsetpos.x = g->magnify.x + g->magnify.offset.x;
2631 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
2632 offsetpos.y = g->magnify.y + g->magnify.offset.y;
2633 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
2634 gtk_widget_set_uposition (mg->drawing_area, offsetpos.x, offsetpos.y);
2635 magnify_get_geom (g, x, y);
2637 gtk_widget_show (mg->drawing_area);
2639 /* we need to wait for the first expose event before we start drawing */
2640 while (!gdk_events_pending ());
2642 e = gdk_event_get ();
2644 if (e->any.type == GDK_EXPOSE) {
2652 mg->pixmap[0] = mg->pixmap[1] = NULL;
2653 graph_pixmaps_create (mg);
2655 g->magnify.active = 1;
2658 static void magnify_move (struct graph *g, int x, int y)
2660 struct ipoint pos, offsetpos;
2662 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &pos.x, &pos.y);
2663 g->magnify.x = pos.x + x - g->magnify.width/2;
2664 g->magnify.y = pos.y + y - g->magnify.height/2;
2665 offsetpos.x = g->magnify.x + g->magnify.offset.x;
2666 offsetpos.x = offsetpos.x >= 0 ? offsetpos.x : 0;
2667 offsetpos.y = g->magnify.y + g->magnify.offset.y;
2668 offsetpos.y = offsetpos.y >= 0 ? offsetpos.y : 0;
2669 magnify_get_geom (g, x, y);
2670 gtk_widget_set_uposition (g->magnify.g->drawing_area, offsetpos.x,
2675 static void magnify_destroy (struct graph *g)
2677 struct element_list *list;
2678 struct graph *mg = g->magnify.g;
2680 window_destroy (GTK_WIDGET (mg->drawing_area));
2681 gdk_pixmap_unref (mg->pixmap[0]);
2682 gdk_pixmap_unref (mg->pixmap[1]);
2683 for (list=mg->elists; list; list=list->next)
2684 g_free (list->elements);
2685 while (mg->elists->next) {
2686 list = mg->elists->next->next;
2687 g_free (mg->elists->next);
2688 mg->elists->next = list;
2690 g_free (g->magnify.g);
2691 g->magnify.active = 0;
2694 static void magnify_get_geom (struct graph *g, int x, int y)
2698 gdk_window_get_position (GTK_WIDGET (g->toplevel)->window, &posx, &posy);
2700 g->magnify.g->geom.x = g->geom.x;
2701 g->magnify.g->geom.y = g->geom.y;
2703 g->magnify.g->geom.x -=
2704 (int )rint ((g->magnify.g->geom.width - g->geom.width) *
2705 ((x-g->geom.x)/(double )g->geom.width));
2706 g->magnify.g->geom.y -=
2707 (int )rint ((g->magnify.g->geom.height - g->geom.height) *
2708 ((y-g->geom.y)/(double )g->geom.height));
2710 /* we have coords of origin of graph relative to origin of g->toplevel.
2711 * now we need them to relate to origin of magnify window */
2712 g->magnify.g->geom.x -= (g->magnify.x - posx);
2713 g->magnify.g->geom.y -= (g->magnify.y - posy);
2716 static void magnify_draw (struct graph *g)
2718 int not_disp = 1 ^ g->magnify.g->displayed;
2720 graph_pixmap_draw (g->magnify.g);
2721 /* graph pixmap is almost ready, just add border */
2722 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0, 0,
2723 g->magnify.width - 1, 0);
2724 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc,
2725 g->magnify.width - 1, 0, g->magnify.width - 1, g->magnify.height);
2726 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0, 0,
2727 0, g->magnify.height - 1);
2728 gdk_draw_line (g->magnify.g->pixmap[not_disp], g->fg_gc, 0,
2729 g->magnify.height - 1, g->magnify.width - 1, g->magnify.height - 1);
2731 graph_pixmaps_switch (g->magnify.g);
2732 graph_pixmap_display (g->magnify.g);
2736 static gint configure_event (GtkWidget *widget, GdkEventConfigure *event)
2738 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2742 int cur_g_width, cur_g_height;
2743 int cur_wp_width, cur_wp_height;
2745 debug(DBS_FENTRY) puts ("configure_event()");
2747 cur_wp_width = g->wp.width;
2748 cur_wp_height = g->wp.height;
2749 g->wp.width = event->width - g->y_axis->p.width - RMARGIN_WIDTH;
2750 g->wp.height = event->height - g->x_axis->p.height - g->wp.y;
2751 g->x_axis->s.width = g->wp.width;
2752 g->x_axis->p.width = g->wp.width + RMARGIN_WIDTH;
2753 g->y_axis->p.height = g->wp.height + g->wp.y;
2754 g->y_axis->s.height = g->wp.height;
2755 g->x_axis->p.y = g->y_axis->p.height;
2756 zoom.x = (double )g->wp.width / cur_wp_width;
2757 zoom.y = (double )g->wp.height / cur_wp_height;
2758 cur_g_width = g->geom.width;
2759 cur_g_height = g->geom.height;
2760 g->geom.width = (int )rint (g->geom.width * zoom.x);
2761 g->geom.height = (int )rint (g->geom.height * zoom.y);
2762 g->zoom.x = (double )(g->geom.width - 1) / g->bounds.width;
2763 g->zoom.y = (double )(g->geom.height -1) / g->bounds.height;
2764 /* g->zoom.initial.x = g->zoom.x; */
2765 /* g->zoom.initial.y = g->zoom.y; */
2767 g->geom.x = (int) (g->wp.x - (double )g->geom.width/cur_g_width *
2768 (g->wp.x - g->geom.x));
2769 g->geom.y = (int) (g->wp.y - (double )g->geom.height/cur_g_height *
2770 (g->wp.y - g->geom.y));
2772 printf ("configure: graph: (%d,%d), (%d,%d); viewport: (%d,%d), (%d,%d); "
2773 "zooms: (%f,%f)\n", g->geom.x, g->geom.y, g->geom.width,
2774 g->geom.height, g->wp.x, g->wp.y, g->wp.width, g->wp.height,
2775 g->zoom.x, g->zoom.y);
2778 update_zoom_spins (g);
2779 graph_element_lists_make (g);
2780 graph_pixmaps_create (g);
2781 graph_title_pixmap_create (g);
2782 axis_pixmaps_create (g->y_axis);
2783 axis_pixmaps_create (g->x_axis);
2784 /* we don't do actual drawing here; we leave it to expose handler */
2785 graph_pixmap_draw (g);
2786 graph_pixmaps_switch (g);
2787 graph_title_pixmap_draw (g);
2788 h_axis_pixmap_draw (g->x_axis);
2789 axis_pixmaps_switch (g->x_axis);
2790 v_axis_pixmap_draw (g->y_axis);
2791 axis_pixmaps_switch (g->y_axis);
2795 static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
2797 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2799 debug(DBS_FENTRY) puts ("expose_event()");
2804 /* lower left corner */
2805 gdk_draw_rectangle (g->drawing_area->window, g->bg_gc, TRUE, 0,
2806 g->wp.y + g->wp.height, g->y_axis->p.width, g->x_axis->p.height);
2808 gdk_draw_rectangle (g->drawing_area->window, g->bg_gc, TRUE,
2809 g->wp.x + g->wp.width, g->wp.y, RMARGIN_WIDTH, g->wp.height);
2811 graph_pixmap_display (g);
2812 graph_title_pixmap_display (g);
2813 axis_pixmap_display (g->x_axis);
2814 axis_pixmap_display (g->y_axis);
2819 static gint button_press_event (GtkWidget *widget, GdkEventButton *event)
2821 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2823 debug(DBS_FENTRY) puts ("button_press_event()");
2825 if (event->button == 3) {
2826 if (event->state & GDK_CONTROL_MASK)
2827 magnify_create (g, (int )rint (event->x), (int )rint (event->y));
2829 g->grab.x = (int )rint (event->x) - g->geom.x;
2830 g->grab.y = (int )rint (event->y) - g->geom.y;
2831 g->grab.grabbed = TRUE;
2834 /* Windows mouse control: */
2835 /* [<ctrl>-left] - select packet */
2836 /* [left] - zoom in */
2837 /* [<shift>-left] - zoom out */
2838 } else if (event->button == 1) {
2839 if (event->state & GDK_CONTROL_MASK) {
2840 graph_select_segment (g, (int)event->x, (int)event->y);
2843 } else if (event->button == 2) {
2845 int cur_width = g->geom.width, cur_height = g->geom.height;
2846 struct { double x, y; } factor;
2848 if (g->zoom.flags & ZOOM_OUT) {
2849 if (g->zoom.flags & ZOOM_HLOCK)
2852 factor.x = 1 / g->zoom.step_x;
2853 if (g->zoom.flags & ZOOM_VLOCK)
2856 factor.y = 1 / g->zoom.step_y;
2858 if (g->zoom.flags & ZOOM_HLOCK)
2861 factor.x = g->zoom.step_x;
2862 if (g->zoom.flags & ZOOM_VLOCK)
2865 factor.y = g->zoom.step_y;
2868 g->geom.width = (int )rint (g->geom.width * factor.x);
2869 g->geom.height = (int )rint (g->geom.height * factor.y);
2870 if (g->geom.width < g->wp.width)
2871 g->geom.width = g->wp.width;
2872 if (g->geom.height < g->wp.height)
2873 g->geom.height = g->wp.height;
2874 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
2875 g->zoom.y = (g->geom.height- 1) / g->bounds.height;
2877 g->geom.x -= (int )rint ((g->geom.width - cur_width) *
2878 ((event->x-g->geom.x)/(double )cur_width));
2879 g->geom.y -= (int )rint ((g->geom.height - cur_height) *
2880 ((event->y-g->geom.y)/(double )cur_height));
2882 if (g->geom.x > g->wp.x)
2883 g->geom.x = g->wp.x;
2884 if (g->geom.y > g->wp.y)
2885 g->geom.y = g->wp.y;
2886 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2887 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2888 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2889 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2891 printf ("button press: graph: (%d,%d), (%d,%d); viewport: (%d,%d), "
2892 "(%d,%d); zooms: (%f,%f)\n", g->geom.x, g->geom.y,
2893 g->geom.width, g->geom.height, g->wp.x, g->wp.y, g->wp.width,
2894 g->wp.height, g->zoom.x, g->zoom.y);
2896 graph_element_lists_make (g);
2897 g->cross.erase_needed = 0;
2899 axis_display (g->y_axis);
2900 axis_display (g->x_axis);
2901 update_zoom_spins (g);
2903 cross_draw (g, (int) event->x, (int) event->y);
2905 } else if (event->button == 1) {
2906 graph_select_segment (g, (int )event->x, (int )event->y);
2914 static gint motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
2916 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2918 GdkModifierType state;
2920 /* debug(DBS_FENTRY) puts ("motion_notify_event()"); */
2923 gdk_window_get_pointer (event->window, &x, &y, &state);
2927 state = event->state;
2930 /* Testing just (state & GDK_BUTTON1_MASK) is not enough since when button1
2931 * is pressed while pointer is in motion, we will receive one more motion
2932 * notify *before* we get the button press. This last motion notify works
2933 * with stale grab coordinates */
2934 if (state & GDK_BUTTON3_MASK) {
2935 if (g->grab.grabbed) {
2936 g->geom.x = x-g->grab.x;
2937 g->geom.y = y-g->grab.y;
2939 if (g->geom.x > g->wp.x)
2940 g->geom.x = g->wp.x;
2941 if (g->geom.y > g->wp.y)
2942 g->geom.y = g->wp.y;
2943 if (g->wp.x + g->wp.width > g->geom.x + g->geom.width)
2944 g->geom.x = g->wp.width + g->wp.x - g->geom.width;
2945 if (g->wp.y + g->wp.height > g->geom.y + g->geom.height)
2946 g->geom.y = g->wp.height + g->wp.y - g->geom.height;
2947 g->cross.erase_needed = 0;
2949 axis_display (g->y_axis);
2950 axis_display (g->x_axis);
2952 cross_draw (g, x, y);
2953 } else if (g->magnify.active)
2954 magnify_move (g, x, y);
2955 } else if (state & GDK_BUTTON1_MASK) {
2956 graph_select_segment (g, x, y);
2957 if (g->cross.erase_needed)
2960 cross_draw (g, x, y);
2962 if (g->cross.erase_needed)
2965 cross_draw (g, x, y);
2971 static gint button_release_event (GtkWidget *widget, GdkEventButton *event)
2973 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2975 debug(DBS_FENTRY) puts ("button_release_event()");
2977 if (event->button == 3)
2978 g->grab.grabbed = FALSE;
2980 if (g->magnify.active)
2981 magnify_destroy (g);
2985 static gint key_press_event (GtkWidget *widget, GdkEventKey *event)
2987 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
2989 debug(DBS_FENTRY) puts ("key_press_event()");
2991 if (event->keyval == 32 /*space*/) {
2994 if (g->cross.draw) {
2996 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
2998 } else if (g->cross.erase_needed) {
3002 /* toggle buttons emit their "toggled" signals so don't bother doing
3003 * any real work here, it will be done in signal handlers */
3005 gtk_toggle_button_set_active (g->cross.on_toggle, TRUE);
3007 gtk_toggle_button_set_active (g->cross.off_toggle, TRUE);
3008 } else if (event->keyval == 't')
3009 toggle_time_origin (g);
3010 else if (event->keyval == 's')
3011 toggle_seq_origin (g);
3012 else if (event->keyval == GDK_Shift_L) {
3013 /* g->zoom.flags |= ZOOM_OUT; */
3014 gtk_toggle_button_set_active (g->zoom.widget.out_toggle, TRUE);
3019 static gint key_release_event (GtkWidget *widget, GdkEventKey *event)
3021 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3023 debug(DBS_FENTRY) puts ("key_release_event()");
3025 if (event->keyval == GDK_Shift_L || event->keyval == GDK_ISO_Prev_Group) {
3026 /* g->zoom.flags &= ~ZOOM_OUT; */
3027 gtk_toggle_button_set_active (g->zoom.widget.in_toggle, TRUE);
3032 static gint leave_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_)
3034 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3036 if (g->cross.erase_needed)
3042 static gint enter_notify_event (GtkWidget *widget, GdkEventCrossing *event _U_)
3044 struct graph *g = (struct graph *) g_object_get_data(G_OBJECT(widget), "graph");
3046 /* graph_pixmap_display (g); */
3047 if (g->cross.draw) {
3049 gdk_window_get_pointer (g->drawing_area->window, &x, &y, 0);
3050 cross_draw (g, x, y);
3055 static void toggle_time_origin (struct graph *g)
3058 case GRAPH_TSEQ_STEVENS:
3059 tseq_stevens_toggle_time_origin (g);
3061 case GRAPH_TSEQ_TCPTRACE:
3062 tseq_tcptrace_toggle_time_origin (g);
3064 case GRAPH_THROUGHPUT:
3065 tput_toggle_time_origin (g);
3070 axis_display (g->x_axis);
3073 static void toggle_seq_origin (struct graph *g)
3076 case GRAPH_TSEQ_STEVENS:
3077 tseq_stevens_toggle_seq_origin (g);
3078 axis_display (g->y_axis);
3080 case GRAPH_TSEQ_TCPTRACE:
3081 tseq_tcptrace_toggle_seq_origin (g);
3082 axis_display (g->y_axis);
3085 rtt_toggle_seq_origin (g);
3086 axis_display (g->x_axis);
3093 static int get_num_dsegs (struct graph *g)
3096 struct segment *tmp;
3098 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3099 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3100 g->current->th_sport, g->current->th_dport,
3101 &tmp->ip_src, &tmp->ip_dst,
3102 tmp->th_sport, tmp->th_dport,
3103 COMPARE_CURR_DIR)) {
3110 static int get_num_acks (struct graph *g)
3113 struct segment *tmp;
3115 for (tmp=g->segments, count=0; tmp; tmp=tmp->next) {
3116 if(!compare_headers(&g->current->ip_src, &g->current->ip_dst,
3117 g->current->th_sport, g->current->th_dport,
3118 &tmp->ip_src, &tmp->ip_dst,
3119 tmp->th_sport, tmp->th_dport,
3120 COMPARE_CURR_DIR)) {
3128 * Stevens-style time-sequence grapH
3131 static void tseq_stevens_read_config (struct graph *g)
3133 debug(DBS_FENTRY) puts ("tseq_stevens_read_config()");
3135 g->s.tseq_stevens.seq_width = 4;
3136 g->s.tseq_stevens.seq_height = 4;
3137 g->s.tseq_stevens.flags = 0;
3139 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3140 g->title[0] = "Time/Sequence Graph";
3142 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3143 g->y_axis->label[0] = "number[B]";
3144 g->y_axis->label[1] = "Sequence";
3145 g->y_axis->label[2] = NULL;
3146 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3147 g->x_axis->label[0] = "Time[s]";
3148 g->x_axis->label[1] = NULL;
3151 /* Used by both 'stevens' and 'tcptrace' */
3152 static void tseq_initialize (struct graph *g)
3154 debug(DBS_FENTRY) puts ("tseq_initialize()");
3155 tseq_get_bounds (g);
3161 case GRAPH_TSEQ_STEVENS:
3162 tseq_stevens_read_config(g);
3164 case GRAPH_TSEQ_TCPTRACE:
3165 tseq_tcptrace_read_config(g);
3171 /* Determine "bounds"
3172 * Essentially: look for lowest/highest time and seq in the list of segments
3173 * Note that for tcptrace the "(ack + window) sequence number" would normally be expected
3174 * to be the upper bound; However, just to be safe, include the data seg sequence numbers
3175 * in the comparison for tcptrace
3176 * (e.g. to handle the case of only data segments).
3179 /* ToDo: worry about handling cases such as trying to plot seq of just 1 frame */
3181 static void tseq_get_bounds (struct graph *g)
3183 struct segment *tmp;
3185 gboolean data_frame_seen=FALSE;
3186 double data_tim_low=0;
3187 double data_tim_high=0;
3188 guint32 data_seq_cur;
3189 guint32 data_seq_nxt;
3190 guint32 data_seq_low=0;
3191 guint32 data_seq_high=0;
3192 gboolean ack_frame_seen=FALSE;
3193 double ack_tim_low=0;
3194 double ack_tim_high=0;
3195 guint32 ack_seq_cur;
3196 guint32 ack_seq_low=0;
3197 guint32 win_seq_cur;
3198 guint32 win_seq_high=0;
3200 /* go thru all segments to determine "bounds" */
3201 for (tmp=g->segments; tmp; tmp=tmp->next) {
3202 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3203 g->current->th_sport, g->current->th_dport,
3204 &tmp->ip_src, &tmp->ip_dst,
3205 tmp->th_sport, tmp->th_dport,
3206 COMPARE_CURR_DIR)) {
3209 tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3210 data_seq_cur = tmp->th_seq;
3211 data_seq_nxt = data_seq_cur + tmp->th_seglen;
3212 if (! data_frame_seen) {
3213 data_tim_low = data_tim_high = tim;
3214 data_seq_low = data_seq_cur;
3215 data_seq_high = data_seq_nxt;
3216 data_frame_seen = TRUE;
3218 if (tim < data_tim_low) data_tim_low = tim;
3219 if (tim > data_tim_high) data_tim_high = tim;
3220 if (data_seq_cur < data_seq_low) data_seq_low = data_seq_cur;
3221 if (data_seq_nxt > data_seq_high) data_seq_high = data_seq_nxt;
3223 else { /* ack seg */
3224 /* skip ack processing if no ACK (e.g. in RST) */
3225 if (TCP_ACK (tmp->th_flags)) {
3226 tim = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3227 ack_seq_cur = tmp->th_ack;
3228 win_seq_cur = ack_seq_cur + tmp->th_win;
3229 if (! ack_frame_seen) {
3230 ack_tim_low = ack_tim_high = tim;
3231 ack_seq_low = ack_seq_cur;
3232 win_seq_high = win_seq_cur;
3233 ack_frame_seen = TRUE;
3235 if (tim < ack_tim_low) ack_tim_low = tim;
3236 if (tim > ack_tim_high) ack_tim_high = tim;
3237 if (ack_seq_cur < ack_seq_low) ack_seq_low = ack_seq_cur;
3238 if (win_seq_cur > win_seq_high) win_seq_high = win_seq_cur;
3243 /* if 'stevens': use only data segments to determine bounds */
3244 /* if 'tcptrace': use both data and ack segments to determine bounds */
3246 case GRAPH_TSEQ_STEVENS:
3247 g->bounds.x0 = data_tim_low;
3248 g->bounds.width = data_tim_high - data_tim_low;
3249 g->bounds.y0 = data_seq_low;
3250 g->bounds.height = data_seq_high - data_seq_low;
3252 case GRAPH_TSEQ_TCPTRACE:
3253 /* If (ack_frame_seen == false) -> use 'data' segments.
3254 * Else If (data_frame_seen == false) -> use 'ack' segments.
3255 * Else -> use both data and ack segments.
3257 g->bounds.x0 = ((data_tim_low <= ack_tim_low && data_frame_seen) || (! ack_frame_seen)) ? data_tim_low : ack_tim_low;
3258 g->bounds.width = (((data_tim_high >= ack_tim_high && data_frame_seen) || (! ack_frame_seen)) ? data_tim_high : ack_tim_high) - g->bounds.x0;
3259 g->bounds.y0 = ((data_seq_low <= ack_seq_low && data_frame_seen) || (! ack_frame_seen)) ? data_seq_low : ack_seq_low;
3260 g->bounds.height = (((data_seq_high >= win_seq_high && data_frame_seen) || (! ack_frame_seen)) ? data_seq_high : win_seq_high) - g->bounds.y0;
3264 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3265 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3269 static void tseq_stevens_make_elmtlist (struct graph *g)
3271 struct segment *tmp;
3272 struct element *elements, *e;
3273 double x0 = g->bounds.x0, y0 = g->bounds.y0;
3274 guint32 seq_base = (guint32) y0;
3277 debug(DBS_FENTRY) puts ("tseq_stevens_make_elmtlist()");
3278 if (g->elists->elements == NULL) {
3279 int n = 1 + get_num_dsegs (g);
3280 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
3282 e = elements = g->elists->elements;
3284 for (tmp=g->segments; tmp; tmp=tmp->next) {
3287 if(!compare_headers(&g->current->ip_src, &g->current->ip_dst,
3288 g->current->th_sport, g->current->th_dport,
3289 &tmp->ip_src, &tmp->ip_dst,
3290 tmp->th_sport, tmp->th_dport,
3291 COMPARE_CURR_DIR)) {
3295 seq_cur = tmp->th_seq - seq_base;
3296 secs = g->zoom.x * (tmp->rel_secs + tmp->rel_usecs / 1000000.0 - x0);
3297 seqno = g->zoom.y * seq_cur;
3302 e->p.arc.dim.width = g->s.tseq_stevens.seq_width;
3303 e->p.arc.dim.height = g->s.tseq_stevens.seq_height;
3304 e->p.arc.dim.x = secs - g->s.tseq_stevens.seq_width/2.0;
3305 e->p.arc.dim.y = seqno + g->s.tseq_stevens.seq_height/2.0;
3306 e->p.arc.filled = TRUE;
3307 e->p.arc.angle1 = 0;
3308 e->p.arc.angle2 = 23040;
3311 e->type = ELMT_NONE;
3312 g->elists->elements = elements;
3315 static void tseq_stevens_toggle_seq_origin (struct graph *g)
3317 g->s.tseq_stevens.flags ^= SEQ_ORIGIN;
3319 if ((g->s.tseq_stevens.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3320 g->y_axis->min = g->bounds.y0;
3321 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
3325 static void tseq_stevens_toggle_time_origin (struct graph *g)
3327 g->s.tseq_stevens.flags ^= TIME_ORIGIN;
3329 if ((g->s.tseq_stevens.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3330 g->x_axis->min = g->bounds.x0;
3331 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3336 * tcptrace-style time-sequence graph
3339 static void tseq_tcptrace_read_config (struct graph *g)
3341 GdkColormap *colormap;
3344 g->s.tseq_tcptrace.flags = 0;
3345 g->s.tseq_tcptrace.gc_seq = gdk_gc_new (g->drawing_area->window);
3346 g->s.tseq_tcptrace.gc_ack[0] = gdk_gc_new (g->drawing_area->window);
3347 g->s.tseq_tcptrace.gc_ack[1] = gdk_gc_new (g->drawing_area->window);
3348 colormap = gdk_window_get_colormap (g->drawing_area->window);
3349 if (!gdk_color_parse ("black", &color)) {
3351 * XXX - do more than just warn.
3353 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3354 "Could not parse color black.");
3356 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
3358 * XXX - do more than just warn.
3360 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3361 "Could not allocate color black.");
3363 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_seq, &color);
3364 if (!gdk_color_parse ("LightSlateGray", &color)) {
3366 * XXX - do more than just warn.
3368 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3369 "Could not parse color LightSlateGray.");
3371 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
3373 * XXX - do more than just warn.
3375 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3376 "Could not allocate color LightSlateGray.");
3378 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_ack[0], &color);
3379 if (!gdk_color_parse ("LightGray", &color)) {
3381 * XXX - do more than just warn.
3383 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3384 "Could not parse color LightGray.");
3386 if (!gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE)) {
3388 * XXX - do more than just warn.
3390 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3391 "Could not allocate color LightGray.");
3393 gdk_gc_set_foreground (g->s.tseq_tcptrace.gc_ack[1], &color);
3395 g->elists->next = (struct element_list * )
3396 g_malloc (sizeof (struct element_list));
3397 g->elists->next->next = NULL;
3398 g->elists->next->elements = NULL;
3400 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3401 g->title[0] = "Time/Sequence Graph";
3403 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3404 g->y_axis->label[0] = "number[B]";
3405 g->y_axis->label[1] = "Sequence";
3406 g->y_axis->label[2] = NULL;
3407 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3408 g->x_axis->label[0] = "Time[s]";
3409 g->x_axis->label[1] = NULL;
3412 static void tseq_tcptrace_make_elmtlist (struct graph *g)
3414 struct segment *tmp;
3415 struct element *elements0, *e0; /* list of elmts with prio 0 */
3416 struct element *elements1, *e1; /* list of elmts with prio 1 */
3418 double p_t = 0; /* ackno, window and time of previous segment */
3419 double p_ackno = 0, p_win = 0;
3420 gboolean ack_seen=FALSE;
3425 debug(DBS_FENTRY) puts ("tseq_tcptrace_make_elmtlist()");
3427 if (g->elists->elements == NULL) {
3428 int n = 1 + 4*get_num_acks(g);
3429 e0 = elements0 = (struct element * )g_malloc (n*sizeof (struct element));
3431 e0 = elements0 = g->elists->elements;
3433 if (g->elists->next->elements == NULL ) {
3434 int n = 1 + 3*get_num_dsegs(g);
3435 e1 = elements1 = (struct element * )g_malloc (n*sizeof (struct element));
3437 e1 = elements1 = g->elists->next->elements;
3441 seq_base = (guint32) y0;
3443 for (tmp=g->segments; tmp; tmp=tmp->next) {
3447 secs = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3450 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3451 g->current->th_sport, g->current->th_dport,
3452 &tmp->ip_src, &tmp->ip_dst,
3453 tmp->th_sport, tmp->th_dport,
3454 COMPARE_CURR_DIR)) {
3455 /* forward direction -> we need seqno and amount of data */
3458 seq_cur = tmp->th_seq - seq_base;
3459 if (TCP_SYN (tmp->th_flags) || TCP_FIN (tmp->th_flags))
3462 data = tmp->th_seglen;
3464 y1 = g->zoom.y * (seq_cur);
3465 y2 = g->zoom.y * (seq_cur + data);
3466 e1->type = ELMT_LINE;
3468 e1->gc = g->s.tseq_tcptrace.gc_seq;
3469 e1->p.line.dim.x1 = e1->p.line.dim.x2 = x;
3470 e1->p.line.dim.y1 = y1;
3471 e1->p.line.dim.y2 = y2;
3473 e1->type = ELMT_LINE;
3475 e1->gc = g->s.tseq_tcptrace.gc_seq;
3476 e1->p.line.dim.x1 = x - 1;
3477 e1->p.line.dim.x2 = x + 1;
3478 e1->p.line.dim.y1 = e1->p.line.dim.y2 = y1;
3480 e1->type = ELMT_LINE;
3482 e1->gc = g->s.tseq_tcptrace.gc_seq;
3483 e1->p.line.dim.x1 = x + 1;
3484 e1->p.line.dim.x2 = x - 1;
3485 e1->p.line.dim.y1 = e1->p.line.dim.y2 = y2;
3489 if (! TCP_ACK (tmp->th_flags))
3490 /* SYN's and RST's do not necessarily have ACK's*/
3492 /* backward direction -> we need ackno and window */
3493 seq_cur = tmp->th_ack - seq_base;
3494 ackno = seq_cur * g->zoom.y;
3495 win = tmp->th_win * g->zoom.y;
3498 if (ack_seen == TRUE) { /* don't plot the first ack */
3499 e0->type = ELMT_LINE;
3501 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3502 e0->p.line.dim.x1 = p_t;
3503 e0->p.line.dim.y1 = p_ackno;
3504 e0->p.line.dim.x2 = x;
3505 e0->p.line.dim.y2 = p_ackno;
3507 e0->type = ELMT_LINE;
3509 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3510 e0->p.line.dim.x1 = x;
3511 e0->p.line.dim.y1 = p_ackno;
3512 e0->p.line.dim.x2 = x;
3513 e0->p.line.dim.y2 = ackno!=p_ackno || ackno<4 ? ackno : ackno-4;
3516 e0->type = ELMT_LINE;
3518 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3519 e0->p.line.dim.x1 = p_t;
3520 e0->p.line.dim.y1 = p_win + p_ackno;
3521 e0->p.line.dim.x2 = x;
3522 e0->p.line.dim.y2 = p_win + p_ackno;
3524 e0->type = ELMT_LINE;
3526 e0->gc = g->s.tseq_tcptrace.gc_ack[toggle];
3527 e0->p.line.dim.x1 = x;
3528 e0->p.line.dim.y1 = p_win + p_ackno;
3529 e0->p.line.dim.x2 = x;
3530 e0->p.line.dim.y2 = win + ackno;
3540 e0->type = ELMT_NONE;
3541 e1->type = ELMT_NONE;
3542 g->elists->elements = elements0;
3543 g->elists->next->elements = elements1;
3546 static void tseq_tcptrace_toggle_seq_origin (struct graph *g)
3548 g->s.tseq_tcptrace.flags ^= SEQ_ORIGIN;
3550 if ((g->s.tseq_tcptrace.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3551 g->y_axis->min = g->bounds.y0;
3552 else /* g->tseq_stevens.flags & SEQ_ORIGIN == SEQ_ORIGIN_ISN */
3556 static void tseq_tcptrace_toggle_time_origin (struct graph *g)
3558 g->s.tseq_tcptrace.flags ^= TIME_ORIGIN;
3560 if ((g->s.tseq_tcptrace.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3561 g->x_axis->min = g->bounds.x0;
3562 else /* g->tseq_stevens.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3570 static void tput_make_elmtlist (struct graph *g)
3572 struct segment *tmp, *oldest;
3573 struct element *elements, *e;
3577 if (g->elists->elements == NULL) {
3578 int n = 1 + get_num_dsegs (g);
3579 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
3581 e = elements = g->elists->elements;
3583 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
3584 double time = tmp->rel_secs + tmp->rel_usecs/1000000.0;
3585 dtime = time - (oldest->rel_secs + oldest->rel_usecs/1000000.0);
3586 if (i>g->s.tput.nsegs) {
3587 sum -= oldest->th_seglen;
3588 oldest=oldest->next;
3590 sum += tmp->th_seglen;
3592 /* debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput); */
3597 e->p.arc.dim.width = g->s.tput.width;
3598 e->p.arc.dim.height = g->s.tput.height;
3599 e->p.arc.dim.x = g->zoom.x*(time - g->bounds.x0) - g->s.tput.width/2.0;
3600 e->p.arc.dim.y = g->zoom.y*tput + g->s.tput.height/2.0;
3601 e->p.arc.filled = TRUE;
3602 e->p.arc.angle1 = 0;
3603 e->p.arc.angle2 = 23040;
3606 e->type = ELMT_NONE;
3607 g->elists->elements = elements;
3610 /* Purpose of <graph_type>_initialize functions:
3611 * - find maximum and minimum for both axes
3612 * - call setup routine for style struct */
3613 static void tput_initialize (struct graph *g)
3615 struct segment *tmp, *oldest, *last;
3617 double dtime, tput, tputmax=0;
3618 double t, t0, tmax = 0, y0, ymax;
3620 debug(DBS_FENTRY) puts ("tput_initialize()");
3622 tput_read_config(g);
3624 for (last=g->segments; last->next; last=last->next);
3625 for (oldest=g->segments,tmp=g->segments->next,i=0; tmp; tmp=tmp->next,i++) {
3626 dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 -
3627 (oldest->rel_secs + oldest->rel_usecs/1000000.0);
3628 if (i>g->s.tput.nsegs) {
3629 sum -= oldest->th_seglen;
3630 oldest=oldest->next;
3632 sum += tmp->th_seglen;
3634 debug(DBS_TPUT_ELMTS) printf ("tput=%f\n", tput);
3637 t = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3642 t0 = g->segments->rel_secs + g->segments->rel_usecs / 1000000.0;
3648 g->bounds.width = tmax - t0;
3649 g->bounds.height = ymax - y0;
3650 g->zoom.x = (g->geom.width - 1) / g->bounds.width;
3651 g->zoom.y = (g->geom.height -1) / g->bounds.height;
3654 static void tput_read_config (struct graph *g)
3656 debug(DBS_FENTRY) puts ("tput_read_config()");
3658 g->s.tput.width = 4;
3659 g->s.tput.height = 4;
3660 g->s.tput.nsegs = 20;
3662 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3663 g->title[0] = "Throughput Graph";
3665 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3666 g->y_axis->label[0] = "[B/s]";
3667 g->y_axis->label[1] = "Throughput";
3668 g->y_axis->label[2] = NULL;
3669 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3670 g->x_axis->label[0] = "Time[s]";
3671 g->x_axis->label[1] = NULL;
3672 g->s.tput.flags = 0;
3675 static void tput_toggle_time_origin (struct graph *g)
3677 g->s.tput.flags ^= TIME_ORIGIN;
3679 if ((g->s.tput.flags & TIME_ORIGIN) == TIME_ORIGIN_CAP)
3680 g->x_axis->min = g->bounds.x0;
3681 else /* g->s.tput.flags & TIME_ORIGIN == TIME_ORIGIN_CONN */
3687 static void rtt_read_config (struct graph *g)
3689 debug(DBS_FENTRY) puts ("rtt_read_config()");
3692 g->s.rtt.height = 4;
3695 g->title = (const char ** )g_malloc (2 * sizeof (char *));
3696 g->title[0] = "Round Trip Time Graph";
3698 g->y_axis->label = (const char ** )g_malloc (3 * sizeof (char * ));
3699 g->y_axis->label[0] = "RTT [s]";
3700 g->y_axis->label[1] = NULL;
3701 g->x_axis->label = (const char ** )g_malloc (2 * sizeof (char * ));
3702 g->x_axis->label[0] = "Sequence Number[B]";
3703 g->x_axis->label[1] = NULL;
3706 static void rtt_initialize (struct graph *g)
3708 struct segment *tmp, *first=NULL;
3709 struct unack *unack = NULL, *u;
3711 double x0, y0, ymax;
3713 guint32 seq_base = 0;
3715 debug(DBS_FENTRY) puts ("rtt_initialize()");
3717 rtt_read_config (g);
3719 for (tmp=g->segments; tmp; tmp=tmp->next) {
3720 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3721 g->current->th_sport, g->current->th_dport,
3722 &tmp->ip_src, &tmp->ip_dst,
3723 tmp->th_sport, tmp->th_dport,
3724 COMPARE_CURR_DIR)) {
3725 guint32 seqno = tmp->th_seq;
3732 if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) {
3733 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3734 u = rtt_get_new_unack (time, seqno);
3736 rtt_put_unack_on_list (&unack, u);
3739 if (seqno + tmp->th_seglen > xmax)
3740 xmax = seqno + tmp->th_seglen;
3742 guint32 ackno = tmp->th_ack -seq_base;
3743 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3746 for (u=unack; u; u=v)
3747 if (ackno > u->seqno) {
3748 double rtt = time - u->time;
3752 rtt_delete_unack_from_list (&unack, u);
3764 g->bounds.width = xmax;
3765 g->bounds.height = ymax - y0;
3766 g->zoom.x = g->geom.width / g->bounds.width;
3767 g->zoom.y = g->geom.height / g->bounds.height;
3770 static int rtt_is_retrans (struct unack *list, unsigned int seqno)
3774 for (u=list; u; u=u->next)
3775 if (u->seqno== seqno)
3781 static struct unack *rtt_get_new_unack (double time, unsigned int seqno)
3785 u = (struct unack * )g_malloc (sizeof (struct unack));
3794 static void rtt_put_unack_on_list (struct unack **l, struct unack *new)
3796 struct unack *u, *list = *l;
3798 for (u=list; u; u=u->next)
3808 static void rtt_delete_unack_from_list (struct unack **l, struct unack *dead)
3810 struct unack *u, *list = *l;
3819 for (u=list; u; u=u->next)
3820 if (u->next == dead) {
3821 u->next = u->next->next;
3827 static void rtt_make_elmtlist (struct graph *g)
3829 struct segment *tmp;
3830 struct unack *unack = NULL, *u;
3831 struct element *elements, *e;
3832 guint32 seq_base = (guint32) g->bounds.x0;
3834 debug(DBS_FENTRY) puts ("rtt_make_elmtlist()");
3836 if (g->elists->elements == NULL) {
3837 int n = 1 + get_num_dsegs (g);
3838 e = elements = (struct element * )g_malloc (n*sizeof (struct element));
3840 e = elements = g->elists->elements;
3843 for (tmp=g->segments; tmp; tmp=tmp->next) {
3844 if(compare_headers(&g->current->ip_src, &g->current->ip_dst,
3845 g->current->th_sport, g->current->th_dport,
3846 &tmp->ip_src, &tmp->ip_dst,
3847 tmp->th_sport, tmp->th_dport,
3848 COMPARE_CURR_DIR)) {
3849 guint32 seqno = tmp->th_seq -seq_base;
3851 if (tmp->th_seglen && !rtt_is_retrans (unack, seqno)) {
3852 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3853 u = rtt_get_new_unack (time, seqno);
3855 rtt_put_unack_on_list (&unack, u);
3858 guint32 ackno = tmp->th_ack -seq_base;
3859 double time = tmp->rel_secs + tmp->rel_usecs / 1000000.0;
3862 for (u=unack; u; u=v)
3863 if (ackno > u->seqno) {
3864 double rtt = time - u->time;
3869 e->p.arc.dim.width = g->s.rtt.width;
3870 e->p.arc.dim.height = g->s.rtt.height;
3871 e->p.arc.dim.x = g->zoom.x * u->seqno - g->s.rtt.width/2.0;
3872 e->p.arc.dim.y = g->zoom.y * rtt + g->s.rtt.height/2.0;
3873 e->p.arc.filled = TRUE;
3874 e->p.arc.angle1 = 0;
3875 e->p.arc.angle2 = 23040;
3879 rtt_delete_unack_from_list (&unack, u);
3884 e->type = ELMT_NONE;
3885 g->elists->elements = elements;
3888 static void rtt_toggle_seq_origin (struct graph *g)
3890 g->s.rtt.flags ^= SEQ_ORIGIN;
3892 if ((g->s.rtt.flags & SEQ_ORIGIN) == SEQ_ORIGIN_ZERO)
3893 g->x_axis->min = g->bounds.x0;
3898 #if defined(_WIN32) && !defined(__MINGW32__)
3899 /* replacement of Unix rint() for Windows */
3900 static int rint (double x)
3905 buf = _fcvt(x, 0, &dec, &sig);
3915 static gboolean tcp_graph_selected_packet_enabled(frame_data *current_frame, epan_dissect_t *edt, gpointer callback_data _U_)
3917 return current_frame != NULL ? (edt->pi.ipproto == IP_PROTO_TCP) : FALSE;
3922 register_tap_listener_tcp_graph(void)
3924 register_stat_menu_item("TCP Stream Graph/Time-Sequence Graph (Stevens)", REGISTER_STAT_GROUP_UNSORTED,
3925 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(0));
3926 register_stat_menu_item("TCP Stream Graph/Time-Sequence Graph (tcptrace)", REGISTER_STAT_GROUP_UNSORTED,
3927 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(1));
3928 register_stat_menu_item("TCP Stream Graph/Throughput Graph", REGISTER_STAT_GROUP_UNSORTED,
3929 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(2));
3930 register_stat_menu_item("TCP Stream Graph/Round Trip Time Graph", REGISTER_STAT_GROUP_UNSORTED,
3931 tcp_graph_cb, tcp_graph_selected_packet_enabled, NULL, GINT_TO_POINTER(3));