Ethereal-dev: [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: Miha Jemec <miha.jemec@xxxxxxxxxxxxxx>
Date: Wed, 05 Mar 2003 16:18:46 +0100
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/ directoryg711.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 attachedBecause 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 ----
- Follow-Ups:
- Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- From: Jason House
- Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- From: Ronnie Sahlberg
- Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- From: Ronnie Sahlberg
- Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- Prev by Date: [Ethereal-dev] Firestorm Network Intrusion Detection support for Ethereal
- Next by Date: Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- Previous by thread: Re: [Ethereal-dev] Firestorm Network Intrusion Detection support for Ethereal
- Next by thread: Re: [Ethereal-dev] Ethereal addition for analysing RTP data
- Index(es):