Ethereal-dev: Re: [Ethereal-dev] Ethereal addition for analysing RTP data
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: "Ronnie Sahlberg" <ronnie_sahlberg@xxxxxxxxxxxxxx>
Date: Thu, 6 Mar 2003 05:13:46 +1100
Very very cool, This would be very nice to have in 0.9.10 I think you generated the diff in the reverse order. the diff looks like it wants to remove the tap from packet-rtp.c, that is no problem, patch is bright enough to detect this and do the right thing anyway. But there seems to be one patch missing, where is the _rtp_info struct defined? is it in a missing patch to packet-rtp.h ? As for your question in tap-rtp.c The tap listeners are called after each individual packet is dissected. The next packet will not be dissected until all previous *_packet() tap listeners have been called and have completed. In other words, the dissection of packets and calling of *_packet() is single threaded. This means that there will not be any corruption if *_packet() is not fast enough, however, since a slow(==takes long to finish) *_packet() function will prevent ethereal from dissecting the next packet it is good to try to make the *_packet() function as fast as possible. best regards ronnie sahlberg ----- Original Message ----- From: "Miha Jemec" Sent: Thursday, March 06, 2003 2:18 AM Subject: [Ethereal-dev] Ethereal addition for analysing RTP data > Hi! > > After quite some time here is the rewritten version of RTP analysing > tool. It uses now the tap system (I had to change the packet-rtp.c and > packet-rtp.h) and with the intention of being OS independent it doesn't > make possible to play the voice directly through the sound card but has > the possibility to save it in a file for later listening. How it works > is described in code itself (I tried to put many comments there). There > are still some open questions or problems (look for XXX). I was able to > test it only under Intel machine with Linux OS, so test on other OS > would be welcome. > > Attached files are: > > rtp.jpg - screenshot > tap_rtp.c - actual code, that goes into gtk/ directory > g711.c - routines for converting alaw or ulaw to linear, goes into gtk/ > as well > > I also modified some other files (ethereal 0.9.8): > > in gtk/menu.c one more line under "Tools": > > ITEM_FACTORY_ENTRY("/Tools/_RTP analysis...", NULL, rtp_analyse_cb, 0, > NULL, NULL), > > > in packet-rtp.h added following structure at the end: > > 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; > }; > > > in packet-rtp.c: diff is attached > > > Because I'm not very comfortable with automake , autoconf, ... I just > added some lines by hand to compile: > > In etereal_tap_register two more lines: > > { extern void register_tap_listener_gtkrtp (void); > register_tap_listener_gtkrtp ();} > > In gtk/Makefile in line am__objects_1 = > added tap_rtp.$(OBJEXT) > > > I would be glad to get any comments. > Regards, > Miha > > > ---------------------------------------------------------------------------- ---- > /* > * tap_rtp.c > * > * RTP analysing addition for ethereal > * > * Copyright 2003, Iskratel, Ltd, Kranj > * By Miha Jemec <m.jemec@xxxxxxxxxxx> > * > * Ethereal - Network traffic analyzer > * By Gerald Combs <gerald@xxxxxxxxxxxx> > * 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? > * > * - since I don't know exactly how the tap events are scheduled , is it possible that "next" > * matching rtp frame will corrupt the information in struct info_stat (is it possible > * that rtp_packet is not "fast" enough?). I tried with 166Mhz procesor and 30 Mb of captured > * file and worked fine > * > * - 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 "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 <gtk/gtk.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.c" > #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. %lu \n\n" > "Total RTP packets = %lu (expected %lu) Lost RTP packets = %ld" > " Sequence error = %lu", > 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. %lu \n\n" > "Total RTP packets = %lu (expected %lu) Lost RTP packets = %ld" > " Sequence error = %lu", > 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, "%lu", number); > g_snprintf(field[1], 20, "%lu", 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_, struct _rtp_info *pri) > { > info_stat *rs=prs; > 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 %lu to %s port %lu SSRC = %lu\n", > rs->source, rs->srcport, rs->destination, rs->dstport, rs->ssrc_forward); > g_snprintf(label_reverse, 149, > "Analysing connection from %s port %lu to %s port %lu SSRC = %lu\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 %lu Destination %s port %lu", > 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, "%lu", 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 */ > static 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); > } > > /* 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_cb, 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; > > } > > ---------------------------------------------------------------------------- ---- ---------------------------------------------------------------------------- ---- > /* > * 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 -r -2 -c ethereal-0.9.8-test/packet-rtp.c ethereal-0.9.8/packet-rtp.c > > *** ethereal-0.9.8-test/packet-rtp.c Wed Mar 5 16:08:19 2003 > --- ethereal-0.9.8/packet-rtp.c Thu Aug 29 02:40:00 2002 > *************** > *** 64,70 **** > #include "packet-rtp.h" > #include <epan/conversation.h> > - #include "tap.h" > - > - static int rtp_tap = -1; > > /* RTP header fields */ > --- 64,67 ---- > *************** > *** 343,348 **** > guint32 csrc_item; > > - static struct _rtp_info rtp_info; > - > /* Get the fields in the first octet */ > octet = tvb_get_guint8( tvb, offset ); > --- 340,343 ---- > *************** > *** 386,399 **** > 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" ); > --- 381,384 ---- > *************** > *** 410,413 **** > --- 395,399 ---- > marker_set ? ", Mark" : ""); > } > + > if ( tree ) { > ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, -1, FALSE ); > *************** > *** 560,564 **** > } > } > - tap_queue_packet(rtp_tap, pinfo, &rtp_info); > } > > --- 546,549 ---- > *************** > *** 776,780 **** > > register_dissector("rtp", dissect_rtp, proto_rtp); > - rtp_tap = register_tap("rtp"); > > #if 0 > --- 761,764 ---- >
- References:
- [Ethereal-dev] Ethereal addition for analysing RTP data
- From: Miha Jemec
- [Ethereal-dev] Ethereal addition for analysing RTP data
- Prev by Date: Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- Next by Date: Re: [Ethereal-dev] Firestorm Network Intrusion Detection support for Ethereal
- Previous by thread: Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- Next by thread: Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- Index(es):