/****************************************************************************
** File: rtcp.c
**
** Author: Mike Borella
**
** Comments: Dump RTCP header information.
**
** $Id: rtcp.c,v 1.3 2001/11/02 23:59:29 mborella Exp $
**
** 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 Library 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.
**
*****************************************************************************/
#include "rtcp.h"
/*
* Static part of RTCP header
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P| RC | PT | length | header
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
typedef struct rtcp_header
{
#if defined(WORDS_BIGENDIAN)
u_int8_t version:2,
padding:1,
rc_sc:5;
#else
u_int8_t rc_sc:5,
padding:1,
version:2;
#endif
u_int8_t packet_type;
u_int16_t length;
} rtcp_header_t;
/*
* RTCP SR packet type sender info portion
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of sender |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* | NTP timestamp, most significant word | sender
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ info
* | NTP timestamp, least significant word |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | RTP timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | sender's packet count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | sender's octet count |
* +---------------------------------------------------------------+
*/
typedef struct rtcp_sr_senderinfo
{
u_int32_t sender_ssrc;
u_int32_t timestamp_MSW;
u_int32_t timestamp_LSW;
u_int32_t timestamp_RTP;
u_int32_t sender_pkt_cnt;
u_int32_t sender_octet_cnt;
} rtcp_sr_senderinfo_t;
/*
* RTCP SR report block
*
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* | SSRC_1 (SSRC of first source) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | fraction lost | cumulative number of packets lost |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | extended highest sequence number received |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | interarrival jitter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | last SR (LSR) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | delay since last SR (DLSR) |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*/
typedef struct rtcp_sr_reportblock
{
u_int32_t ssrc;
u_int8_t frac_lost;
u_int8_t packets_lost[3];
u_int32_t ext_seqno_recvd;
u_int32_t jitter;
u_int32_t lsr;
u_int32_t delay_since_lsr;
} rtcp_sr_reportblock_t;
/*
* RTCP packet type definitions
*/
#define RTCP_PACKETTYPE_SR 200
#define RTCP_PACKETTYPE_RR 201
#define RTCP_PACKETTYPE_SDES 202
#define RTCP_PACKETTYPE_BYE 203
#define RTCP_PACKETTYPE_APP 204
/*
* RTCP payload type map
*/
strmap_t rtcp_packettype_map[] =
{
{ RTCP_PACKETTYPE_SR, "sender report" },
{ RTCP_PACKETTYPE_RR, "receiver report" },
{ RTCP_PACKETTYPE_SDES, "source description" },
{ RTCP_PACKETTYPE_BYE, "bye" },
{ RTCP_PACKETTYPE_APP, "application" },
{ 0, ""}
};
extern struct arg_t * my_args;
/*----------------------------------------------------------------------------
**
** dump_rtcp_sr()
**
** Parse RTCP sender report fields
**
**----------------------------------------------------------------------------
*/
void dump_rtcp_sr(packet_t * pkt, int count)
{
rtcp_sr_senderinfo_t senderinfo;
rtcp_sr_reportblock_t reportblock;
int reports_seen;
/* Get the sender info */
if (get_packet_bytes((u_int8_t *) &senderinfo, pkt, sizeof(senderinfo)) == 0)
return;
/* Conversions */
senderinfo.sender_ssrc = ntohl(senderinfo.sender_ssrc);
senderinfo.timestamp_MSW = ntohl(senderinfo.timestamp_MSW);
senderinfo.timestamp_LSW = ntohl(senderinfo.timestamp_LSW);
senderinfo.timestamp_RTP = ntohl(senderinfo.timestamp_RTP);
senderinfo.sender_pkt_cnt = ntohl(senderinfo.sender_pkt_cnt);
senderinfo.sender_octet_cnt = ntohl(senderinfo.sender_octet_cnt);
/* Display */
if (my_args->m)
{
display_minimal((u_int8_t *) &senderinfo.sender_ssrc, 4, DISP_DEC);
display_minimal_string(" ");
}
else
{
display("Sender SSRC", (u_int8_t *) &senderinfo.sender_ssrc, 4,
DISP_DEC);
display("Timestamp MSW", (u_int8_t *) &senderinfo.timestamp_MSW, 4,
DISP_DEC);
display("Timestamp LSW", (u_int8_t *) &senderinfo.timestamp_LSW, 4,
DISP_DEC);
display("RTP timestamp", (u_int8_t *) &senderinfo.timestamp_RTP, 4,
DISP_DEC);
display("Sender packet count", (u_int8_t *) &senderinfo.sender_pkt_cnt,
4, DISP_DEC);
display("Sender octet count", (u_int8_t *) &senderinfo.sender_octet_cnt,
4, DISP_DEC);
}
/* Loop over report blocks */
reports_seen = 0;
while(reports_seen < count)
{
/* Get the report block */
if (get_packet_bytes((u_int8_t *) &reportblock, pkt,
sizeof(reportblock)) == 0)
break;
/* Conversions */
reportblock.ssrc = ntohl(reportblock.ssrc);
reportblock.ext_seqno_recvd = ntohl(reportblock.ext_seqno_recvd);
reportblock.jitter = ntohl(reportblock.jitter);
reportblock.lsr = ntohl(reportblock.lsr);
reportblock.delay_since_lsr = ntohl(reportblock.delay_since_lsr);
/* Display */
if (my_args->m)
{
display_minimal((u_int8_t *) &reportblock.ssrc, 4, DISP_DEC);
display_minimal_string(" ");
}
else
{
display("SSRC", (u_int8_t *) &reportblock.ssrc, 4, DISP_DEC);
display(" Fraction lost", (u_int8_t *) &reportblock.frac_lost,
1, DISP_DEC);
display(" Packets lost",
(u_int8_t *) &reportblock.packets_lost, 3, DISP_DEC);
display(" Highest seqno received",
(u_int8_t *) &reportblock.ext_seqno_recvd, 4,
DISP_DEC);
display(" Jitter", (u_int8_t *) &reportblock.jitter, 4,
DISP_DEC);
display(" Last SR", (u_int8_t *) &reportblock.lsr, 4,
DISP_DEC);
display(" Delay since last SR",
(u_int8_t *) &reportblock.delay_since_lsr, 4,
DISP_DEC);
}
reports_seen ++;
}
}
/*----------------------------------------------------------------------------
**
** dump_rtcp_rr()
**
** Parse RTCP receiver report fields
**
**----------------------------------------------------------------------------
*/
void dump_rtcp_rr(packet_t * pkt, int count)
{
rtcp_sr_reportblock_t reportblock;
int reports_seen;
u_int32_t ssrc;
/* Get the SSRC */
if (get_packet_bytes((u_int8_t *) &ssrc, pkt, 4) == 0)
return;
/* Conversions */
ssrc = ntohl(ssrc);
/* Display */
if (my_args->m)
{
display_minimal((u_int8_t *) &ssrc, 4, DISP_DEC);
display_minimal_string(" ");
}
else
display("SSRC", (u_int8_t *) &ssrc, 4, DISP_DEC);
/* Loop over report blocks */
reports_seen = 0;
while(reports_seen < count)
{
/* Get the report block */
if (get_packet_bytes((u_int8_t *) &reportblock, pkt,
sizeof(reportblock)) == 0)
break;
/* Conversions */
reportblock.ssrc = ntohl(reportblock.ssrc);
reportblock.ext_seqno_recvd = ntohl(reportblock.ext_seqno_recvd);
reportblock.jitter = ntohl(reportblock.jitter);
reportblock.lsr = ntohl(reportblock.lsr);
reportblock.delay_since_lsr = ntohl(reportblock.delay_since_lsr);
/* Display */
if (my_args->m)
{
display_minimal((u_int8_t *) &reportblock.ssrc, 4, DISP_DEC);
display_minimal_string(" ");
}
else
{
display("SSRC", (u_int8_t *) &reportblock.ssrc, 4, DISP_DEC);
display(" Fraction lost", (u_int8_t *) &reportblock.frac_lost,
1, DISP_DEC);
display(" Packets lost",
(u_int8_t *) &reportblock.packets_lost, 3, DISP_DEC);
display(" Highest seqno received",
(u_int8_t *) &reportblock.ext_seqno_recvd, 4,
DISP_DEC);
display(" Jitter", (u_int8_t *) &reportblock.jitter, 4,
DISP_DEC);
display(" Last SR", (u_int8_t *) &reportblock.lsr, 4,
DISP_DEC);
display(" Delay since last SR",
(u_int8_t *) &reportblock.delay_since_lsr, 4,
DISP_DEC);
}
reports_seen ++;
}
}
/*----------------------------------------------------------------------------
**
** dump_rtcp_sdes()
**
** Parse RTCP source description fields
**
**----------------------------------------------------------------------------
*/
void dump_rtcp_sdes(packet_t * pkt, int count)
{
u_int32_t ssrc;
u_int8_t type;
u_int8_t length;
u_int8_t * string;
int chunks_read;
int pad_len;
chunks_read = 0;
while(chunks_read < count)
{
/* Get the ssrc, type and length */
if (get_packet_bytes((u_int8_t *) &ssrc, pkt, 4) == 0)
break;
/* Conversions */
ssrc = ntohl(ssrc);
/* Display */
if (my_args->m)
{
display_minimal((u_int8_t *) &ssrc, 4, DISP_DEC);
display_minimal_string(" ");
}
else
display("SSRC/CSRC", (u_int8_t *) &ssrc, 4, DISP_DEC);
/* Loop through items */
while (1)
{
u_int8_t byte;
if (get_packet_bytes((u_int8_t *) &type, pkt, 1) == 0)
break;
if (get_packet_bytes((u_int8_t *) &length, pkt, 1) == 0)
break;
/* Allocate memory for the string then get it */
string = my_malloc(length+1);
if (get_packet_bytes(string, pkt, length) == 0)
break;
string[length] = '\0';
/* Display */
if (my_args->m)
{
display_minimal_string(string);
display_minimal_string(" ");
}
else
{
display(" Type", (u_int8_t *) &type, 1, DISP_DEC);
display(" Length", (u_int8_t *) &length, 1, DISP_DEC);
display_string(" SDES", string);
}
/* Free string memory */
my_free(string);
/* Look for a null terminator */
if (look_packet_bytes((u_int8_t *) &byte, pkt, 1) == 0)
break;
if (byte == 0)
break;
}
/* Figure out the pad and skip by it */
pad_len = 4 - (length+2) % 4;
if (skip_packet_bytes(pkt, pad_len) == 0)
break;
chunks_read ++;
}
}
/*----------------------------------------------------------------------------
**
** dump_rtcp()
**
** Parse RTCP packet and dump fields
**
**----------------------------------------------------------------------------
*/
void dump_rtcp(packet_t * pkt)
{
rtcp_header_t rtcp;
u_int8_t packet_type;
u_int8_t padding;
u_int8_t version;
u_int8_t count;
u_int16_t bytes_remaining;
/* Set the layer */
set_layer(LAYER_APPLICATION);
while(1)
{
/* Get the fixed RTCP header */
if (get_packet_bytes((u_int8_t *) &rtcp, pkt, sizeof(rtcp)) == 0)
break;
/* Conversions */
packet_type = rtcp.packet_type;
padding = rtcp.padding;
version = rtcp.version;
count = rtcp.rc_sc;
rtcp.length = ntohs(rtcp.length);
/* Set the number of bytes remaining */
bytes_remaining = 4 * rtcp.length;
/* Display */
if (my_args->m)
{
display_minimal_string("| RTCPv");
display_minimal((u_int8_t *) &version, 1, DISP_DEC);
display_minimal_string(" ");
display_minimal_string(map2str(rtcp_packettype_map, packet_type));
display_minimal_string(" ");
}
else
{
display_header_banner("RTCP Header");
display("Version", (u_int8_t *) &version, 1, DISP_DEC);
display("Padding", (u_int8_t *) &padding, 1, DISP_DEC);
display("Report/source count", (u_int8_t *) &count, 1, DISP_DEC);
display_strmap("Packet type", packet_type, rtcp_packettype_map);
display("Length", (u_int8_t *) &rtcp.length, 2, DISP_DEC);
}
switch(packet_type)
{
case RTCP_PACKETTYPE_SR:
dump_rtcp_sr(pkt, count);
break;
case RTCP_PACKETTYPE_RR:
dump_rtcp_rr(pkt, count);
break;
case RTCP_PACKETTYPE_SDES:
dump_rtcp_sdes(pkt, count);
break;
default:
break;
}
}
/* Dump the hex buffer */
hexbuffer_flush();
}
syntax highlighted by Code2HTML, v. 0.9.1