Bugfix from Irene Ruengeler to improve the TSN plot for SCTP
[obnox/wireshark/wip.git] / gtk / sctp_graph_dlg.c
1 /*
2  * Copyright 2004, Irene Ruengeler <i.ruengeler [AT] fh-muenster.de>
3  * Copyright 2009, Varun Notibala <nbvarun [AT] gmail.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h>
32 #include <string.h>
33
34 #include <gtk/gtk.h>
35
36 #include "epan/filesystem.h"
37 #include <epan/strutil.h>
38
39 #include "../globals.h"
40 #include "../color.h"
41 #include "../ui_util.h"
42 #include "../simple_dialog.h"
43
44 #include "gtk/dlg_utils.h"
45 #include "gtk/main.h"
46 #include "gtk/sctp_stat.h"
47
48
49 #define DEFAULT_PIXELS_PER_TICK 2
50 #define MAX_PIXELS_PER_TICK 4
51 #define AUTO_MAX_YSCALE 0
52 #define MAX_TICK_VALUES 5
53 #define DEFAULT_TICK_VALUE 3
54 #define MAX_YSCALE 22
55 #define MAX_COUNT_TYPES 3
56
57 #define COUNT_TYPE_FRAMES   0
58 #define COUNT_TYPE_BYTES    1
59 #define COUNT_TYPE_ADVANCED 2
60
61 #define LEFT_BORDER 60
62 #define RIGHT_BORDER 10
63 #define TOP_BORDER 10
64 #define BOTTOM_BORDER 50
65
66 #define SUB_32(a, b)    a-b
67 #define POINT_SIZE      3
68
69 static GtkWidget * sack_bt;
70
71 /*
72  * Global variables that help in redrawing graph
73  * for SACK and NRSACK
74  */
75 static guint8 gIsSackChunkPresent   = 0;
76 static guint8 gIsNRSackChunkPresent = 0;
77
78 struct chunk_header {
79         guint8  type;
80         guint8  flags;
81         guint16 length;
82 };
83
84 struct data_chunk_header {
85         guint8  type;
86         guint8  flags;
87         guint16 length;
88         guint32 tsn;
89         guint16 sid;
90         guint16 ssn;
91         guint32 ppi;
92 };
93
94 struct init_chunk_header {
95         guint8  type;
96         guint8  flags;
97         guint16 length;
98         guint32 initiate_tag;
99         guint32 a_rwnd;
100         guint16 mos;
101         guint16 mis;
102         guint32 initial_tsn;
103 };
104
105 struct gaps {
106         guint16 start;
107         guint16 end;
108 };
109
110 struct sack_chunk_header {
111         guint8  type;
112         guint8  flags;
113         guint16 length;
114         guint32 cum_tsn_ack;
115         guint32 a_rwnd;
116         guint16 nr_of_gaps;
117         guint16 nr_of_dups;
118         struct gaps gaps[1];
119 };
120
121 struct nr_sack_chunk_header {
122         guint8  type;
123         guint8  flags;
124         guint16 length;
125         guint32 cum_tsn_ack;
126         guint32 a_rwnd;
127         guint16 nr_of_gaps;
128         guint16 nr_of_nr_gaps;
129         guint16 nr_of_dups;
130         guint16 reserved;
131         struct gaps gaps[1];
132 };
133
134 static gboolean label_set = FALSE;
135 static guint32 max_tsn=0, min_tsn=0;
136 static void sctp_graph_set_title(struct sctp_udata *u_data);
137 static void create_draw_area(GtkWidget *box, struct sctp_udata *u_data);
138 static GtkWidget *zoomout_bt;
139 #if defined(_WIN32) && !defined(__MINGW32__)
140 static int rint (double );      /* compiler template for Windows */
141 #endif
142
143 static void
144 draw_sack_graph(struct sctp_udata *u_data)
145 {
146         tsn_t   *sack;
147         GList *list=NULL, *tlist;
148         guint16 gap_start=0, gap_end=0, i, j, nr, dup_nr;
149         guint8 type;
150         guint32 tsnumber, dup;
151         gint xvalue, yvalue;
152         GdkColor red_color = {0, 65535, 0, 0};
153         GdkColor green_color = {0, 0, 65535, 0};
154         GdkColor cyan_color = {0, 0, 65535, 65535};
155         GdkGC *red_gc, *green_gc, *cyan_gc;
156         struct sack_chunk_header *sack_header;
157         struct gaps *gap;
158         guint32 max_num, diff;
159         guint32 *dup_list;
160
161         red_gc = gdk_gc_new(u_data->io->draw_area->window);
162         gdk_gc_set_rgb_fg_color(red_gc, &red_color);
163
164         green_gc = gdk_gc_new(u_data->io->draw_area->window);
165         gdk_gc_set_rgb_fg_color(green_gc, &green_color);
166
167         cyan_gc = gdk_gc_new(u_data->io->draw_area->window);
168         gdk_gc_set_rgb_fg_color(cyan_gc, &cyan_color);
169
170         if (u_data->dir==2)
171         {
172
173                 list = g_list_last(u_data->assoc->sack2);
174                 if (u_data->io->tmp==FALSE)
175                 {
176                         min_tsn=u_data->assoc->min_tsn2;
177                         max_tsn=u_data->assoc->max_tsn2;
178                 }
179                 else
180                 {
181                         min_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_min_tsn2;
182                         max_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_max_tsn2;
183                 }
184         }
185         else if (u_data->dir==1)
186         {
187                 list = g_list_last(u_data->assoc->sack1);
188                 if (u_data->io->tmp==FALSE)
189                 {
190                         min_tsn=u_data->assoc->min_tsn1;
191                         max_tsn=u_data->assoc->max_tsn1;
192                 }
193                 else
194                 {
195                         min_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_min_tsn1;
196                         max_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_max_tsn1;
197                 }
198         }
199
200         while (list)
201         {
202                 sack = (tsn_t*) (list->data);
203                 tlist = g_list_first(sack->tsns);
204                 while (tlist)
205                 {
206                         type = ((struct chunk_header *)tlist->data)->type;
207
208                         if (type == SCTP_SACK_CHUNK_ID)
209                         {
210                                 gIsSackChunkPresent = 1;
211                                 sack_header =(struct sack_chunk_header *)tlist->data;
212                                 nr=g_ntohs(sack_header->nr_of_gaps);
213                                 tsnumber = g_ntohl(sack_header->cum_tsn_ack);
214                                 dup_nr=g_ntohs(sack_header->nr_of_dups);
215
216                                 if (sack->secs>=u_data->io->x1_tmp_sec)
217                                 {
218                                         if (nr>0)
219                                         {
220                                                 gap = &sack_header->gaps[0];
221                                                 for(i=0;i<nr; i++)
222                                                 {
223                                                         gap_start=g_ntohs(gap->start);
224                                                         gap_end = g_ntohs(gap->end);
225                                                         max_num=gap_end+tsnumber;
226                                                         for (j=gap_start; j<=gap_end; j++)
227                                                         {
228                                                                 if (u_data->io->uoff)
229                                                                         diff = sack->secs - u_data->io->min_x;
230                                                                 else
231                                                                         diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
232                                                                 xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
233                                                                 yvalue = (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-POINT_SIZE-u_data->io->offset-((SUB_32(j+tsnumber,min_tsn))*u_data->io->y_interval));
234                                                                 if (xvalue >= LEFT_BORDER+u_data->io->offset &&
235                                                                     xvalue <= u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
236                                                                     yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
237                                                                     yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
238                                                                         gdk_draw_arc(u_data->io->pixmap,green_gc,TRUE,
239                                                                                      xvalue,
240                                                                                      yvalue,
241                                                                                      POINT_SIZE, POINT_SIZE,0, (64*360) );
242                                                         }
243                                                         if (i < nr-1)
244                                                                 gap++;
245                                                 }
246                                         }
247                                         else
248                                                 max_num=tsnumber;
249                                         if (tsnumber>=min_tsn)
250                                         {
251                                                 if (u_data->io->uoff)
252                                                         diff = sack->secs - u_data->io->min_x;
253                                                 else
254                                                         diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
255                                                 xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
256                                                 yvalue = (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-POINT_SIZE -u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval));
257                                                 if (xvalue >= LEFT_BORDER+u_data->io->offset &&
258                                                     xvalue <= u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
259                                                     yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
260                                                     yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
261                                                     {
262                                                         gdk_draw_arc(u_data->io->pixmap,red_gc,TRUE,
263                                                                      xvalue,
264                                                                      yvalue,
265                                                                      POINT_SIZE, POINT_SIZE,0, (64*360) );
266                                                         }
267                                         }
268                                         if (dup_nr > 0)
269                                         {
270                                                 dup_list = (guint32 *)(((char *)&sack_header->nr_of_dups)+sizeof(guint16)+(nr*sizeof(struct gaps)));
271                                                 for (i = 0; i < dup_nr; i++)
272                                                 {
273                                                         dup = g_ntohl(dup_list[i]);
274                                                         if (dup >= min_tsn)
275                                                         {
276                                                                 if (u_data->io->uoff)
277                                                                         diff = sack->secs - u_data->io->min_x;
278                                                                 else
279                                                                         diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
280                                                                 xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
281                                                                 yvalue = (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-POINT_SIZE -u_data->io->offset-((SUB_32(dup,min_tsn))*u_data->io->y_interval));
282                                                                 if (xvalue >= LEFT_BORDER+u_data->io->offset &&
283                                                                     xvalue <= u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
284                                                                     yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
285                                                                     yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
286                                                                         gdk_draw_arc(u_data->io->pixmap,cyan_gc,TRUE,
287                                                                                      xvalue,
288                                                                                      yvalue,
289                                                                                      POINT_SIZE, POINT_SIZE,0, (64*360) );
290                                                         }
291                                                 }
292                                         }
293                                 }
294                         }
295                         tlist = g_list_next(tlist);
296                 }
297                 list = g_list_previous(list);
298         }
299         g_object_unref(G_OBJECT(red_gc));
300         g_object_unref(G_OBJECT(green_gc));
301 }
302
303 /*
304  * This function plots the NR_SACK gap ack and
305  * nr gap acks.
306  * Red dot - Cumulative TSN ack
307  * Green dot - Gap ack
308  * Blue circle - NR Gap ack
309  */
310 static void
311 draw_nr_sack_graph(struct sctp_udata *u_data)
312 {
313         tsn_t *sack;
314         GList *list=NULL, *tlist;
315         guint16 gap_start=0, gap_end=0, i, numberOf_gaps, numberOf_nr_gaps;
316         guint8 type;
317         guint32 tsnumber, j;
318         gint xvalue, yvalue;
319         GdkColor red_color = {0, 65535, 0, 0};
320         GdkColor blue_color = {0, 0, 0, 65535};
321         GdkColor green_color = {0, 0, 65535, 0};
322         GdkGC *red_gc, *blue_gc, *green_gc;
323         struct nr_sack_chunk_header *nr_sack_header;
324         struct gaps *nr_gap;
325         guint32 max_num, diff;
326         /* This holds the sum of gap acks and nr gap acks */
327         guint16 total_gaps = 0;
328
329         red_gc = gdk_gc_new(u_data->io->draw_area->window);
330         gdk_gc_set_rgb_fg_color(red_gc, &red_color);
331         blue_gc = gdk_gc_new(u_data->io->draw_area->window);
332         gdk_gc_set_rgb_fg_color(blue_gc, &blue_color);
333         green_gc = gdk_gc_new(u_data->io->draw_area->window);
334         gdk_gc_set_rgb_fg_color(green_gc, &green_color);
335
336
337         if (u_data->dir==2)
338         {
339                 list = g_list_last(u_data->assoc->sack2);
340                 if (u_data->io->tmp==FALSE)
341                 {
342                         min_tsn=u_data->assoc->min_tsn2;
343                         max_tsn=u_data->assoc->max_tsn2;
344                 }
345                 else
346                 {
347                         min_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_min_tsn2;
348                         max_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_max_tsn2;
349                 }
350         }
351         else if (u_data->dir==1)
352         {
353                 list = g_list_last(u_data->assoc->sack1);
354                 if (u_data->io->tmp==FALSE)
355                 {
356                         min_tsn=u_data->assoc->min_tsn1;
357                         max_tsn=u_data->assoc->max_tsn1;
358                 }
359                 else
360                 {
361                         min_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_min_tsn1;
362                         max_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_max_tsn1;
363                 }
364         }
365         while (list)
366         {
367                 sack = (tsn_t*) (list->data);
368                 tlist = g_list_first(sack->tsns);
369                 while (tlist)
370                 {
371                         type = ((struct chunk_header *)tlist->data)->type;
372                         /*
373                          * The tlist->data is memcpy ied to the appropriate structure
374                          * They entire raw tvb bytes are copied on to one of the *_chunk_header
375                          * structures in sctp_stat.c
376                          */
377                         if (type == SCTP_NR_SACK_CHUNK_ID)
378                         {
379                                 gIsNRSackChunkPresent = 1;
380                                 nr_sack_header =(struct nr_sack_chunk_header *)tlist->data;
381                                 numberOf_nr_gaps=g_ntohs(nr_sack_header->nr_of_nr_gaps);
382                                 numberOf_gaps=g_ntohs(nr_sack_header->nr_of_gaps);
383                                 tsnumber = g_ntohl(nr_sack_header->cum_tsn_ack);
384                                 total_gaps = numberOf_gaps + numberOf_nr_gaps;
385                                 if (sack->secs>=u_data->io->x1_tmp_sec)
386                                 {
387                                         /* If the number of nr_gaps is greater than 0 */
388                                         if ( total_gaps > 0 )
389                                         {
390                                                 nr_gap = &nr_sack_header->gaps[0];
391                                                 for ( i=0; i < total_gaps; i++ )
392                                                 {
393                                                         gap_start=g_ntohs(nr_gap->start);
394                                                         gap_end = g_ntohs(nr_gap->end);
395                                                         max_num= gap_end + tsnumber;
396                                                         for ( j = gap_start; j <= gap_end; j++)
397                                                         {
398                                                                 if (u_data->io->uoff)
399                                                                         diff = sack->secs - u_data->io->min_x;
400                                                                 else
401                                                                         diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
402                                                                 xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
403                                                                 yvalue = (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-POINT_SIZE-u_data->io->offset-((SUB_32(j+tsnumber,min_tsn))*u_data->io->y_interval));
404                                                                 if (xvalue >= LEFT_BORDER+u_data->io->offset &&
405                                                                     xvalue <= u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
406                                                                     yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
407                                                                     yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
408                                                                 {
409                                                                         /* Check if this is an GAP ACK or NR GAP ACK */
410                                                                         if ( i >= numberOf_gaps)
411                                                                         {
412                                                                                 /* This is a nr gap ack */
413                                                                                 gdk_draw_arc(u_data->io->pixmap,blue_gc,FALSE,
414                                                                                              xvalue,
415                                                                                              yvalue,
416                                                                                              POINT_SIZE , POINT_SIZE,0, (64*360) );
417
418                                                                                 /* All NR GAP Acks are also gap acks, so plot these as
419                                                                                  * gap acks - green dot.
420                                                                                  * These will be shown as points with a green dot - GAP ACK
421                                                                                  * surrounded by a blue circle - NR GAP ack
422                                                                                  */
423                                                                                 gdk_draw_arc(u_data->io->pixmap, green_gc, TRUE,
424                                                                                              xvalue,
425                                                                                              yvalue,
426                                                                                              POINT_SIZE , POINT_SIZE,0, (64*360) );
427
428                                                                         }
429                                                                         else
430                                                                         {
431                                                                                 /* This is just a gap ack */
432                                                                                 gdk_draw_arc(u_data->io->pixmap, green_gc, TRUE,
433                                                                                              xvalue,
434                                                                                              yvalue,
435                                                                                              POINT_SIZE , POINT_SIZE,0, (64*360) );
436                                                                         }
437                                                                 }
438                                                         }
439                                                         if (i < total_gaps-1)
440                                                                 nr_gap++;
441                                                 }
442                                         }
443                                         else
444                                                 max_num=tsnumber;
445
446                                         if (tsnumber>=min_tsn)
447                                         {
448                                                 if (u_data->io->uoff)
449                                                         diff = sack->secs - u_data->io->min_x;
450                                                 else
451                                                         diff=sack->secs*1000000+sack->usecs-u_data->io->min_x;
452                                                 xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
453                                                 yvalue = (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-POINT_SIZE -u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval));
454                                                 if (xvalue >= LEFT_BORDER+u_data->io->offset &&
455                                                     xvalue <= u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
456                                                     yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
457                                                     yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
458                                                         gdk_draw_arc(u_data->io->pixmap,red_gc,TRUE,
459                                                                      xvalue,
460                                                                      yvalue,
461                                                                      POINT_SIZE, POINT_SIZE,0, (64*360) );
462                                         }
463                                 }
464                         }
465                         tlist = g_list_next(tlist);
466                 }
467                 list = g_list_previous(list);
468         }
469         g_object_unref(G_OBJECT(red_gc));
470         g_object_unref(G_OBJECT(blue_gc));
471         g_object_unref(G_OBJECT(green_gc));
472 }
473
474 static void
475 draw_tsn_graph(struct sctp_udata *u_data)
476 {
477         tsn_t *tsn;
478         GList *list=NULL, *tlist;
479         guint8 type;
480         guint32 tsnumber=0;
481         guint32 min_secs=0, diff;
482         gint xvalue, yvalue;
483
484         if (u_data->dir==1)
485         {
486                 list = g_list_last(u_data->assoc->tsn1);
487                 if (u_data->io->tmp==FALSE)
488                 {
489                         min_tsn=u_data->assoc->min_tsn1;
490                         max_tsn=u_data->assoc->max_tsn1;
491                 }
492                 else
493                 {
494                         min_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_min_tsn1;
495                         max_tsn=u_data->assoc->min_tsn1+u_data->io->tmp_max_tsn1;
496                 }
497         }
498         else if (u_data->dir==2)
499         {
500                 list = g_list_last(u_data->assoc->tsn2);
501                 if (u_data->io->tmp==FALSE)
502                 {
503                         min_tsn=u_data->assoc->min_tsn2;
504                         max_tsn=u_data->assoc->max_tsn2;
505                 }
506                 else
507                 {
508                         min_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_min_tsn2;
509                         max_tsn=u_data->assoc->min_tsn2+u_data->io->tmp_max_tsn2;
510                 }
511         }
512
513         while (list)
514         {
515                 tsn = (tsn_t*) (list->data);
516                 tlist = g_list_first(tsn->tsns);
517                 while (tlist)
518                 {
519                         type = ((struct chunk_header *)tlist->data)->type;
520                         if (type == SCTP_DATA_CHUNK_ID)
521                                 tsnumber = g_ntohl(((struct data_chunk_header *)tlist->data)->tsn);
522                         if (tsnumber>=min_tsn && tsnumber<=max_tsn && tsn->secs>=min_secs)
523                         {
524                                         if (u_data->io->uoff)
525                                                 diff = tsn->secs - u_data->io->min_x;
526                                         else
527                                                 diff=tsn->secs*1000000+tsn->usecs-u_data->io->min_x;
528                                         xvalue = (guint32)(LEFT_BORDER+u_data->io->offset+u_data->io->x_interval*diff);
529                                         yvalue = (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-POINT_SIZE-u_data->io->offset-((SUB_32(tsnumber,min_tsn))*u_data->io->y_interval));
530                                         if (xvalue >= LEFT_BORDER+u_data->io->offset &&
531                                             xvalue <= u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset &&
532                                             yvalue >= TOP_BORDER-u_data->io->offset-POINT_SIZE &&
533                                             yvalue <= u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
534                                                 gdk_draw_arc(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,TRUE,
535                                                              xvalue,
536                                                              yvalue,
537                                                              POINT_SIZE, POINT_SIZE, 0, (64*360));
538                         }
539                         tlist = g_list_next(tlist);
540                 }
541                 list = g_list_previous(list);
542         }
543 }
544
545
546 static void
547 sctp_graph_draw(struct sctp_udata *u_data)
548 {
549         int length, lwidth;
550         guint32  distance=5, i, e, sec, w, start, a, b, j;
551         gint label_width, label_height;
552         char label_string[15];
553         gfloat dis;
554         gboolean write_label = FALSE;
555         PangoLayout  *layout;
556
557         if (u_data->io->x1_tmp_sec==0 && u_data->io->x1_tmp_usec==0)
558                 u_data->io->offset=0;
559         else
560                 u_data->io->offset=5;
561
562         if (u_data->io->x2_tmp_sec - u_data->io->x1_tmp_sec > 1500)
563         {
564                 u_data->io->min_x=u_data->io->x1_tmp_sec;
565                 u_data->io->max_x=u_data->io->x2_tmp_sec;
566                 u_data->io->uoff = TRUE;
567         }
568         else
569         {
570                 u_data->io->min_x=(guint32)(u_data->io->x1_tmp_sec*1000000.0+u_data->io->x1_tmp_usec);
571                 u_data->io->max_x=(guint32)(u_data->io->x2_tmp_sec*1000000.0+u_data->io->x2_tmp_usec);
572                 u_data->io->uoff = FALSE;
573         }
574
575         u_data->io->tmp_width=u_data->io->max_x-u_data->io->min_x;
576
577         if (u_data->dir==1)
578         {
579                 if (u_data->io->tmp==FALSE)
580                 {
581                         if (u_data->assoc->tsn1!=NULL || u_data->assoc->sack1!=NULL)
582                                 u_data->io->max_y=u_data->io->tmp_max_tsn1 - u_data->io->tmp_min_tsn1;
583                         else
584                                 u_data->io->max_y= 0;
585                         u_data->io->min_y = 0;
586                 }
587                 else
588                 {
589                         u_data->io->max_y = u_data->io->tmp_max_tsn1;
590                         u_data->io->min_y = u_data->io->tmp_min_tsn1;
591                 }
592         }
593         else if (u_data->dir==2)
594         {
595                 if (u_data->io->tmp==FALSE)
596                 {
597                         if (u_data->assoc->tsn2!=NULL || u_data->assoc->sack2!=NULL)
598                                         u_data->io->max_y=u_data->io->tmp_max_tsn2 -u_data->io->tmp_min_tsn2;
599                         else
600                                 u_data->io->max_y= 0;
601                         u_data->io->min_y = 0;
602                 }
603                 else
604                 {
605                         u_data->io->max_y = u_data->io->tmp_max_tsn2;
606                         u_data->io->min_y = u_data->io->tmp_min_tsn2;
607                 }
608         }
609
610         gdk_draw_rectangle(u_data->io->pixmap,
611                            u_data->io->draw_area->style->white_gc,
612                            TRUE,
613                            0, 0,
614                            u_data->io->draw_area->allocation.width,
615                            u_data->io->draw_area->allocation.height);
616
617         distance=5;
618         /* x_axis */
619         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc, LEFT_BORDER+u_data->io->offset,u_data->io->pixmap_height-BOTTOM_BORDER,u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset, u_data->io->pixmap_height-BOTTOM_BORDER);
620         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset, u_data->io->pixmap_height-BOTTOM_BORDER, u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset-5, u_data->io->pixmap_height-BOTTOM_BORDER-5);
621         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset, u_data->io->pixmap_height-BOTTOM_BORDER, u_data->io->pixmap_width-RIGHT_BORDER+u_data->io->offset-5, u_data->io->pixmap_height-BOTTOM_BORDER+5);
622         u_data->io->axis_width=u_data->io->pixmap_width-LEFT_BORDER-RIGHT_BORDER-u_data->io->offset;
623
624         /* try to avoid dividing by zero */
625         if(u_data->io->tmp_width>0){
626                 u_data->io->x_interval = (float)((u_data->io->axis_width*1.0)/u_data->io->tmp_width); /*distance in pixels between 2 data points*/
627         } else {
628                 u_data->io->x_interval = (float)(u_data->io->axis_width);
629         }
630
631         e=0; /*number of decimals of x_interval*/
632         if (u_data->io->x_interval<1)
633         {
634                 dis=1/u_data->io->x_interval;
635                 while (dis >1)
636                 {
637                         dis/=10;
638                         e++;
639                 }
640                 distance=1;
641                 for (i=0; i<=e+1; i++)
642                         distance*=10; /*distance per 100 pixels*/
643         }
644         else
645                 distance=5;
646
647         g_snprintf(label_string, sizeof(label_string), "%d", 0);
648         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
649         layout = gtk_widget_create_pango_layout(u_data->io->draw_area, label_string);
650         pango_layout_get_pixel_size(layout, &label_width, &label_height);
651
652         if (u_data->io->x1_tmp_usec==0)
653                 sec=u_data->io->x1_tmp_sec;
654         else
655                 sec=u_data->io->x1_tmp_sec+1;
656
657
658         if (u_data->io->offset!=0)
659         {
660                 g_snprintf(label_string, sizeof(label_string), "%u", u_data->io->x1_tmp_sec);
661
662                 memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
663                 pango_layout_set_text(layout, label_string, -1);
664                 pango_layout_get_pixel_size(layout, &lwidth, NULL);
665
666                 gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
667                                 LEFT_BORDER-25,
668                                 u_data->io->pixmap_height-BOTTOM_BORDER+20,
669                                 layout);
670         }
671
672         w=(guint32)(500/(guint32)(distance*u_data->io->x_interval)); /*there will be a label for every w_th tic*/
673
674         if (w==0)
675                 w=1;
676
677         if (w==4 || w==3 || w==2)
678         {
679                 w=5;
680                 a=distance/10;  /*distance between two tics*/
681                 b = (guint32)((u_data->io->min_x/100000))%10; /* start for labels*/
682         }
683         else
684         {
685                 a=distance/5;
686                 b=0;
687         }
688
689
690         if (!u_data->io->uoff)
691         {
692                 if (a>=1000000)
693                 {
694                         start=u_data->io->min_x/1000000*1000000;
695                         if (a==1000000)
696                                 b = 0;
697                 }
698                 else
699                 {
700                         start=u_data->io->min_x/100000;
701                         if (start%2!=0)
702                                 start--;
703                         start*=100000;
704                         b = (guint32)((start/100000))%10;
705                 }
706         }
707         else
708         {
709                 start = u_data->io->min_x;
710                 if (start%2!=0)
711                         start--;
712                 b = 0;
713
714         }
715
716         for (i=start, j=b; i<=u_data->io->max_x; i+=a, j++)
717         {
718                 if (!u_data->io->uoff)
719                 if (i>=u_data->io->min_x && i%1000000!=0)
720                 {
721                         length=5;
722                         g_snprintf(label_string, sizeof(label_string), "%d", i%1000000);
723                         if (j%w==0)
724                         {
725                                 length=10;
726                                 memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
727                                 pango_layout_set_text(layout, label_string, -1);
728                                 pango_layout_get_pixel_size(layout, &lwidth, NULL);
729                                 gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
730                                         (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval-lwidth/2),
731                                         u_data->io->pixmap_height-BOTTOM_BORDER+10,
732                                         layout);
733                         }
734                         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
735                                 (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
736                                 u_data->io->pixmap_height-BOTTOM_BORDER,
737                                 (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
738                                 u_data->io->pixmap_height-BOTTOM_BORDER+length);
739                 }
740
741                 if (!u_data->io->uoff)
742                 {
743                         if (i%1000000==0 && j%w==0)
744                         {
745                                 sec=i/1000000;
746                                 write_label = TRUE;
747                         }
748                 }
749                 else
750                 {
751                         if (j%w == 0)
752                         {
753                                 sec = i;
754                                 write_label = TRUE;
755                         }
756                 }
757                 if (write_label)
758                 {
759                         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
760                                       (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
761                                       u_data->io->pixmap_height-BOTTOM_BORDER,
762                                       (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval),
763                                       u_data->io->pixmap_height-BOTTOM_BORDER+10);
764
765                         g_snprintf(label_string, sizeof(label_string), "%d", sec);
766                         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
767                         pango_layout_set_text(layout, label_string, -1);
768                         pango_layout_get_pixel_size(layout, &lwidth, NULL);
769
770                         gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
771                                         (guint32)(LEFT_BORDER+u_data->io->offset+(i-u_data->io->min_x)*u_data->io->x_interval-10),
772                                         u_data->io->pixmap_height-BOTTOM_BORDER+20,
773                                         layout);
774                         write_label = FALSE;
775                 }
776
777         }
778
779         g_strlcpy(label_string, "sec", sizeof(label_string));
780
781         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
782         pango_layout_set_text(layout, label_string, -1);
783         pango_layout_get_pixel_size(layout, &lwidth, NULL);
784         gdk_draw_layout(u_data->io->pixmap,
785                         u_data->io->draw_area->style->black_gc,
786                         u_data->io->pixmap_width-RIGHT_BORDER-10,
787                         u_data->io->pixmap_height-BOTTOM_BORDER+30,
788                         layout);
789
790         distance=5;
791
792         /* y-axis */
793         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc, LEFT_BORDER,TOP_BORDER-u_data->io->offset,LEFT_BORDER,u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset);
794         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,LEFT_BORDER,TOP_BORDER-u_data->io->offset, LEFT_BORDER-5, TOP_BORDER-u_data->io->offset+5);
795         gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,LEFT_BORDER,TOP_BORDER-u_data->io->offset, LEFT_BORDER+5, TOP_BORDER-u_data->io->offset+5);
796
797         u_data->io->y_interval = (float)(((u_data->io->pixmap_height-TOP_BORDER-BOTTOM_BORDER)*1.0)/(u_data->io->max_y-u_data->io->min_y));
798
799         e=0;
800         if (u_data->io->y_interval<1)
801         {
802                 dis=1/u_data->io->y_interval;
803                 while (dis >1)
804                 {
805                         dis/=10;
806                         e++;
807                 }
808                 distance=1;
809                 for (i=0; i<=e; i++)
810                         distance=distance*10;
811         }
812         else if (u_data->io->y_interval<2)
813                 distance = 10;
814
815         if (u_data->io->max_y>0)
816         {
817                 for (i=u_data->io->min_y/distance*distance; i<=u_data->io->max_y; i+=distance/5)
818                 {
819                         if (i>=u_data->io->min_y)
820                         {
821                                 length=5;
822                                 g_snprintf(label_string, sizeof(label_string), "%d", i);
823                                 if (i%distance==0 || (distance<=5 && u_data->io->y_interval>10))
824                                 {
825                                         length=10;
826
827                                         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), sizeof(label_string));
828                                         pango_layout_set_text(layout, label_string, -1);
829                                         pango_layout_get_pixel_size(layout, &lwidth, NULL);
830                                         gdk_draw_layout(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
831                                                         LEFT_BORDER-length-lwidth-5,
832                                                         (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval-POINT_SIZE),
833                                                         layout);
834                                 }
835                                 gdk_draw_line(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,LEFT_BORDER-length,
836                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval),
837                                               LEFT_BORDER,
838                                               (guint32)(u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-(i-u_data->io->min_y)*u_data->io->y_interval));
839                         }
840                 }
841         }
842         else if ((u_data->dir==1 && u_data->assoc->n_array_tsn1==0) || (u_data->dir==2 && u_data->assoc->n_array_tsn2==0))
843                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "No Data Chunks sent");
844 }
845
846 /* This function is used to change the title
847  * in the graph dialogue to NR_SACK or SACK based on the
848  * association
849  * If an association has both SAKC and NR_SACK PDU's
850  * a warning is popped
851  */
852 static void
853 updateLabels(void)
854 {
855         if (gIsSackChunkPresent && gIsNRSackChunkPresent)
856         {
857                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "This data set contains both SACK and NR SACK PDUs.");
858                 gtk_button_set_label( (GtkButton*) sack_bt, "Show both Sack and NR Sack");
859         }
860         else if (gIsSackChunkPresent)
861                 gtk_button_set_label( (GtkButton*) sack_bt, "Show Only Sack");
862         else
863                 /* gIsNRSackChunkPresent will be true here */
864                 gtk_button_set_label( (GtkButton*) sack_bt, "Show Only NR Sack");
865 }
866
867 static void
868 sctp_graph_redraw(struct sctp_udata *u_data)
869 {
870 sctp_graph_t *ios;
871
872         u_data->io->needs_redraw=TRUE;
873
874         sctp_graph_draw(u_data);
875         switch (u_data->io->graph_type)
876         {
877                 case 0:
878                         /* Show both TSN and SACK information
879                          * Reset the global sack variable
880                          * for sack and nr sack cases
881                          */
882                         gIsSackChunkPresent = 0;
883                         gIsNRSackChunkPresent = 0;
884                         draw_sack_graph(u_data);
885                         draw_nr_sack_graph(u_data);
886                         draw_tsn_graph(u_data);
887                         break;
888                 case 1:
889                         /* Show only TSN */
890                         draw_tsn_graph(u_data);
891                         break;
892                 case 2:
893                         /* Show only SACK information
894                          * Reset the global sack variable
895                          * for sack and nr sack cases
896                          */
897                         gIsSackChunkPresent = 0;
898                         gIsNRSackChunkPresent = 0;
899                         draw_sack_graph(u_data);
900                         draw_nr_sack_graph(u_data);
901                         break;
902         }
903
904         /* Updates the sack / nr sack buttons */
905         updateLabels();
906
907         ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
908         if(!ios){
909                 exit(10);
910         }
911
912
913         gdk_draw_pixmap(u_data->io->draw_area->window,
914                         u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
915                         ios->pixmap,
916                         0,0,
917                         0, 0,
918                         u_data->io->draw_area->allocation.width,
919                         u_data->io->draw_area->allocation.height);
920 }
921
922
923 static void
924 on_sack_bt(GtkWidget *widget _U_, struct sctp_udata *u_data)
925 {
926
927         u_data = (struct sctp_udata *) u_data;
928         u_data->io->graph_type=2;
929         sctp_graph_redraw(u_data);
930 }
931
932 static void
933 on_tsn_bt(GtkWidget *widget _U_, struct sctp_udata *u_data)
934 {
935
936         u_data->io->graph_type=1;
937         sctp_graph_redraw(u_data);
938 }
939
940 static void
941 on_both_bt(GtkWidget *widget _U_, struct sctp_udata *u_data)
942 {
943
944         u_data->io->graph_type=0;
945         sctp_graph_redraw(u_data);
946 }
947
948 static void
949 sctp_graph_close_cb(GtkWidget* widget _U_, gpointer u_data)
950 {
951         struct sctp_udata *udata;
952         int dir;
953
954         udata = (struct sctp_udata *)u_data;
955         dir=udata->dir-1;
956         gtk_grab_remove(GTK_WIDGET(udata->io->window));
957         gtk_widget_destroy(GTK_WIDGET(udata->io->window));
958
959 }
960
961 static gint
962 configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, struct sctp_udata *u_data)
963 {
964         if(!u_data->io){
965                 exit(10);
966         }
967
968         if(u_data->io->pixmap){
969                 gdk_pixmap_unref(u_data->io->pixmap);
970                 u_data->io->pixmap=NULL;
971         }
972
973         u_data->io->pixmap=gdk_pixmap_new(widget->window,
974                         widget->allocation.width,
975                         widget->allocation.height,
976                         -1);
977         u_data->io->pixmap_width=widget->allocation.width;
978         u_data->io->pixmap_height=widget->allocation.height;
979
980         gdk_draw_rectangle(u_data->io->pixmap,
981                         widget->style->white_gc,
982                         TRUE,
983                         0, 0,
984                         widget->allocation.width,
985                         widget->allocation.height);
986         sctp_graph_redraw(u_data);
987         return TRUE;
988 }
989
990 static gint
991 expose_event(GtkWidget *widget, GdkEventExpose *event)
992 {
993         sctp_graph_t *ios;
994
995         ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(widget), "sctp_graph_t");
996         if(!ios){
997                 exit(10);
998         }
999
1000         gdk_draw_pixmap(widget->window,
1001                         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1002                         ios->pixmap,
1003                         event->area.x, event->area.y,
1004                         event->area.x, event->area.y,
1005                         event->area.width, event->area.height);
1006
1007         return FALSE;
1008 }
1009
1010
1011 static void
1012 on_zoomin_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
1013 {
1014         sctp_min_max_t *tmp_minmax;
1015
1016         if (u_data->io->rectangle_present==TRUE)
1017         {
1018                 tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
1019
1020                 u_data->io->tmp_min_tsn1=u_data->io->y1_tmp+u_data->io->min_y;
1021                 u_data->io->tmp_max_tsn1=u_data->io->y2_tmp+1+u_data->io->min_y;
1022                 u_data->io->tmp_min_tsn2=u_data->io->tmp_min_tsn1;
1023                 u_data->io->tmp_max_tsn2=u_data->io->tmp_max_tsn1;
1024                 tmp_minmax->tmp_min_secs=u_data->io->x1_tmp_sec;
1025                 tmp_minmax->tmp_min_usecs=      u_data->io->x1_tmp_usec;
1026                 tmp_minmax->tmp_max_secs=       u_data->io->x2_tmp_sec;
1027                 tmp_minmax->tmp_max_usecs=      u_data->io->x2_tmp_usec;
1028                 tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
1029                 tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
1030                 tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
1031                 tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
1032                 u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
1033                 u_data->io->length = g_slist_length(u_data->assoc->min_max);
1034                 u_data->io->tmp=TRUE;
1035                 u_data->io->rectangle=FALSE;
1036                 u_data->io->rectangle_present=FALSE;
1037                 gtk_widget_set_sensitive(zoomout_bt, TRUE);
1038                 sctp_graph_redraw(u_data);
1039         }
1040         else
1041         {
1042                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please draw a rectangle around the area you want to zoom in!");
1043         }
1044 }
1045
1046 static void
1047 zoomin_bt_fcn (struct sctp_udata *u_data)
1048 {
1049         sctp_min_max_t *tmp_minmax;
1050
1051         tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
1052
1053         u_data->io->tmp_min_tsn1=u_data->io->y1_tmp+u_data->io->min_y;
1054         u_data->io->tmp_max_tsn1=u_data->io->y2_tmp+1+u_data->io->min_y;
1055         u_data->io->tmp_min_tsn2=u_data->io->tmp_min_tsn1;
1056         u_data->io->tmp_max_tsn2=u_data->io->tmp_max_tsn1;
1057         tmp_minmax->tmp_min_secs=u_data->io->x1_tmp_sec;
1058         tmp_minmax->tmp_min_usecs=      u_data->io->x1_tmp_usec;
1059         tmp_minmax->tmp_max_secs=       u_data->io->x2_tmp_sec;
1060         tmp_minmax->tmp_max_usecs=      u_data->io->x2_tmp_usec;
1061         tmp_minmax->tmp_min_tsn1=u_data->io->tmp_min_tsn1;
1062         tmp_minmax->tmp_max_tsn1=u_data->io->tmp_max_tsn1;
1063         tmp_minmax->tmp_min_tsn2=u_data->io->tmp_min_tsn2;
1064         tmp_minmax->tmp_max_tsn2=u_data->io->tmp_max_tsn2;
1065         u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
1066         u_data->io->length = g_slist_length(u_data->assoc->min_max);
1067         u_data->io->tmp=TRUE;
1068         u_data->io->rectangle=FALSE;
1069         u_data->io->rectangle_present=FALSE;
1070         gtk_widget_set_sensitive(zoomout_bt, TRUE);
1071         sctp_graph_redraw(u_data);
1072
1073 }
1074
1075
1076
1077 static void
1078 on_zoomout_bt (GtkWidget *widget _U_, struct sctp_udata *u_data)
1079 {
1080         sctp_min_max_t *tmp_minmax, *mm;
1081         gint l;
1082
1083         l = g_slist_length(u_data->assoc->min_max);
1084
1085         if (u_data->assoc->min_max!=NULL)
1086         {
1087                 mm=(sctp_min_max_t *)((u_data->assoc->min_max)->data);
1088                 u_data->assoc->min_max=g_slist_remove(u_data->assoc->min_max, mm);
1089                 g_free(mm);
1090                 if (l>2)
1091                 {
1092                         tmp_minmax = (sctp_min_max_t *)u_data->assoc->min_max->data;
1093                         u_data->io->x1_tmp_sec=tmp_minmax->tmp_min_secs;
1094                         u_data->io->x1_tmp_usec=tmp_minmax->tmp_min_usecs;
1095                         u_data->io->x2_tmp_sec=tmp_minmax->tmp_max_secs;
1096                         u_data->io->x2_tmp_usec=tmp_minmax->tmp_max_usecs;
1097                         u_data->io->tmp_min_tsn1=tmp_minmax->tmp_min_tsn1;
1098                         u_data->io->tmp_max_tsn1=tmp_minmax->tmp_max_tsn1;
1099                         u_data->io->tmp_min_tsn2=tmp_minmax->tmp_min_tsn2;
1100                         u_data->io->tmp_max_tsn2=tmp_minmax->tmp_max_tsn2;
1101                         u_data->io->tmp=TRUE;
1102                 }
1103                 else
1104                 {
1105                         u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
1106                         u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
1107                         u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
1108                         u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
1109                         u_data->io->tmp_min_tsn1=u_data->assoc->min_tsn1;
1110                         u_data->io->tmp_max_tsn1=u_data->assoc->max_tsn1;
1111                         u_data->io->tmp_min_tsn2=u_data->assoc->min_tsn2;
1112                         u_data->io->tmp_max_tsn2=u_data->assoc->max_tsn2;
1113                         u_data->io->tmp=FALSE;
1114                 }
1115         }
1116         else
1117         {
1118                 u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
1119                 u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
1120                 u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
1121                 u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
1122                 u_data->io->tmp_min_tsn1=u_data->assoc->min_tsn1;
1123                 u_data->io->tmp_max_tsn1=u_data->assoc->max_tsn1;
1124                 u_data->io->tmp_min_tsn2=u_data->assoc->min_tsn2;
1125                 u_data->io->tmp_max_tsn2=u_data->assoc->max_tsn2;
1126                 u_data->io->tmp=FALSE;
1127         }
1128         if (g_slist_length(u_data->assoc->min_max)==1)
1129                 gtk_widget_set_sensitive(zoomout_bt, FALSE);
1130         sctp_graph_redraw(u_data);
1131 }
1132
1133 static gint
1134 on_button_press (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata *u_data)
1135 {
1136         sctp_graph_t *ios;
1137
1138         if (u_data->io->rectangle==TRUE)
1139         {
1140                 gdk_draw_rectangle(u_data->io->pixmap,u_data->io->draw_area->style->white_gc,
1141                                    FALSE,
1142                                    (gint)floor(MIN(u_data->io->x_old,u_data->io->x_new)),
1143                                    (gint)floor(MIN(u_data->io->y_old,u_data->io->y_new)),
1144                                    (gint)floor(abs((long)(u_data->io->x_new-u_data->io->x_old))),
1145                                    (gint)floor(abs((long)(u_data->io->y_new-u_data->io->y_old))));
1146                 ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
1147
1148                 if(!ios){
1149                         exit(10);
1150                 }
1151
1152                 gdk_draw_pixmap(u_data->io->draw_area->window,
1153                                 u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
1154                                 ios->pixmap,
1155                                 0,0,
1156                                 0, 0,
1157                                 (gint)(abs((long)(u_data->io->x_new-u_data->io->x_old))),
1158                                 (gint)(abs((long)(u_data->io->y_new-u_data->io->y_old))));
1159                 sctp_graph_redraw(u_data);
1160         }
1161         u_data->io->x_old=event->x;
1162         u_data->io->y_old=event->y;
1163         if (u_data->io->y_old>u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-POINT_SIZE)
1164                 u_data->io->y_old=u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-POINT_SIZE;
1165         if (u_data->io->x_old<LEFT_BORDER+u_data->io->offset)
1166                 u_data->io->x_old=LEFT_BORDER+u_data->io->offset;
1167         u_data->io->rectangle=FALSE;
1168
1169         return TRUE;
1170 }
1171
1172
1173 static gint
1174 on_button_release (GtkWidget *widget _U_, GdkEventButton *event, struct sctp_udata *u_data)
1175 {
1176         sctp_graph_t *ios;
1177         guint32 helpx, helpy, x1_tmp, x2_tmp,  y_value, t_size=0, s_size=0, i, y_tolerance;
1178         gint label_width, label_height;
1179         gdouble x_value, position, s_diff=0, t_diff=0, x_tolerance=0.0001;
1180         gint lwidth;
1181         char label_string[30];
1182         GdkGC *text_color;
1183         GPtrArray *tsnlist = NULL, *sacklist=NULL;
1184         struct tsn_sort *tsn, *sack=NULL;
1185         gboolean sack_found = FALSE;
1186         PangoLayout  *layout;
1187
1188         g_snprintf(label_string, 15, "%d", 0);
1189         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
1190         layout = gtk_widget_create_pango_layout(u_data->io->draw_area, label_string);
1191         pango_layout_get_pixel_size(layout, &label_width, &label_height);
1192
1193         if (event->y>u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)
1194                 event->y = u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset;
1195         if (event->x < LEFT_BORDER+u_data->io->offset)
1196                 event->x = LEFT_BORDER+u_data->io->offset;
1197         if (abs((long)(event->x-u_data->io->x_old))>10 || abs((long)(event->y-u_data->io->y_old))>10)
1198         {
1199                 u_data->io->rect_x_min = (gint)floor(MIN(u_data->io->x_old,event->x));
1200                 u_data->io->rect_x_max = (gint)ceil(MAX(u_data->io->x_old,event->x));
1201                 u_data->io->rect_y_min = (gint)floor(MIN(u_data->io->y_old,event->y));
1202                 u_data->io->rect_y_max = (gint)ceil(MAX(u_data->io->y_old,event->y))+POINT_SIZE;
1203                 gdk_draw_rectangle(u_data->io->pixmap,u_data->io->draw_area->style->black_gc,
1204                                    FALSE,
1205                                    u_data->io->rect_x_min, u_data->io->rect_y_min,
1206                                    u_data->io->rect_x_max - u_data->io->rect_x_min,
1207                                    u_data->io->rect_y_max - u_data->io->rect_y_min);
1208                 ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
1209
1210                 if(!ios){
1211                         exit(10);
1212                 }
1213
1214                 gdk_draw_pixmap(u_data->io->draw_area->window,
1215                                 u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
1216                                 ios->pixmap,
1217                                 0, 0,
1218                                 0, 0,
1219                                 u_data->io->draw_area->allocation.width,
1220                                 u_data->io->draw_area->allocation.height);
1221
1222                 x1_tmp=(unsigned int)floor(u_data->io->min_x+((u_data->io->x_old-LEFT_BORDER-u_data->io->offset)*u_data->io->tmp_width/u_data->io->axis_width));
1223                 x2_tmp=(unsigned int)floor(u_data->io->min_x+((event->x-LEFT_BORDER-u_data->io->offset)*u_data->io->tmp_width/u_data->io->axis_width));
1224                 helpx=MIN(x1_tmp, x2_tmp);
1225                 if (helpx==x2_tmp)
1226                 {
1227                         x2_tmp=x1_tmp;
1228                         x1_tmp=helpx;
1229                 }
1230                 if (u_data->io->uoff)
1231                 {
1232                         if (x2_tmp - x1_tmp <= 1500)
1233                                 u_data->io->uoff = FALSE;
1234                         u_data->io->x1_tmp_sec=(guint32)x1_tmp;
1235                         u_data->io->x1_tmp_usec=0;
1236                         u_data->io->x2_tmp_sec=(guint32)x2_tmp;
1237                         u_data->io->x2_tmp_usec=0;
1238                 }
1239                 else
1240                 {
1241                         u_data->io->x1_tmp_sec=(guint32)x1_tmp/1000000;
1242                         u_data->io->x1_tmp_usec=x1_tmp%1000000;
1243                         u_data->io->x2_tmp_sec=(guint32)x2_tmp/1000000;
1244                         u_data->io->x2_tmp_usec=x2_tmp%1000000;
1245                 }
1246                 u_data->io->x1_akt_sec = u_data->io->x1_tmp_sec;
1247                 u_data->io->x1_akt_usec = u_data->io->x1_tmp_usec;
1248                 u_data->io->x2_akt_sec = u_data->io->x2_tmp_sec;
1249                 u_data->io->x2_akt_usec = u_data->io->x2_tmp_usec;
1250
1251                 u_data->io->y1_tmp=(guint32)((u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-u_data->io->y_old)/u_data->io->y_interval);
1252                 u_data->io->y2_tmp=(guint32)((u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-event->y)/u_data->io->y_interval);
1253                 helpy = MIN(u_data->io->y1_tmp, u_data->io->y2_tmp);
1254                 u_data->io->y2_tmp = MAX(u_data->io->y1_tmp, u_data->io->y2_tmp);
1255                 u_data->io->y1_tmp = helpy;
1256                 u_data->io->x_new=event->x;
1257                 u_data->io->y_new=event->y;
1258                 u_data->io->rectangle=TRUE;
1259                 u_data->io->rectangle_present=TRUE;
1260         }
1261         else
1262         {
1263                 if (u_data->io->rectangle_present==TRUE)
1264                 {
1265                         u_data->io->rectangle_present=FALSE;
1266                         if (event->x >= u_data->io->rect_x_min && event->x <= u_data->io->rect_x_max &&
1267                              event->y >= u_data->io->rect_y_min && event->y <= u_data->io->rect_y_max)
1268                                 zoomin_bt_fcn(u_data);
1269                         else
1270                         {
1271                                 u_data->io->x1_tmp_sec = u_data->io->x1_akt_sec;
1272                                 u_data->io->x1_tmp_usec = u_data->io->x1_akt_usec;
1273                                 u_data->io->x2_tmp_sec = u_data->io->x2_akt_sec;
1274                                 u_data->io->x2_tmp_usec = u_data->io->x2_akt_usec;
1275                                 sctp_graph_redraw(u_data);
1276                         }
1277                 }
1278                 else if (label_set)
1279                 {
1280                         label_set = FALSE;
1281                         sctp_graph_redraw(u_data);
1282                 }
1283                 else
1284                 {
1285                         x_value = ((event->x-LEFT_BORDER-u_data->io->offset) * ((u_data->io->x2_tmp_sec+u_data->io->x2_tmp_usec/1000000.0)-(u_data->io->x1_tmp_sec+u_data->io->x1_tmp_usec/1000000.0)) / (u_data->io->pixmap_width-LEFT_BORDER-RIGHT_BORDER-u_data->io->offset))+u_data->io->x1_tmp_sec+u_data->io->x1_tmp_usec/1000000.0;
1286                         y_value = (gint)rint((u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset-event->y) * (max_tsn - min_tsn) / (u_data->io->pixmap_height-BOTTOM_BORDER-u_data->io->offset)) + min_tsn;
1287                         text_color = u_data->io->draw_area->style->black_gc;
1288
1289                         if (u_data->dir == 1)
1290                         {
1291                                 tsnlist = u_data->assoc->sort_tsn1;
1292                                 t_size = u_data->assoc->n_data_chunks_ep1;
1293                                 sacklist = u_data->assoc->sort_sack1;
1294                                 s_size = u_data->assoc->n_sack_chunks_ep1;
1295                         }
1296                         else
1297                         {
1298                                 tsnlist = u_data->assoc->sort_tsn2;
1299                                 t_size = u_data->assoc->n_data_chunks_ep2;
1300                                 sacklist = u_data->assoc->sort_sack2;
1301                                 s_size = u_data->assoc->n_sack_chunks_ep2;
1302                         }
1303                         x_tolerance = (gdouble)((u_data->io->tmp_width / u_data->io->axis_width*1.0))*5/1000000.0;
1304                         y_tolerance = (guint32)(((u_data->io->max_y - u_data->io->min_y) / (u_data->io->pixmap_height-TOP_BORDER-BOTTOM_BORDER-u_data->io->offset)) * 2.0);
1305                         if (y_tolerance==0)
1306                                 y_tolerance = 2;
1307                         else if (y_tolerance > 5)
1308                                 y_tolerance = 5;
1309
1310                         for (i=0; i<s_size; i++)
1311                         {
1312                                 sack = (struct tsn_sort*)(g_ptr_array_index(sacklist, i));
1313                                 if ((guint32)abs(sack->tsnumber - y_value)<y_tolerance)
1314                                 {
1315                                         s_diff = fabs((sack->secs+sack->usecs/1000000.0)- x_value);
1316                                         if (s_diff < x_tolerance)
1317                                                 sack_found = TRUE;
1318                                         break;
1319                                 }
1320                         }
1321
1322                         for (i=0; i<t_size; i++)
1323                         {
1324                                 tsn = (struct tsn_sort*)(g_ptr_array_index(tsnlist, i));
1325                                 if ((guint32)abs(tsn->tsnumber - y_value)<y_tolerance)
1326                                 {
1327                                         t_diff = fabs((tsn->secs+tsn->usecs/1000000.0)- x_value);
1328                                         if (sack_found && s_diff < t_diff)
1329                                         {
1330                                                 cf_goto_frame(&cfile, sack->framenumber);
1331                                                 x_value = sack->secs+sack->usecs/1000000.0;
1332                                                 y_value = sack->tsnumber;
1333                                         }
1334                                         else if (t_diff < x_tolerance)
1335                                         {
1336                                                 cf_goto_frame(&cfile, tsn->framenumber);
1337                                                 x_value = tsn->secs+tsn->usecs/1000000.0;
1338                                                 y_value = tsn->tsnumber;
1339                                         }
1340                                         break;
1341                                 }
1342                         }
1343
1344                         g_snprintf(label_string, sizeof(label_string), "(%.6lf, %u)", x_value, y_value);
1345
1346                         label_set = TRUE;
1347
1348                         gdk_draw_line(u_data->io->pixmap,text_color, (gint)(event->x-2), (gint)(event->y), (gint)(event->x+2), (gint)(event->y));
1349                         gdk_draw_line(u_data->io->pixmap,text_color, (gint)(event->x), (gint)(event->y-2), (gint)(event->x), (gint)(event->y+2));
1350                         if (event->x+150>=u_data->io->pixmap_width)
1351                                 position = event->x - 150;
1352                         else
1353                                 position = event->x + 5;
1354
1355
1356                         memcpy(label_string,(gchar *)g_locale_to_utf8(label_string, -1 , NULL, NULL, NULL), 15);
1357                         pango_layout_set_text(layout, label_string, -1);
1358                         pango_layout_get_pixel_size(layout, &lwidth, NULL);
1359
1360                         gdk_draw_layout(u_data->io->pixmap,text_color,
1361                                         (gint)position,
1362                                         (gint)(event->y-10),
1363                                         layout);
1364
1365                         ios=(sctp_graph_t *)g_object_get_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t");
1366
1367                         if(!ios){
1368                                 exit(10);
1369                         }
1370                         gdk_draw_pixmap(u_data->io->draw_area->window,
1371                                         u_data->io->draw_area->style->fg_gc[GTK_WIDGET_STATE(u_data->io->draw_area)],
1372                                         ios->pixmap,
1373                                         0, 0,
1374                                         0, 0,
1375                                         u_data->io->draw_area->allocation.width,
1376                                         u_data->io->draw_area->allocation.height);
1377                 }
1378         }
1379         return TRUE;
1380 }
1381
1382
1383 static void
1384 init_sctp_graph_window(struct sctp_udata *u_data)
1385 {
1386         GtkWidget *vbox;
1387         GtkWidget *hbox;
1388         GtkWidget *bt_close, *tsn_bt, *both_bt, *zoomin_bt;
1389         GtkTooltips *tooltip_in, *tooltip_out;
1390
1391         /* create the main window */
1392         u_data->io->window= dlg_window_new("WSCTP Graphics");  /* transient_for top_level */
1393         gtk_window_set_destroy_with_parent (GTK_WINDOW(u_data->io->window), TRUE);
1394
1395         vbox=gtk_vbox_new(FALSE, 0);
1396         gtk_container_add(GTK_CONTAINER(u_data->io->window), vbox);
1397         gtk_widget_show(vbox);
1398
1399         create_draw_area(vbox, u_data);
1400
1401         sctp_graph_set_title(u_data);
1402
1403         hbox = gtk_hbutton_box_new();
1404         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1405         gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
1406         gtk_button_box_set_layout(GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD);
1407         gtk_box_set_spacing(GTK_BOX (hbox), 0);
1408         gtk_box_set_child_packing(GTK_BOX(vbox), hbox, FALSE, FALSE, 0, GTK_PACK_START);
1409         gtk_widget_show(hbox);
1410         sack_bt = gtk_button_new_with_label ("Show Only Sacks");
1411         gtk_box_pack_start(GTK_BOX(hbox), sack_bt, FALSE, FALSE, 0);
1412         gtk_widget_show(sack_bt);
1413
1414         g_signal_connect(sack_bt, "clicked", G_CALLBACK(on_sack_bt), u_data);
1415         tsn_bt = gtk_button_new_with_label ("Show Only TSNs");
1416         gtk_box_pack_start(GTK_BOX(hbox), tsn_bt, FALSE, FALSE, 0);
1417         gtk_widget_show(tsn_bt);
1418         g_signal_connect(tsn_bt, "clicked", G_CALLBACK(on_tsn_bt), u_data);
1419
1420         both_bt = gtk_button_new_with_label ("Show both");
1421         gtk_box_pack_start(GTK_BOX(hbox), both_bt, FALSE, FALSE, 0);
1422         gtk_widget_show(both_bt);
1423         g_signal_connect(both_bt, "clicked", G_CALLBACK(on_both_bt), u_data);
1424
1425         zoomin_bt = gtk_button_new_with_label ("Zoom in");
1426         gtk_box_pack_start(GTK_BOX(hbox), zoomin_bt, FALSE, FALSE, 0);
1427         gtk_widget_show(zoomin_bt);
1428         g_signal_connect(zoomin_bt, "clicked", G_CALLBACK(on_zoomin_bt), u_data);
1429         tooltip_in = gtk_tooltips_new();
1430         gtk_tooltips_set_tip(tooltip_in, zoomin_bt, "Zoom in the area you have selected", NULL);
1431
1432         zoomout_bt = gtk_button_new_with_label ("Zoom out");
1433         gtk_box_pack_start(GTK_BOX(hbox), zoomout_bt, FALSE, FALSE, 0);
1434         gtk_widget_show(zoomout_bt);
1435         g_signal_connect(zoomout_bt, "clicked", G_CALLBACK(on_zoomout_bt), u_data);
1436         tooltip_out = gtk_tooltips_new();
1437         gtk_tooltips_set_tip(tooltip_out, zoomout_bt, "Zoom out one step", NULL);
1438         gtk_widget_set_sensitive(zoomout_bt, FALSE);
1439
1440         bt_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1441         gtk_box_pack_start(GTK_BOX(hbox), bt_close, FALSE, FALSE, 0);
1442         gtk_widget_show(bt_close);
1443         g_signal_connect(bt_close, "clicked", G_CALLBACK(sctp_graph_close_cb), u_data);
1444
1445         g_signal_connect(u_data->io->draw_area,"button_press_event",G_CALLBACK(on_button_press), u_data);
1446         g_signal_connect(u_data->io->draw_area,"button_release_event",G_CALLBACK(on_button_release), u_data);
1447         gtk_widget_set_events(u_data->io->draw_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK);
1448
1449         gtk_widget_show(u_data->io->window);
1450 }
1451
1452 static void
1453 sctp_graph_set_title(struct sctp_udata *u_data)
1454 {
1455         char *title;
1456
1457         if(!u_data->io->window)
1458         {
1459                 return;
1460         }
1461         title = g_strdup_printf("SCTP TSNs and Sacks over Time: %s Port1 %u Port2 %u Endpoint %u",
1462                                 cf_get_display_name(&cfile), u_data->parent->assoc->port1, u_data->parent->assoc->port2, u_data->dir);
1463         gtk_window_set_title(GTK_WINDOW(u_data->io->window), title);
1464         g_free(title);
1465 }
1466
1467 static void
1468 gtk_sctpgraph_init(struct sctp_udata *u_data)
1469 {
1470         sctp_graph_t *io;
1471         gint dir;
1472         sctp_min_max_t* tmp_minmax;
1473
1474         io=g_malloc(sizeof(sctp_graph_t));
1475         io->needs_redraw=TRUE;
1476         io->x_interval=1000;
1477         io->window=NULL;
1478         io->draw_area=NULL;
1479         io->pixmap=NULL;
1480         io->pixmap_width=800;
1481         io->pixmap_height=600;
1482         io->graph_type=0;
1483         dir=u_data->dir-1;
1484         u_data->io=io;
1485         u_data->io->x1_tmp_sec=u_data->assoc->min_secs;
1486         u_data->io->x1_tmp_usec=u_data->assoc->min_usecs;
1487         u_data->io->x2_tmp_sec=u_data->assoc->max_secs;
1488         u_data->io->x2_tmp_usec=u_data->assoc->max_usecs;
1489         u_data->io->tmp_min_tsn1=u_data->assoc->min_tsn1;
1490         u_data->io->tmp_max_tsn1=u_data->assoc->max_tsn1;
1491         u_data->io->tmp_min_tsn2=u_data->assoc->min_tsn2;
1492         u_data->io->tmp_max_tsn2=u_data->assoc->max_tsn2;
1493         u_data->io->tmp=FALSE;
1494
1495         tmp_minmax = g_malloc(sizeof(sctp_min_max_t));
1496         tmp_minmax->tmp_min_secs = u_data->assoc->min_secs;
1497         tmp_minmax->tmp_min_usecs=u_data->assoc->min_usecs;
1498         tmp_minmax->tmp_max_secs=u_data->assoc->max_secs;
1499         tmp_minmax->tmp_max_usecs=u_data->assoc->max_usecs;
1500         tmp_minmax->tmp_min_tsn2=u_data->assoc->min_tsn2;
1501         tmp_minmax->tmp_min_tsn1=u_data->assoc->min_tsn1;
1502         tmp_minmax->tmp_max_tsn1=u_data->assoc->max_tsn1;
1503         tmp_minmax->tmp_max_tsn2=u_data->assoc->max_tsn2;
1504         u_data->assoc->min_max = g_slist_prepend(u_data->assoc->min_max, tmp_minmax);
1505
1506         /* build the GUI */
1507         init_sctp_graph_window(u_data);
1508         sctp_graph_redraw(u_data);
1509
1510 }
1511
1512
1513 static gint
1514 quit(GtkObject *object _U_, gpointer user_data)
1515 {
1516         struct sctp_udata *u_data=(struct sctp_udata*)user_data;
1517
1518         decrease_childcount(u_data->parent);
1519         remove_child(u_data, u_data->parent);
1520
1521         g_free(u_data->io);
1522
1523         u_data->assoc->min_max = NULL;
1524         g_free(u_data);
1525         return TRUE;
1526 }
1527
1528
1529 static void
1530 create_draw_area(GtkWidget *box, struct sctp_udata *u_data)
1531 {
1532
1533         u_data->io->draw_area=gtk_drawing_area_new();
1534         g_signal_connect(u_data->io->draw_area, "destroy", G_CALLBACK(quit), u_data);
1535         g_object_set_data(G_OBJECT(u_data->io->draw_area), "sctp_graph_t", u_data->io);
1536
1537         gtk_widget_set_size_request(u_data->io->draw_area, u_data->io->pixmap_width, u_data->io->pixmap_height);
1538
1539         /* signals needed to handle backing pixmap */
1540         g_signal_connect(u_data->io->draw_area, "expose_event", G_CALLBACK(expose_event), NULL);
1541         g_signal_connect(u_data->io->draw_area, "configure_event", G_CALLBACK(configure_event), u_data);
1542
1543         gtk_widget_show(u_data->io->draw_area);
1544         gtk_box_pack_start(GTK_BOX(box), u_data->io->draw_area, TRUE, TRUE, 0);
1545 }
1546
1547
1548
1549 void
1550 create_graph(guint16 dir, struct sctp_analyse* userdata)
1551 {
1552         struct sctp_udata *u_data;
1553
1554         u_data=g_malloc(sizeof(struct sctp_udata));
1555         u_data->assoc=g_malloc(sizeof(sctp_assoc_info_t));
1556         u_data->assoc=userdata->assoc;
1557         u_data->io=NULL;
1558         u_data->dir = dir;
1559         u_data->parent = userdata;
1560         if ((u_data->dir==1 && u_data->assoc->n_array_tsn1==0)|| (u_data->dir==2 && u_data->assoc->n_array_tsn2==0))
1561                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "No Data Chunks sent");
1562         else
1563         {
1564                 set_child(u_data, u_data->parent);
1565                 increase_childcount(u_data->parent);
1566                 gtk_sctpgraph_init(u_data);
1567         }
1568 }
1569
1570 #if defined(_WIN32) && !defined(__MINGW32__)
1571 /* replacement of Unix rint() for Windows */
1572 static int
1573 rint (double x)
1574 {
1575         char *buf;
1576         int i,dec,sig;
1577
1578         buf = _fcvt(x, 0, &dec, &sig);
1579         i = atoi(buf);
1580         if(sig == 1) {
1581                 i = i * -1;
1582         }
1583         return(i);
1584 }
1585 #endif