aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS5
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.nmake3
-rw-r--r--g711.c283
-rw-r--r--g711.h28
-rw-r--r--gtk/Makefile.am6
-rw-r--r--gtk/Makefile.nmake5
-rw-r--r--gtk/menu.c5
-rw-r--r--gtk/tap_rtp.c1997
-rw-r--r--gtk/tap_rtp.h27
-rw-r--r--packet-rtp.c20
-rw-r--r--packet-rtp.h13
12 files changed, 2386 insertions, 10 deletions
diff --git a/AUTHORS b/AUTHORS
index fd2e5979eb..a8f6bfeb28 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1635,6 +1635,11 @@ Lars Ronald <Lars.Roland [AT] gmx.net> {
MGCP request/response matching and MGCPSTAT calculation
}
+Miha Jemec <m.jemec [AT] iskratel.si> {
+ Support to follow a RTP stream and save it as a file.
+ Support for G.711 codec
+}
+
And assorted fixes and enhancements by the people listed above and by:
Pavel Roskin <proski [AT] gnu.org>
diff --git a/Makefile.am b/Makefile.am
index 81afca8c94..6d8f36dad3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.565 2003/03/06 09:01:40 sahlberg Exp $
+# $Id: Makefile.am,v 1.566 2003/03/06 20:35:09 sahlberg Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -678,6 +678,8 @@ ETHEREAL_COMMON_SRC = \
follow.c \
follow.h \
format-oid.h \
+ g711.c \
+ g711.h \
greproto.h \
in_cksum.c \
in_cksum.h \
diff --git a/Makefile.nmake b/Makefile.nmake
index 7fabd50fb9..0bc96d81e0 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.285 2003/03/06 09:01:40 sahlberg Exp $
+# $Id: Makefile.nmake,v 1.286 2003/03/06 20:35:09 sahlberg Exp $
include config.nmake
include <win32.mak>
@@ -379,6 +379,7 @@ ETHEREAL_COMMON_OBJECTS = \
crypt-md5.obj \
crypt-rc4.obj \
follow.obj \
+ g711.obj \
getopt.obj \
in_cksum.obj \
ipproto.obj \
diff --git a/g711.c b/g711.c
new file mode 100644
index 0000000000..a5f4679efb
--- /dev/null
+++ b/g711.c
@@ -0,0 +1,283 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g711.c
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define NSEGS (8) /* Number of A-law segments. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+#define SEG_MASK (0x70) /* Segment field mask. */
+
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
+
+/* copy from CCITT G.711 specifications */
+unsigned char _u2a[128] = { /* u- to A-law conversions */
+ 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 27, 29, 31, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 46, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128};
+
+unsigned char _a2u[128] = { /* A- to u-law conversions */
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127};
+
+static int
+search(
+ int val,
+ short *table,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (val <= *table++)
+ return (i);
+ }
+ return (size);
+}
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2alaw(
+ int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char aval;
+ if (pcm_val >= 0) {
+ mask = 0xD5; /* sign (7th) bit = 1 */
+ } else {
+ mask = 0x55; /* sign bit = 0 */
+ pcm_val = -pcm_val - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /* Combine the sign, segment, and quantization bits. */
+
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ aval = seg << SEG_SHIFT;
+ if (seg < 2)
+ aval |= (pcm_val >> 4) & QUANT_MASK;
+ else
+ aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+ return (aval ^ mask);
+ }
+}
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+int
+alaw2linear(
+ unsigned char a_val)
+{
+ int t;
+ int seg;
+ //printf(" vrednost a_val %X ", a_val);
+ a_val ^= 0x55;
+
+ t = (a_val & QUANT_MASK) << 4;
+ seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+ switch (seg) {
+ case 0:
+ t += 8;
+ break;
+ case 1:
+ t += 0x108;
+ break;
+ default:
+ t += 0x108;
+ t <<= seg - 1;
+ }
+ //printf("izracunan int %d in njegov hex %X \n", t,t);
+ return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#define BIAS (0x84) /* Bias for linear code. */
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2ulaw(
+ int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char uval;
+
+ /* Get the sign and the magnitude of the value. */
+ if (pcm_val < 0) {
+ pcm_val = BIAS - pcm_val;
+ mask = 0x7F;
+ } else {
+ pcm_val += BIAS;
+ mask = 0xFF;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+ return (uval ^ mask);
+ }
+
+}
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int
+ulaw2linear(
+ unsigned char u_val)
+{
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & QUANT_MASK) << 3) + BIAS;
+ t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+ return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+/* A-law to u-law conversion */
+unsigned char
+alaw2ulaw(
+ unsigned char aval)
+{
+ aval &= 0xff;
+ return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+ (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/* u-law to A-law conversion */
+unsigned char
+ulaw2alaw(
+ unsigned char uval)
+{
+ uval &= 0xff;
+ return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+ (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
diff --git a/g711.h b/g711.h
new file mode 100644
index 0000000000..1c16824f29
--- /dev/null
+++ b/g711.h
@@ -0,0 +1,28 @@
+/*
+ * g711.h
+ *
+ * Definitions for routines for u-law, A-law and linear PCM conversions
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+unsigned char linear2alaw( int );
+int alaw2linear( unsigned char );
+unsigned char linear2ulaw( int );
+int ulaw2linear( unsigned char );
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 82f2116536..99bd8d357c 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for the GTK interface routines for Ethereal
#
-# $Id: Makefile.am,v 1.53 2003/01/22 00:40:36 sahlberg Exp $
+# $Id: Makefile.am,v 1.54 2003/03/06 20:35:12 sahlberg Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -37,7 +37,9 @@ ETHEREAL_TAP_SRC = \
rpc_progs.c \
rpc_progs.h \
smb_stat.c \
- smb_stat.h
+ smb_stat.h \
+ tap_rtp.c \
+ tap_rtp.h
ethereal-tap-register.c: $(ETHEREAL_TAP_SRC) $(top_srcdir)/make-tapreg-dotc
@echo Making ethereal-tap-register.c
diff --git a/gtk/Makefile.nmake b/gtk/Makefile.nmake
index 1cf9636c05..1e43c56fe8 100644
--- a/gtk/Makefile.nmake
+++ b/gtk/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.40 2003/02/10 23:34:49 guy Exp $
+# $Id: Makefile.nmake,v 1.41 2003/03/06 20:35:12 sahlberg Exp $
include ..\config.nmake
@@ -26,7 +26,8 @@ ETHEREAL_TAP_SRC = \
io_stat.c \
rpc_stat.c \
rpc_progs.c \
- smb_stat.c
+ smb_stat.c \
+ tap_rtp.c
ETHEREAL_TAP_OBJECTS = $(ETHEREAL_TAP_SRC:.c=.obj)
diff --git a/gtk/menu.c b/gtk/menu.c
index d7df085c2f..252ec5d8aa 100644
--- a/gtk/menu.c
+++ b/gtk/menu.c
@@ -1,7 +1,7 @@
/* menu.c
* Menu routines
*
- * $Id: menu.c,v 1.83 2003/01/22 00:40:36 sahlberg Exp $
+ * $Id: menu.c,v 1.84 2003/03/06 20:35:12 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -64,6 +64,7 @@
#include "smb_stat.h"
#include "compat_macros.h"
#include "gtkglobals.h"
+#include "tap_rtp.h"
GtkWidget *popup_menu_object;
@@ -218,6 +219,8 @@ static GtkItemFactoryEntry menu_items[] =
0, NULL, NULL),
ITEM_FACTORY_ENTRY("/Tools/_Decode As...", NULL, decode_as_cb,
0, NULL, NULL),
+ ITEM_FACTORY_ENTRY("/Tools/_RTP analysis...", NULL, rtp_analyse_cb,
+ 0, NULL, NULL),
ITEM_FACTORY_ENTRY("/Tools/_Go To Corresponding Frame", NULL, goto_framenum_cb,
0, NULL, NULL),
/* {"/Tools/Graph", NULL, NULL, 0, NULL}, future use */
diff --git a/gtk/tap_rtp.c b/gtk/tap_rtp.c
new file mode 100644
index 0000000000..51a2942e55
--- /dev/null
+++ b/gtk/tap_rtp.c
@@ -0,0 +1,1997 @@
+/*
+ * tap_rtp.c
+ *
+ * RTP analysing addition for ethereal
+ *
+ * Copyright 2003, Iskratel, Ltd, Kranj
+ * By Miha Jemec <m.jemec@iskratel.si>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This tap works as follows:
+ * When the user clicks on the RTP analisys button, we first check if it is a RTP packet.
+ * If yes we store the SSRC, ip, and port values. Then the tap is registered and the
+ * redissect_packets() routine is called. So we go through all the RTP packets and search
+ * for SSRC of reversed connection (it has inversed socket parameters). If more than one
+ * is found a window is displayed where the user can select the appropriate from the list.
+ * Rigth now we have the information about the converstion we are looking for (both SSRC).
+ * The redissect_packets() routine is called again. This time whenever a RTP packet with
+ * matching SSRC values arrives, we store all the information we need (number, sequence
+ * number, arrival time, ...) and compute the delay, jitter and wrong sequence number.
+ * We add this values to CList. If the RTP packet carries voice in g711 alaw or ulaw, we
+ * also store this voice information in a temp file. Window is displayed.
+ * Then three buttons are available: Close, Refresh and Save voice.
+ * The Refresh button calls the redissect_packets() routine again. It goes through the packets
+ * again and does all the calculation again (if capturing in real time this means that some
+ * more packets could come and can be computed in statistic). It also writes the sound
+ * data again.
+ * The Save voice button opens the dialog where we can choose the file name, format (not yet)
+ * and direction we want to save. Currently it works only with g711 alaw and ulaw, and if the
+ * length of captured packets is equal the length of packets on wire and if there are no padding
+ * bits.
+ *
+ * To do:
+ * - Support for saving voice in more different formats and with more different codecs:
+ * Since this should be portable to all OS, there is only possibility to save the
+ * voice in a file and not play it directly through the sound card. There are enough
+ * players on all platforms, that are doing right this. What about the format?
+ * Currently there is only support for saving as an .au file (ulaw, 8000 Hz, 8bit)
+ * There are many players for this format on all platforms (for example Windows Media Player
+ * under Windows, command play under Linux). Support will be added for wav format and
+ * possibility to save with two channels (separate channel for each direction)
+ *
+ * - Support for more codecs. Now you can save voice only if the codec is g.711 alaw or ulaw.
+ *
+ * - right now, the reversed connection must have the same (only inversed) ip and port numbers.
+ * I think that there is no reason that in special cases the reversed connection would not use
+ * some different port or even the IP combination (please correct me if I am wrong).
+ * So this will be added soon.
+ *
+ * - some more statistics (delay and jitter distribution)
+ *
+ * - GTK2 implementation
+ *
+ * - grammar correction
+ *
+ * - some more testing (other OS)
+ *
+ * XXX Problems:
+ *
+ * - how to use snprintf (or g_snprintf) with guint16, guint32 ? If I put %lu for guint32
+ * then compiler makes a warning but it works. If I put %d for guint32,
+ * then compiler doesn't warns, but then it doesn't work
+ *
+ * - instead of tmpnam() use of mkstemp().
+ * I tried to do it with mkstemp() but didn't now how to solve following problem:
+ * I call mkstemp() and then write in this temp file and it works fine . But if the user
+ * then hits the refresh button, this temp file should be deleted and opened again. I tried
+ * to call close() and unlink(), but when I call mkstemp() for the second time I always get
+ * an error ( -1) as return value. What is the correct order? Is it possible to call
+ * mkstemp() twice with the same template?
+ *
+ * - problem with statistics for lost (late, duplicated) packets. How to make the statistic
+ * more resistant to special (bizarre) arrival of sequence numbers
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <gtk/gtk.h>
+#include "tap_rtp.h"
+#include "globals.h"
+#include <string.h>
+#include "epan/packet_info.h"
+#include <epan/epan_dissect.h>
+#include <epan/filesystem.h>
+#include "../tap.h"
+#include "../register.h"
+#include "../packet-rtp.h"
+#include "file_dlg.h"
+#include "dlg_utils.h"
+#include "ui_util.h"
+#include "simple_dialog.h"
+#include "main.h"
+#include <math.h>
+#include "progress_dlg.h"
+#include "compat_macros.h"
+#include "../g711.h"
+#include <unistd.h>
+#include <fcntl.h>
+
+static GtkWidget *rtp_w = NULL;
+static GtkWidget *voice_w = NULL;
+static GtkWidget *save_w = NULL;
+static GtkWidget *main_vb;
+static GtkWidget *clist;
+static GtkWidget *clist_r;
+static GtkWidget *max;
+static GtkWidget *max_r;
+
+static gboolean copy_file(gchar *, /*gint,*/ gint, void *);
+
+char f_tempname[100], r_tempname[100];
+
+/* type of error when saving voice in a file didn't succeed */
+typedef enum {
+ WRONG_CODEC,
+ WRONG_LENGTH,
+ PADDING_SET,
+ FILE_OPEN_ERROR,
+ NO_DATA
+} error_type_t;
+
+/* structure that holds the information about the forwarding and reversed connection */
+/* f_* always aplies to the forward direction and r_* to the reversed */
+typedef struct _info_stat {
+ gchar source[16];
+ gchar destination[16];
+ guint16 srcport;
+ guint16 dstport;
+ guint32 ssrc_forward;
+ guint32 ssrc_reversed;
+ guint32 *ssrc_tmp;
+ gboolean search_ssrc;
+ guint reversed_ip;
+ guint reversed_ip_and_port;
+ gboolean f_first_packet;
+ gboolean r_first_packet;
+ guint16 f_seq_num;
+ guint16 r_seq_num;
+ guint32 f_timestamp;
+ guint32 r_timestamp;
+ guint32 f_delta_timestamp;
+ guint32 r_delta_timestamp;
+ double f_delay;
+ double r_delay;
+ double f_jitter;
+ double r_jitter;
+ double f_time;
+ double r_time;
+ double f_start_time;
+ double r_start_time;
+ double f_max_delay;
+ double r_max_delay;
+ guint32 f_max_nr;
+ guint32 r_max_nr;
+ guint16 f_start_seq_nr;
+ guint16 r_start_seq_nr;
+ guint16 f_stop_seq_nr;
+ guint16 r_stop_seq_nr;
+ guint32 f_total_nr;
+ guint32 r_total_nr;
+ guint32 f_sequence;
+ guint32 r_sequence;
+ gint f_cycles;
+ gint r_cycles;
+ gboolean f_under;
+ gboolean r_under;
+ FILE *f_fp;
+ FILE *r_fp;
+ gboolean f_saved;
+ gboolean r_saved;
+ error_type_t f_error_type;
+ error_type_t r_error_type;
+ guint32 f_count;
+ guint32 r_count;
+} info_stat;
+
+
+/* when there is a [re]reading of packet's */
+static void
+rtp_reset(void *prs)
+{
+ info_stat *rs=prs;
+
+ rs->f_first_packet = TRUE;
+ rs->r_first_packet = TRUE;
+ rs->f_max_delay = 0;
+ rs->r_max_delay = 0;
+ rs->f_max_nr = 0;
+ rs->r_max_nr = 0;
+ rs->f_total_nr = 0;
+ rs->r_total_nr = 0;
+ rs->f_sequence = 0;
+ rs->r_sequence = 0;
+ rs->f_start_seq_nr = 0;
+ rs->r_start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */
+ rs->f_stop_seq_nr = 0;
+ rs->r_stop_seq_nr = 0;
+ rs->f_cycles = 0;
+ rs->r_cycles = 0;
+ rs->f_under = FALSE;
+ rs->r_under = FALSE;
+ rs->f_saved = FALSE;
+ rs->r_saved = FALSE;
+ rs->f_start_time = 0;
+ rs->r_start_time = 0;
+ rs->f_count = 0;
+ rs->r_count = 0;
+ /* XXX check for error at fclose? */
+ if (rs->f_fp != NULL)
+ fclose(rs->f_fp);
+ if (rs->r_fp != NULL)
+ fclose(rs->r_fp);
+ rs->f_fp = fopen(f_tempname, "w");
+ if (rs->f_fp == NULL)
+ rs->f_error_type = FILE_OPEN_ERROR;
+ rs->r_fp = fopen(r_tempname, "w");
+ if (rs->r_fp == NULL)
+ rs->r_error_type = FILE_OPEN_ERROR;
+ return;
+}
+
+/* here we can redraw the output */
+/* not used yet */
+static void rtp_draw(void *prs _U_)
+{
+ return;
+}
+
+/* when we are finished with redisection, we add the label for the statistic */
+static void draw_stat(void *prs)
+{
+ info_stat *rs=prs;
+ gchar label_max[200];
+ guint32 f_expected = (rs->f_stop_seq_nr + rs->f_cycles*65536) - rs->f_start_seq_nr + 1;
+ guint32 r_expected = (rs->r_stop_seq_nr + rs->r_cycles*65536) - rs->r_start_seq_nr + 1;
+ gint32 f_lost = f_expected - rs->f_total_nr;
+ gint32 r_lost = r_expected - rs->r_total_nr;
+
+ g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
+ "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
+ " Sequence error = %u",
+ rs->f_max_delay, rs->f_max_nr, rs->f_total_nr, f_expected,
+ f_lost, rs->f_sequence);
+
+ gtk_label_set_text(GTK_LABEL(max), label_max);
+
+ g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
+ "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
+ " Sequence error = %u",
+ rs->r_max_delay, rs->r_max_nr, rs->r_total_nr, r_expected,
+ r_lost, rs->r_sequence);
+
+ gtk_label_set_text(GTK_LABEL(max_r), label_max);
+
+ /* could be done somewhere else, but can be here as well */
+ /* if this is true, then we don't have any reversed connection, so the error type
+ * will be no data. This applies only the reversed connection */
+ if (rs->reversed_ip_and_port == 0)
+ rs->r_error_type = NO_DATA;
+
+ return ;
+}
+
+/* append a line to clist */
+/* XXX is there a nicer way to make these assignements? */
+static void add_to_clist(gboolean forward, guint32 number, guint16 seq_num,
+ double delay, double jitter, gboolean status, gboolean marker)
+{
+ gchar *data[6];
+ gchar field[6][30];
+
+ data[0]=&field[0][0];
+ data[1]=&field[1][0];
+ data[2]=&field[2][0];
+ data[3]=&field[3][0];
+ data[4]=&field[4][0];
+ data[5]=&field[5][0];
+
+ g_snprintf(field[0], 20, "%u", number);
+ g_snprintf(field[1], 20, "%u", seq_num);
+ g_snprintf(field[2], 20, "%f", delay);
+ g_snprintf(field[3], 20, "%f", jitter);
+ g_snprintf(field[4], 20, "%s", marker? "SET" : "");
+ g_snprintf(field[5], 29, "%s", status? "OK" : "NOK - Wrong sequence nr.");
+
+ gtk_clist_append(GTK_CLIST(forward? clist : clist_r), data);
+
+}
+
+/* whenever a RTP packet is seen by the tap listener */
+/* this function works as follows:
+ * 1) packets that are not displayed are ignored
+ * return
+ * 2) are we searching what could be the reversed connection (looking for reversed SSRC)
+ * if yes, do the parameters match (inversed IP and port combination from the forward one)?
+ * if yes, do we already have this SSRC stored
+ * if not store it
+ * 3) if not, is current packet matching the forward direction
+ * is it the first time we see a packet in this direction
+ * if yes, store some values, add a line to list and save the voice info
+ * in a temporary file if the codec is supported and the RTP data is ok
+ * if not, is it a packet with mark bit set (there was silence surpression)
+ * same as above, only we have to add some silence in front of the voice data
+ * if not, then this must be a normal packet
+ * store the values and voice data
+ * 4) if not, is current packet matching the reversed connection
+ * (same as for number 3)
+ */
+static int rtp_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, void *vpri)
+{
+ info_stat *rs=prs;
+ struct _rtp_info *pri=vpri;
+ guint i;
+ double n_time;
+ double n_jitter;
+ guint8 *data;
+ gint16 tmp;
+
+ /* we ignore packets that are not displayed */
+ if (pinfo->fd->flags.passed_dfilter == 0)
+ return 0;
+
+ /* are we looking for the SSRC of the reversed connection? */
+ if (rs->search_ssrc != FALSE) {
+ /* XXX what should be the rules for reversed connection?
+ * 1. It should should have same inversed IP and port numbers
+ * 2. If none are found, only inversed IP's - is this possible?
+ * 3. If none are found, there isn't any reversed connection
+ * XXX is it possible that the conversation is not P2P?
+ * Curretly it works only if it matches the number 1. */
+
+ /* have we found inverse parameters? */
+ if ( strcmp(ip_to_str(pinfo->src.data), rs->destination) == 0 &&
+ strcmp( ip_to_str(pinfo->dst.data), rs->source) == 0 ) {
+
+ /* do the ports also match? */
+ if ((rs->srcport == pinfo->destport) && (rs->dstport == pinfo->srcport)) {
+ /* ok, the ip and port combination does match
+ * do we already have this ssrc stored */
+ for(i=0; i< rs->reversed_ip_and_port; i++) {
+ if (pri->info_sync_src == *(rs->ssrc_tmp+i) )
+ return 0;
+ }
+
+ /* no, we found new ssrc, let's store it */
+ rs->ssrc_tmp = (guint32*)g_realloc(rs->ssrc_tmp,
+ (i+1)*sizeof(guint32));
+ *(rs->ssrc_tmp+i) = pri->info_sync_src;
+ rs->reversed_ip_and_port++;
+ return 0;
+ }
+ /* no, only ip addresses match */
+ /* XXX not implemented yet */
+ else {
+ rs->reversed_ip++;
+ return 0;
+ }
+
+ }
+ }
+
+ /* ok, we are not looking for SSRC of the reversed connection */
+ /* is it the forward direction?
+ * if yes, there 3 possibilities:
+ * a) is this the first packet we got in this direction?
+ * b) or is it a packet with the mark bit set?
+ * c) if neither then it is a "normal" packet */
+ else if (rs->ssrc_forward == pri->info_sync_src) {
+ /* first packet? */
+ if (rs->f_first_packet != FALSE) {
+ /* we store all the values */
+ rs->f_seq_num = pri->info_seq_num;
+ rs->f_delay = 0;
+ rs->f_jitter = 0;
+ rs->f_first_packet = FALSE;
+ rs->f_timestamp = pri->info_timestamp;
+ rs->f_start_seq_nr = pri->info_seq_num;
+ rs->f_stop_seq_nr = pri->info_seq_num;
+ rs->f_total_nr++;
+ rs->f_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ rs->f_start_time = rs->f_time;
+ /* and add a row to clist; delay and jitter are 0 for the first packet */
+ add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);
+
+ /* and now save the voice info */
+
+ /* if we couldn't open the tmp file for writing, then we set the flag */
+ if (rs->f_fp == NULL) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = FILE_OPEN_ERROR;
+ return 0;
+ }
+ /* if the captured length and packet length aren't equal, we quit
+ * because there is some information missing */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we put the pointer at the beggining of the RTP data, that is
+ * at the end of the current frame minus the length of the
+ * RTP field plus 12 for the RTP header */
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ rs->f_saved = TRUE;
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ rs->f_saved = TRUE;
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ /* packet with mark bit set? */
+ if (pri->info_marker_set != FALSE) {
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ /* jitter is calculated as for RCTP - RFC 1889
+ * J = J + ( | D(i-1, i) | - J) / 16
+ * XXX the output there should be in timestamp (probably miliseconds)
+ * units expressed as an unsigned integer, so should we do it the same?
+ * (currently we use seconds)
+ *
+ * XXX Packet loss in RTCP is calculated as the difference between the
+ * number of packets expected and actually received, where for actually
+ * received the number is simply the count of packets as they arrive,
+ * including any late or duplicate packets (this means that the number
+ * can be negative). For example, if the seq numbers of the arrived
+ * packets are: 1,2,3,4,5,5,7,7,9,10 the expected number is 10 and the
+ * the number of actually captured frames is also 10. So in upper
+ * calculation there would be no losses. But there are 2 losses and
+ * 2 duplicate packets. Because this kind of statistic is rather
+ * useless (or confusing) we add the information, that there was
+ * an error with sequence number each time the sequence number was
+ * not one bigger than the previous one
+ */
+
+ /* jitter calculation */
+ n_jitter = rs->f_jitter + ( fabs(n_time-(rs->f_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;
+
+ /* we add the information into the clist */
+ add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),
+ n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);
+
+ /* when calculating expected rtp packets the seq number can wrap around
+ * so we have to count the number of cycles
+ * f_cycles counts the wraps around in forwarding connection and
+ * f_under is flag that indicates where we are
+ *
+ * XXX how to determine number of cycles with all possible lost, late
+ * and duplicated packets without any doubt? It seems to me, that
+ * because of all possible combination of late, duplicated or lost
+ * packets, this can only be more or less good approximation
+ *
+ * There are some combinations (rare but theoretically possible),
+ * where below code won't work correctly - statistic may be wrong then.
+ */
+
+ /* so if the current sequence number is less than the start one
+ * we assume, that there is another cycle running */
+ if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ /* what if the start seq nr was 0. Then the above condition will never
+ * be true, so we add another condition. XXX The problem would arise if
+ * if one of the packets with seq nr 0 or 65535 would be lost or late */
+ else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) &&
+ (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->f_start_seq_nr)&&(rs->f_under!=FALSE)){
+ rs->f_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->f_seq_num+1 == pri->info_seq_num)
+ rs->f_seq_num = pri->info_seq_num;
+ /* XXX same problem as above */
+ else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->f_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->f_seq_num+1 < pri->info_seq_num) {
+ rs->f_seq_num = pri->info_seq_num;
+ rs->f_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->f_seq_num+1 > pri->info_seq_num)
+ rs->f_sequence++;
+
+ rs->f_stop_seq_nr = pri->info_seq_num;
+ rs->f_time = n_time;
+ rs->f_jitter = n_jitter;
+ rs->f_delta_timestamp = pri->info_timestamp - rs->f_timestamp;
+ rs->f_timestamp = pri->info_timestamp;
+ rs->f_total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (rs->f_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = PADDING_SET;
+ return 0;
+ }
+ /* because the mark bit is set, we have to add some silence in front */
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we insert some silence */
+ /* XXX the amount of silence should be the difference between
+ * the last timestamp and the current one minus x in the
+ * I am not sure if x is equal the amount of information
+ * current packet? */
+ for(i=0; i<(rs->f_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ for(i=0; i < (rs->f_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_CODEC;
+ return 0;
+ }
+ return 0;
+ }
+
+ /* normal packet in forward connection */
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ n_jitter = rs->f_jitter + ( fabs (n_time-(rs->f_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;
+ rs->f_delay = n_time-(rs->f_time);
+ /* the delay is bigger than previous max delay, so store the delay and nr */
+ if (rs->f_delay > rs->f_max_delay) {
+ rs->f_max_delay = rs->f_delay;
+ rs->f_max_nr = pinfo->fd->num;
+ }
+ add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),
+ n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);
+
+ /* count the cycles */
+ if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) &&
+ (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->f_start_seq_nr+1)&&(rs->f_under!=FALSE)){
+ rs->f_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->f_seq_num+1 == pri->info_seq_num)
+ rs->f_seq_num = pri->info_seq_num;
+ else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->f_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->f_seq_num+1 < pri->info_seq_num) {
+ rs->f_seq_num = pri->info_seq_num;
+ rs->f_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->f_seq_num+1 > pri->info_seq_num)
+ rs->f_sequence++;
+
+ rs->f_stop_seq_nr = pri->info_seq_num;
+ rs->f_time = n_time;
+ rs->f_jitter = n_jitter;
+ rs->f_timestamp = pri->info_timestamp;
+ rs->f_total_nr++;
+
+ /* save the voice information */
+ /* we do it only in following cases:
+ * - the codecs we support are g.711 alaw in ulaw
+ * - the captured length must equal the packet length
+ * - XXX we don't support it if there are padding bits
+ */
+ /* if there was already an error, we quit */
+ if (rs->f_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* cfile.pd points at the beggining of the actual packet. We have
+ * to move this pointer at the RTP data. This is the packet length,
+ * minus whole RTP data length (including the RTP header, that is
+ * why we add 12) */
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len - 12); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ /* is it the reversed direction? */
+ else if (rs->ssrc_reversed == pri->info_sync_src) {
+ /* first packet? */
+ if (rs->r_first_packet !=FALSE) {
+ rs->r_seq_num = pri->info_seq_num;
+ rs->r_delay = 0;
+ rs->r_jitter = 0;
+ rs->r_first_packet = FALSE;
+ rs->r_timestamp = pri->info_timestamp;
+ rs->r_start_seq_nr = pri->info_seq_num;
+ rs->r_stop_seq_nr = pri->info_seq_num;
+ rs->r_total_nr++;
+ rs->r_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ rs->r_start_time = rs->r_time;
+ add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);
+
+ /* save it */
+ /* if we couldn't open the tmp file for writing, then we set the flag */
+ if (rs->r_fp == NULL) {
+ rs->r_saved = FALSE;
+ return 0;
+ }
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ rs->r_saved = TRUE;
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ rs->r_saved = TRUE;
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ /* packet with mark bit set? */
+ if (pri->info_marker_set != FALSE) {
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;
+ add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),
+ n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);
+
+ /* count the cycles */
+ if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) &&
+ (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){
+ rs->r_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->r_seq_num+1 == pri->info_seq_num)
+ rs->r_seq_num = pri->info_seq_num;
+ else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->r_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->r_seq_num+1 < pri->info_seq_num) {
+ rs->r_seq_num = pri->info_seq_num;
+ rs->r_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->r_seq_num+1 > pri->info_seq_num)
+ rs->r_sequence++;
+
+ rs->r_stop_seq_nr = pri->info_seq_num;
+ rs->r_time = n_time;
+ rs->r_jitter = n_jitter;
+ rs->r_delta_timestamp = pri->info_timestamp - rs->r_timestamp;
+ rs->r_timestamp = pri->info_timestamp;
+ rs->r_total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (rs->r_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = PADDING_SET;
+ return 0;
+ }
+ /* because the mark bit is set, we have to add some silence in front */
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we insert some silence */
+ for(i=0; i<(rs->r_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ for(i=0; i < (rs->r_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_CODEC;
+ return 0;
+ }
+ return 0;
+ }
+
+ /* normal packet in reversed connection */
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;
+ rs->r_delay = n_time-(rs->r_time);
+ if (rs->r_delay > rs->r_max_delay) {
+ rs->r_max_delay = rs->r_delay;
+ rs->r_max_nr = pinfo->fd->num;
+ }
+ add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),
+ n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);
+ /* count the cycles */
+ if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) &&
+ (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){
+ rs->r_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->r_seq_num+1 == pri->info_seq_num)
+ rs->r_seq_num = pri->info_seq_num;
+ else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->r_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->r_seq_num+1 < pri->info_seq_num) {
+ rs->r_seq_num = pri->info_seq_num;
+ rs->r_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->r_seq_num+1 > pri->info_seq_num)
+ rs->r_sequence++;
+
+ rs->r_stop_seq_nr = pri->info_seq_num;
+ rs->r_time = n_time;
+ rs->r_jitter = n_jitter;
+ rs->r_timestamp = pri->info_timestamp;
+ rs->r_total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (rs->r_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* XXX just copied from gtk/rpc_stat.c */
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+
+
+/* here we close the rtp analysis dialog window and remove the tap listener */
+static void rtp_destroy_cb(GtkWidget *win _U_, gpointer data _U_)
+{
+ info_stat *rs=(info_stat *)data;
+
+ protect_thread_critical_region();
+ remove_tap_listener(rs);
+ unprotect_thread_critical_region();
+
+ /* xxx is this enough? */
+ g_free(rs->ssrc_tmp);
+ g_free(rs);
+
+ if (rs->f_fp != NULL)
+ fclose(rs->f_fp);
+ if (rs->r_fp != NULL)
+ fclose(rs->r_fp);
+ remove(f_tempname);
+ remove(r_tempname);
+
+ /* is there a save window open */
+ if (save_w != NULL)
+ gtk_widget_destroy(save_w);
+
+ /* Is there a save voice window open? */
+ if (voice_w != NULL)
+ gtk_widget_destroy(voice_w);
+
+ /* Note that we no longer have a "RTP Analyse" dialog box. */
+ rtp_w = NULL;
+}
+
+/* when the close button in rtp window was clicked */
+/* it seems to me that rtp_destroy_cb is automatically called, so we don't
+ * need to do the g_free... and rtp_w = NULL ... */
+static void rtp_destroy (GtkWidget *close_bt _U_, gpointer parent_w)
+{
+ gtk_grab_remove(GTK_WIDGET(parent_w));
+ gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+/* we search the rtp.ssrc node here (thanks to Guy Harris - code here is magic for me */
+static guint32 process_node(proto_item *ptree_node, header_field_info *hfinformation)
+{
+ field_info *finfo;
+ proto_item *proto_sibling_node;
+ header_field_info *hfssrc;
+ guint32 ssrc;
+
+ finfo = PITEM_FINFO(ptree_node);
+
+ if (hfinformation==(finfo->hfinfo)) {
+ hfssrc = proto_registrar_get_byname("rtp.ssrc");
+ if (hfssrc == NULL)
+ return 0;
+ for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL;
+ ptree_node=g_node_next_sibling(ptree_node)) {
+ finfo=PITEM_FINFO(ptree_node);
+ if (hfssrc==finfo->hfinfo) {
+ ssrc = fvalue_get_integer(finfo->value);
+ return ssrc;
+ }
+ }
+ }
+
+ proto_sibling_node = g_node_next_sibling(ptree_node);
+
+ if (proto_sibling_node) {
+ ssrc = process_node(proto_sibling_node, hfinformation);
+ return ssrc;
+ }
+ else
+ return 0;
+}
+
+/* here we search the rtp protocol */
+static guint32 process_tree(proto_tree *protocol_tree)
+{
+ proto_item *ptree_node;
+ header_field_info *hfinformation;
+
+ hfinformation = proto_registrar_get_byname("rtp");
+ if (hfinformation == NULL)
+ return 0;
+
+ ptree_node = g_node_first_child(protocol_tree);
+ if (!ptree_node)
+ return 0;
+
+ return process_node(ptree_node, hfinformation);
+}
+
+/* when we want to update the information */
+static void refresh_cb(GtkWidget *w _U_, void *pri)
+{
+ info_stat *rs=pri;
+
+ gtk_clist_clear(GTK_CLIST(clist));
+ gtk_clist_clear(GTK_CLIST(clist_r));
+ redissect_packets(&cfile);
+ draw_stat(rs);
+}
+
+/* when the user clicks the close button */
+static void voice_close_cb(GtkWidget *close_bt _U_, gpointer parent_w _U_)
+{
+ gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+static void voice_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+ if (save_w != NULL)
+ gtk_widget_destroy(GTK_WIDGET(save_w));
+
+ /* Note that we no longer have a Save voice info dialog box. */
+ voice_w = NULL;
+}
+
+
+/* the user wants to save in a file */
+/* XXX support for different formats is currently commented out */
+static void ok_button_cb(GtkWidget *ok_bt, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+ GtkWidget *entry, *rev, *forw, *both;
+ /*GtkWidget *wav, *au, *sw;*/
+ gchar *g_dest;
+ gint channels /*, format*/;
+
+ entry = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "file_entry");
+ /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");
+ au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");
+ sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/
+ rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
+ forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
+ both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
+ g_dest = gtk_entry_get_text(GTK_ENTRY(entry));
+
+ /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
+ * we don't support that codec. So we pop up a warning. Maybe it would be better to
+ * disable the ok button or disable the buttons for direction if only one is not ok. The
+ * problem is if we open the save voice dialog and then click the refresh button and maybe
+ * the state changes, so we can't save anymore. In this case we should be able to update
+ * the buttons. For now it is easier if we put the warning when the ok button is pressed.
+ */
+
+ /* we can not save in both dirctions */
+ if ((rs->f_saved == FALSE) && (rs->r_saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {
+ /* there are many combinations here, we just exit when first matches */
+ if ((rs->f_error_type == WRONG_CODEC) || (rs->r_error_type == WRONG_CODEC))
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: Unsupported codec!");
+ else if ((rs->f_error_type == WRONG_LENGTH) || (rs->r_error_type == WRONG_LENGTH))
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: Wrong length of captured packets!");
+ else if ((rs->f_error_type == PADDING_SET) || (rs->r_error_type == PADDING_SET))
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: RTP data with padding!");
+ else
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: File I/O problem!");
+ return;
+ }
+ /* we can not save forward direction */
+ else if ((rs->f_saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||
+ (GTK_TOGGLE_BUTTON (both)->active))) {
+ if (rs->f_error_type == WRONG_CODEC)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: Unsupported codec!");
+ else if (rs->f_error_type == WRONG_LENGTH)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: Wrong length of captured packets!");
+ else if (rs->f_error_type == PADDING_SET)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: RTP data with padding!");
+ else
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: File I/O problem!");
+ return;
+ }
+ /* we can not save reversed direction */
+ else if ((rs->r_saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||
+ (GTK_TOGGLE_BUTTON (both)->active))) {
+ if (rs->r_error_type == WRONG_CODEC)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: Unsupported codec!");
+ else if (rs->r_error_type == WRONG_LENGTH)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: Wrong length of captured packets!");
+ else if (rs->r_error_type == PADDING_SET)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: RTP data with padding!");
+ else if (rs->r_error_type == NO_DATA)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: No RTP data!");
+ else
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: File I/O problem!");
+ return;
+ }
+
+ /* if the file text entry is empty */
+ if (!g_dest[0]) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "Saving to file, but no file specified.");
+ return;
+ }
+
+ /*if (GTK_TOGGLE_BUTTON (wav)->active)
+ format = 1;
+ else if (GTK_TOGGLE_BUTTON (au)->active)
+ format = 2;
+ else if (GTK_TOGGLE_BUTTON (sw)->active)
+ format = 3;*/
+
+ if (GTK_TOGGLE_BUTTON (rev)->active)
+ channels = 2;
+ else if (GTK_TOGGLE_BUTTON (both)->active)
+ channels = 3;
+ else
+ channels = 1;
+
+ if(!copy_file(g_dest, channels/*, format*/, rs)) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "An error occured while saving voice in a file!");
+ return;
+ }
+
+ if (save_w != NULL)
+ gtk_widget_destroy(GTK_WIDGET(save_w));
+
+ /* XXX I get GTK warning (sometimes?)!!! */
+ gtk_widget_destroy(GTK_WIDGET(voice_w));
+}
+
+static void save_ok_button_cb(GtkWidget *w _U_, gpointer data)
+{
+ gchar *f_name;
+
+ f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));
+
+ /* Perhaps the user specified a directory instead of a file.
+ Check whether they did. */
+ if (test_for_directory(f_name) == EISDIR) {
+ /* It's a directory - set the file selection box to display it. */
+ set_last_open_dir(f_name);
+ g_free(f_name);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(data), last_open_dir);
+ return;
+ }
+
+ gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, "file_entry")), f_name);
+ gtk_widget_destroy(GTK_WIDGET(data));
+
+ g_free(f_name);
+}
+
+static void save_cancel_button_cb(GtkWidget *w _U_, gpointer data)
+{
+ gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+static void save_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+ /* Note that we no longer have a Save voice info dialog box. */
+ save_w = NULL;
+}
+
+/* file selection window */
+static void file_selection_cb(GtkWidget *w _U_, gpointer file_entry)
+{
+ if (save_w != NULL) {
+ /* Yes. Just re-activate that dialog box. */
+ reactivate_window(save_w);
+ return;
+ }
+
+ save_w = gtk_file_selection_new ("Ethereal: Save to File");
+ gtk_signal_connect(GTK_OBJECT(save_w), "destroy", GTK_SIGNAL_FUNC(save_destroy_cb), NULL);
+
+ OBJECT_SET_DATA(save_w, "file_entry", file_entry);
+
+ gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->cancel_button), "clicked",
+ GTK_SIGNAL_FUNC(save_cancel_button_cb), GTK_OBJECT(save_w));
+
+ gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->ok_button), "clicked",
+ GTK_SIGNAL_FUNC(save_ok_button_cb), GTK_OBJECT(save_w));
+
+ gtk_widget_show(save_w);
+}
+
+/* when the user wants to save the voice information in a file */
+/* XXX support for different formats is currently commented out */
+static void voice_cb(GtkWidget *w _U_, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+
+ GtkWidget *vertb;
+ GtkWidget *table1;
+ GtkWidget *label_format;
+ GtkWidget *channels_label;
+ /*GSList *format_group = NULL;*/
+ GSList *channels_group = NULL;
+ GtkWidget *forward_rb;
+ GtkWidget *reversed_rb;
+ GtkWidget *both_rb;
+ /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/
+ GtkWidget *hbox3;
+ GtkWidget *file_button;
+ GtkWidget *file_entry;
+ GtkWidget *hbox4;
+ GtkWidget *ok_bt;
+ GtkWidget *cancel_bt;
+
+ /* if we can't save in a file: wrong codec, cut packets or other errors */
+ /* shold the error arise here or later when you click ok button ?
+ * if we do it here, then we must disable the refresh button, so we don't do it here */
+
+ if (voice_w != NULL) {
+ /* There's already a Save voice info dialog box; reactivate it. */
+ reactivate_window(voice_w);
+ return;
+ }
+
+ voice_w = dlg_window_new("Ethereal: Save voice data");
+ gtk_signal_connect(GTK_OBJECT(voice_w), "destroy",
+ GTK_SIGNAL_FUNC(voice_destroy_cb), NULL);
+
+ /* Container for each row of widgets */
+ vertb = gtk_vbox_new(FALSE, 0);
+ gtk_container_border_width(GTK_CONTAINER(vertb), 5);
+ gtk_container_add(GTK_CONTAINER(voice_w), vertb);
+ gtk_widget_show (vertb);
+
+ table1 = gtk_table_new (2, 4, FALSE);
+ gtk_widget_show (table1);
+ gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
+ gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
+
+ label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
+ gtk_widget_show (label_format);
+ gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ /* we support .au - ulaw*/
+/* wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));
+ gtk_widget_show (wav_rb);
+ gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit ");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));
+ gtk_widget_show (sw_rb);
+ gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ au_rb = gtk_radio_button_new_with_label (format_group, ".au");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));
+ gtk_widget_show (au_rb);
+ gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ */
+
+ channels_label = gtk_label_new ("Channels:");
+ gtk_widget_show (channels_label);
+ gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
+
+ forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
+ gtk_widget_show (forward_rb);
+ gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
+ gtk_widget_show (reversed_rb);
+ gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ both_rb = gtk_radio_button_new_with_label (channels_group, "both");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
+ gtk_widget_show (both_rb);
+ gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
+
+ /* if one direction is nok we don't allow saving
+ XXX this is not ok since the user can click the refresh button and cause changes
+ but we can not update this window. So we move all the decision on the time the ok
+ button is clicked
+ if (rs->f_saved == FALSE) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);
+ gtk_widget_set_sensitive(forward_rb, FALSE);
+ gtk_widget_set_sensitive(both_rb, FALSE);
+ }
+ else if (rs->r_saved == FALSE) {
+ gtk_widget_set_sensitive(reversed_rb, FALSE);
+ gtk_widget_set_sensitive(both_rb, FALSE);
+ }
+ */
+ hbox3 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox3);
+ gtk_box_pack_start (GTK_BOX (vertb), hbox3, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox3), 10);
+
+ file_button = gtk_button_new_with_label ("File:");
+ gtk_widget_show (file_button);
+ gtk_box_pack_start (GTK_BOX (hbox3), file_button, FALSE, FALSE, 0);
+
+ file_entry = gtk_entry_new ();
+ gtk_widget_show (file_entry);
+ gtk_box_pack_start (GTK_BOX (hbox3), file_entry, TRUE, TRUE, 10);
+
+ hbox4 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox4);
+ gtk_box_pack_start (GTK_BOX (vertb), hbox4, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox4), 10);
+
+ ok_bt = gtk_button_new_with_label ("OK");
+ gtk_widget_show (ok_bt);
+ gtk_box_pack_start (GTK_BOX (hbox4), ok_bt, TRUE, FALSE, 0);
+ gtk_widget_set_usize (ok_bt, 60, -2);
+ OBJECT_SET_DATA(ok_bt, "file_entry", file_entry);
+ /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);
+ OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);
+ OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/
+ OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
+ OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
+ OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
+
+ cancel_bt = gtk_button_new_with_label (" Cancel ");
+ gtk_widget_show (cancel_bt);
+ gtk_box_pack_start (GTK_BOX (hbox4), cancel_bt, TRUE, FALSE, 0);
+ gtk_widget_set_usize (cancel_bt, 60, -2);
+
+ gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
+ GTK_SIGNAL_FUNC(voice_close_cb), GTK_OBJECT(voice_w));
+
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(ok_button_cb), rs);
+
+ gtk_signal_connect(GTK_OBJECT(file_button), "clicked",
+ GTK_SIGNAL_FUNC(file_selection_cb), file_entry);
+
+ gtk_widget_show(voice_w);
+}
+
+/* all the graphics on the window is done here */
+static void add_rtp_notebook(void *pri)
+{
+ info_stat *rs=pri;
+
+ GtkWidget *notebook, *page, *page_r, *label, *label1, *label2, *label3;
+ GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;
+ GtkWidget *box4, *voice_bt, *refresh_bt, *close_bn;
+
+ gchar *titles[6] = {"Packet nr.", "Sequence", "Delay (s)", "Jitter (s)", "Marker", "Status"};
+ gchar label_forward[150];
+ gchar label_reverse[150];
+
+ /* XXX is it ok to use %lu for guint32? The compiler is not satisfied, but it works
+ * with %d the compiler is satisfied, but it doesn't work */
+ g_snprintf(label_forward, 149,
+ "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
+ rs->source, rs->srcport, rs->destination, rs->dstport, rs->ssrc_forward);
+ g_snprintf(label_reverse, 149,
+ "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
+ rs->destination, rs->dstport, rs->source, rs->srcport, rs->ssrc_reversed);
+
+ gtk_widget_destroy(main_vb);
+ main_vb = gtk_vbox_new(FALSE, 3);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
+ gtk_widget_show(main_vb);
+
+ /* Start a nootbook for flipping between sets of changes */
+ notebook = gtk_notebook_new();
+ gtk_container_add(GTK_CONTAINER(main_vb), notebook);
+ gtk_object_set_data(GTK_OBJECT(rtp_w), "notebook", notebook);
+
+ /* page for forward connection */
+ page = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(page), 20);
+
+ /* scrolled window */
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window, 600, 200);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ /* direction label */
+ label1 = gtk_label_new(label_forward);
+ gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);
+
+ /* place for some statistics */
+ max = gtk_label_new("\n\n");
+ gtk_box_pack_end(GTK_BOX(page), max, FALSE, FALSE, 5);
+
+ /* clist for the information */
+ clist = gtk_clist_new_with_titles(6, titles);
+ gtk_widget_show(clist);
+ gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
+ gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
+
+ /* and the label */
+ label = gtk_label_new(" Forward Direction ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
+
+ /* column width and justification */
+ gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 4, 40);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_CENTER);
+
+ /* same page for reversed connection */
+ page_r = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);
+ scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window_r, 600, 200);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ label3 = gtk_label_new(label_reverse);
+ gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);
+ max_r = gtk_label_new("\n\n");
+ gtk_box_pack_end(GTK_BOX(page_r), max_r, FALSE, FALSE, 5);
+ clist_r = gtk_clist_new_with_titles(6, titles);
+ gtk_widget_show(clist_r);
+ gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_r);
+ gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);
+ label2 = gtk_label_new(" Reversed Direction ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);
+
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 1, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 2, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 3, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 4, 40);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 5, GTK_JUSTIFY_CENTER);
+
+ /* page for help&about or future
+ page_help = gtk_hbox_new(FALSE, 5);
+ label4 = gtk_label_new(" Future ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);
+ frame = gtk_frame_new("");
+ text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");
+ gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);
+ gtk_container_add(GTK_CONTAINER(frame), text);
+ gtk_container_set_border_width(GTK_CONTAINER(frame), 20);
+ gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);
+*/
+ /* show all notebooks */
+ gtk_widget_show_all(notebook);
+
+ /* and the buttons */
+ box4 = gtk_hbutton_box_new();
+ gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(box4), 10);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(box4), GTK_BUTTONBOX_SPREAD);
+ gtk_widget_show(box4);
+
+ voice_bt = gtk_button_new_with_label("Save voice data");
+ gtk_container_add(GTK_CONTAINER(box4), voice_bt);
+ gtk_widget_show(voice_bt);
+ gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",
+ GTK_SIGNAL_FUNC(voice_cb), rs);
+
+ refresh_bt = gtk_button_new_with_label("Refresh");
+ gtk_container_add(GTK_CONTAINER(box4), refresh_bt);
+ gtk_widget_show(refresh_bt);
+ gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",
+ GTK_SIGNAL_FUNC(refresh_cb), rs);
+
+ close_bn = gtk_button_new_with_label("Close");
+ gtk_container_add(GTK_CONTAINER(box4), close_bn);
+ gtk_widget_show(close_bn);
+ gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",
+ GTK_SIGNAL_FUNC(rtp_destroy), GTK_OBJECT(rtp_w));
+
+ redissect_packets(&cfile);
+
+ draw_stat(rs);
+}
+
+
+/* when we click on the selected row it copies that ssrc value into ssrc_reversed */
+static void get_selected_ssrc(GtkWidget *clist_r, gint row, gint column,
+ GdkEventButton *event _U_, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+ gchar *text;
+
+ gtk_clist_get_text(GTK_CLIST(clist_r), row, column, &text);
+ /* XXX is this strtoul portable for guint32? */
+ rs->ssrc_reversed = strtoul(text, (char **)NULL, 10);
+ return;
+}
+
+/* when we click apply button in ssrc reversed dialog */
+static void apply_selected_ssrc(GtkWidget *w _U_, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+ add_rtp_notebook(rs);
+}
+
+/* this function goes through all the packets that have the same ip and port combination
+ * (only inversed) as the forward direction (XXX what if the reversed direction doesn't use
+ * the same ports???) and looks for different SSRC values. This can happen if you capture
+ * two RTP conversations one after another from the same pair of phones (PC's).
+ * Both have same IP's and can also have same port numbers, so they (should) differ only
+ * in SSRC values. In such case we get a list of ssrc values and we have to choose the right
+ * one from the list. If there is only one or none, we do it automatically */
+static void get_reversed_ssrc(void *prs)
+{
+ info_stat *ri = prs;
+ GtkWidget *scroll_r, *clist_r, *ok_bt, *label, *label2, *label1, *main_hbnbox;
+ gchar temp[150];
+ guint i;
+
+ switch(ri->reversed_ip_and_port)
+ {
+ /* in case we haven't found any reversed ssrc */
+ /* XXX in this case we could look for the inversed IP only */
+ case 0: {
+ ri->ssrc_reversed = 0;
+ ri->search_ssrc = FALSE;
+ add_rtp_notebook(ri);
+ return;
+ }
+ /* in case we found exactly one matching ssrc for reversed connection */
+ case 1: {
+ ri->ssrc_reversed = ri->ssrc_tmp[0];
+ ri->search_ssrc = FALSE;
+ add_rtp_notebook(ri);
+ return;
+ }
+ /* there is more then one matching ssrc, so we have to choose between them */
+ default: {
+ ri->search_ssrc = FALSE;
+ /* let's draw the window */
+ label = gtk_label_new("Found more SSRC values for the reversed\n"
+ "connection with following parameters:\n");
+ g_snprintf(temp, 149, "Source %s port %u Destination %s port %u",
+ ri->destination, ri->dstport, ri->source, ri->srcport);
+ label2 = gtk_label_new(temp);
+ gtk_box_pack_start(GTK_BOX(main_vb), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(main_vb), label2, FALSE, FALSE, 0);
+ scroll_r = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_r),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ clist_r = gtk_clist_new(1);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
+ gtk_container_add(GTK_CONTAINER(scroll_r), clist_r);
+ gtk_box_pack_start(GTK_BOX(main_vb), scroll_r, TRUE, TRUE, 0);
+ label1 = gtk_label_new("Select one value and click apply");
+ gtk_box_pack_start(GTK_BOX(main_vb), label1, FALSE, FALSE, 0);
+
+ main_hbnbox = gtk_hbutton_box_new();
+ gtk_box_pack_start(GTK_BOX(main_vb), main_hbnbox, FALSE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(main_hbnbox), 10);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(main_hbnbox),
+ GTK_BUTTONBOX_SPREAD);
+ gtk_widget_show(main_hbnbox);
+
+ ok_bt = gtk_button_new_with_label("Apply");
+ gtk_container_add(GTK_CONTAINER(main_hbnbox), ok_bt);
+ gtk_signal_connect(GTK_OBJECT(clist_r), "select_row",
+ GTK_SIGNAL_FUNC(get_selected_ssrc), ri);
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(apply_selected_ssrc), ri);
+
+ /* add all the ssrc values in the clist */
+ /* XXX I'm sure the tmp variable could be avoided here
+ * i tried to assign guint32 from ri->ssrc_tmp somehow to gchar **text
+ * but gave up. So if you can do this, just go ahead */
+ for (i=0; i < ri->reversed_ip_and_port; i++) {
+ gchar *text[0];
+ gchar tmp[20];
+ g_snprintf(tmp, 20, "%u", ri->ssrc_tmp[i]);
+ text[0] = (gchar *)&tmp;
+ gtk_clist_append(GTK_CLIST(clist_r), text);
+ }
+
+ gtk_clist_select_row(GTK_CLIST(clist_r), 0, 0);
+
+ gtk_widget_show(label);
+ gtk_widget_show(label1);
+ gtk_widget_show(label2);
+ gtk_widget_show(ok_bt);
+ gtk_widget_show(clist_r);
+ gtk_widget_show(scroll_r);
+ }
+ }
+}
+
+/* when the user clicks the RTP dialog button */
+void rtp_analyse_cb(GtkWidget *w _U_, gpointer data _U_)
+{
+ info_stat *rs;
+ gchar filter_text[]="rtp";
+ dfilter_t *sfcode;
+ capture_file *cf;
+ epan_dissect_t *edt;
+ gint err;
+ gboolean frame_matched;
+ frame_data *fdata;
+
+ /* There's already a "Display Options" dialog box; reactivate it. */
+ if (rtp_w != NULL) {
+ reactivate_window(rtp_w);
+ return;
+ }
+
+ /* Try to compile the filter. */
+ if (!dfilter_compile(filter_text, &sfcode)) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
+ return;
+ }
+ /* we load the current file into cf variable */
+ cf = &cfile;
+ fdata = cf->current_frame;
+
+ /* we are on the selected frame now */
+ if (fdata == NULL)
+ return; /* if we exit here it's an error */
+
+ /* XXX instead of looking for RTP protocol like this, we could do the process_node() staff */
+ /* dissect the current frame */
+ wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err);
+ edt = epan_dissect_new(TRUE, FALSE);
+ epan_dissect_prime_dfilter(edt, sfcode);
+ epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+
+ /* if it is not an rtp frame, exit */
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+ if (frame_matched != 1) {
+ epan_dissect_free(edt);
+ simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a RTP packet!");
+ return;
+ }
+
+ /* in rs we put all the info */
+ rs=g_malloc(sizeof(info_stat));
+
+ /* ok, it is a RTP frame, so let's get the ip and port values */
+ rs->srcport = edt->pi.srcport;
+ rs->dstport = edt->pi.destport;
+ strncpy(rs->source, ip_to_str(edt->pi.src.data), 16);
+ strncpy(rs->destination, ip_to_str(edt->pi.dst.data), 16);
+
+ /* now we need the SSRC value of the current frame */
+ rs->ssrc_forward = process_tree(edt->tree);
+ if (rs->ssrc_forward == 0) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "SSRC value couldn't be found!");
+ return;
+ }
+
+ /* now we have all the information about the forwarding connection
+ * we need to go through all the packets and search for reversed connection
+ */
+ rs->search_ssrc = TRUE;
+ rs->ssrc_reversed = 0;
+ rs->reversed_ip = 0;
+ rs->reversed_ip_and_port = 0;
+ rs->ssrc_tmp = NULL;
+
+/* XXX compiler warning:passing arg 5 of `register_tap_listener' from incompatible pointer type */
+ if(register_tap_listener("rtp", rs, NULL, rtp_reset, rtp_packet, rtp_draw)){
+ printf("ethereal: rtp_init() failed to attach the tap.\n");
+ /* XXX is this enough or do I have to free anything else? */
+ g_free(rs);
+ exit(1);
+ }
+
+ /* let's draw the window */
+ rtp_w = dlg_window_new("Ethereal: RTP Analyse");
+ gtk_window_set_position (GTK_WINDOW (rtp_w), GTK_WIN_POS_CENTER);
+ gtk_signal_connect(GTK_OBJECT(rtp_w), "destroy",
+ GTK_SIGNAL_FUNC(rtp_destroy_cb), rs);
+
+ /* Container for each row of widgets */
+ main_vb = gtk_vbox_new(FALSE, 3);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
+ gtk_widget_show(main_vb);
+
+ /* file names for storing sound data */
+ tmpnam(f_tempname);
+ tmpnam(r_tempname);
+ rs->f_fp = NULL;
+ rs->r_fp = NULL;
+
+ redissect_packets(cf);
+
+ /* so how many reversed connection we have ? */
+ get_reversed_ssrc(rs);
+
+ /* and finally display this window */
+ gtk_widget_show(rtp_w);
+}
+
+static void
+rtp_analyse_init(char *dummy _U_)
+{
+ rtp_analyse_cb(NULL, NULL);
+}
+
+/* XXX compiler warning:passing arg 2 of `register_ethereal_tap' from incompatible pointer type */
+void
+register_tap_listener_gtkrtp(void)
+{
+ register_ethereal_tap("rtp", rtp_analyse_init, NULL, NULL);
+}
+
+
+/* here we save it into a file that user specified */
+/* XXX what about endians here? could go something wrong? */
+static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ void *data)
+{
+ info_stat *rs=(info_stat *)data;
+ int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;
+ gint16 f_pd;
+ gint16 r_pd;
+ gchar pd[1];
+ guint32 f_write_silence = 0;
+ guint32 r_write_silence = 0;
+ progdlg_t *progbar;
+ guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;
+ gboolean stop_flag = FALSE;
+
+ forw_fd = open(f_tempname, O_RDONLY | 0);
+ if (forw_fd < 0)
+ return FALSE;
+ rev_fd = open(r_tempname, O_RDONLY | 0);
+ if (rev_fd < 0) {
+ close(forw_fd);
+ return FALSE;
+ }
+
+ /* open file for saving */
+ to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | 0, 0644);
+ if (to_fd < 0) {
+ close(forw_fd);
+ close(rev_fd);
+ return FALSE;
+ }
+
+ progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);
+
+ /* First we write the .au header. XXX Hope this is endian independant */
+ /* the magic word 0x2e736e64 == .snd */
+ *pd = (unsigned char)0x2e; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x73; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x6e; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x64; write(to_fd, pd, 1);
+ /* header offset == 24 bytes */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x18; write(to_fd, pd, 1);
+ /* total length, it is permited to set this to 0xffffffff */
+ *pd = (unsigned char)0xff; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ /* encoding format == 8 bit ulaw */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x01; write(to_fd, pd, 1);
+ /* sample rate == 8000 Hz */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x1f; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x40; write(to_fd, pd, 1);
+ /* channels == 1 */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x01; write(to_fd, pd, 1);
+
+ switch (channels) {
+ /* only forward direction */
+ case 1: {
+ progbar_count = rs->f_count;
+ progbar_quantum = rs->f_count/100;
+ while ((fread = read(forw_fd, &f_pd, 2)) > 0) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ *pd = (unsigned char)linear2ulaw(f_pd);
+ fwritten = write(to_fd, pd, 1);
+ if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ /* only reversed direction */
+ case 2: {
+ progbar_count = rs->r_count;
+ progbar_quantum = rs->r_count/100;
+ while ((rread = read(rev_fd, &r_pd, 2)) > 0) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ *pd = (unsigned char)linear2ulaw(r_pd);
+ rwritten = write(to_fd, pd, 1);
+ if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ /* both directions */
+ default: {
+ (rs->f_count > rs->r_count) ? (progbar_count = rs->f_count) :
+ (progbar_count = rs->r_count);
+ progbar_quantum = progbar_count/100;
+ /* since conversation in one way can start later than in the other one,
+ * we have to write some silence information for one channel */
+ if (rs->f_start_time > rs->r_start_time) {
+ f_write_silence = (rs->f_start_time-rs->r_start_time)*8000;
+ }
+ else if (rs->f_start_time < rs->r_start_time) {
+ r_write_silence = (rs->r_start_time-rs->f_start_time)*8000;
+ }
+ for(;;) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ if(f_write_silence > 0) {
+ rread = read(rev_fd, &r_pd, 2);
+ f_pd = 0;
+ fread = 1;
+ f_write_silence--;
+ }
+ else if(r_write_silence > 0) {
+ fread = read(forw_fd, &f_pd, 2);
+ r_pd = 0;
+ rread = 1;
+ r_write_silence--;
+ }
+ else {
+ fread = read(forw_fd, &f_pd, 2);
+ rread = read(rev_fd, &r_pd, 2);
+ }
+ if ((rread == 0) && (fread == 0))
+ break;
+ *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );
+ rwritten = write(to_fd, pd, 1);
+ if ((rwritten < 0) || (rread < 0) || (fread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ }
+ }
+ destroy_progress_dlg(progbar);
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ return TRUE;
+
+}
+
diff --git a/gtk/tap_rtp.h b/gtk/tap_rtp.h
new file mode 100644
index 0000000000..cb4d668394
--- /dev/null
+++ b/gtk/tap_rtp.h
@@ -0,0 +1,27 @@
+/*
+ * tap_rtp.h
+ *
+ * Declaration for rtp analysing tool
+ *
+ * Copyright 2003, Iskratel, Ltd, Kranj
+ * By Miha Jemec <m.jemec@iskratel.si>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+void rtp_analyse_cb(GtkWidget *, gpointer);
diff --git a/packet-rtp.c b/packet-rtp.c
index b95fd6258d..8439e0854c 100644
--- a/packet-rtp.c
+++ b/packet-rtp.c
@@ -6,7 +6,7 @@
* Copyright 2000, Philips Electronics N.V.
* Written by Andreas Sikkema <andreas.sikkema@philips.com>
*
- * $Id: packet-rtp.c,v 1.37 2003/02/28 22:03:08 guy Exp $
+ * $Id: packet-rtp.c,v 1.38 2003/03/06 20:35:09 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -63,6 +63,9 @@
#include "packet-rtp.h"
#include <epan/conversation.h>
+#include "tap.h"
+
+static int rtp_tap = -1;
/* RTP header fields */
static int proto_rtp = -1;
@@ -349,6 +352,8 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
guint32 sync_src;
guint32 csrc_item;
+ static struct _rtp_info rtp_info;
+
/* Get the fields in the first octet */
octet = tvb_get_guint8( tvb, offset );
version = RTP_VERSION( octet );
@@ -390,6 +395,16 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
timestamp = tvb_get_ntohl( tvb, offset + 4 );
sync_src = tvb_get_ntohl( tvb, offset + 8 );
+ /* fill in the rtp_info structure */
+ rtp_info.info_padding_set = padding_set;
+ rtp_info.info_padding_count = 0;
+ rtp_info.info_marker_set = marker_set;
+ rtp_info.info_payload_type = payload_type;
+ rtp_info.info_seq_num = seq_num;
+ rtp_info.info_timestamp = timestamp;
+ rtp_info.info_sync_src = sync_src;
+ rtp_info.info_data_len = tvb_reported_length_remaining( tvb, offset );
+
if ( check_col( pinfo->cinfo, COL_PROTOCOL ) ) {
col_set_str( pinfo->cinfo, COL_PROTOCOL, "RTP" );
}
@@ -404,7 +419,6 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
timestamp,
marker_set ? ", Mark" : "");
}
-
if ( tree ) {
ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, -1, FALSE );
rtp_tree = proto_item_add_subtree( ti, ett_rtp );
@@ -555,6 +569,7 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
payload_type );
}
}
+ tap_queue_packet(rtp_tap, pinfo, &rtp_info);
}
void
@@ -770,6 +785,7 @@ proto_register_rtp(void)
proto_register_subtree_array(ett, array_length(ett));
register_dissector("rtp", dissect_rtp, proto_rtp);
+ rtp_tap = register_tap("rtp");
#if 0
register_init_routine( &rtp_init );
diff --git a/packet-rtp.h b/packet-rtp.h
index 4eecb3d26f..bd9dd96772 100644
--- a/packet-rtp.h
+++ b/packet-rtp.h
@@ -3,7 +3,7 @@
* Routines for RTP dissection
* RTP = Real time Transport Protocol
*
- * $Id: packet-rtp.h,v 1.7 2002/08/28 21:00:30 jmayer Exp $
+ * $Id: packet-rtp.h,v 1.8 2003/03/06 20:35:09 sahlberg Exp $
*
* Copyright 2000, Philips Electronics N.V.
* Written by Andreas Sikkema <andreas.sikkema@philips.com>
@@ -27,5 +27,16 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+struct _rtp_info {
+ gboolean info_padding_set;
+ gboolean info_marker_set;
+ unsigned int info_payload_type;
+ unsigned int info_padding_count;
+ guint16 info_seq_num;
+ guint32 info_timestamp;
+ guint32 info_sync_src;
+ guint info_data_len;
+};
+
void rtp_add_address ( packet_info *pinfo, const unsigned char* ip_addr, int prt );
void proto_register_rtp( void );