FreeCalypso > hg > rtp-debug-utils
changeset 10:e686bc92c7d8
revamp for new subdir structure and configure script
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 15 May 2024 01:44:46 +0000 |
parents | c00510e1ae8b |
children | 8b047c9bfe5f |
files | .hgignore Makefile configure net-traffic/Makefile net-traffic/rtp-stream-gen.c net-traffic/udp-test-sink.c pcap-study/Makefile pcap-study/rtp-cont-check.c pcap-study/rtp-g711-extr.c pcap-study/rtp-gsmfr-dump.c pcap-study/rtp-gsmfr-extr.c pcap-study/rtp-jitter-view.c pcap-study/rtp-stream-dump.c pcap-study/rtp-tfo-trace.c rtp-cont-check.c rtp-g711-extr.c rtp-gsmfr-dump.c rtp-gsmfr-extr.c rtp-jitter-view.c rtp-stream-dump.c rtp-stream-gen.c rtp-tfo-trace.c udp-test-sink.c |
diffstat | 23 files changed, 2120 insertions(+), 2020 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Sun Mar 10 02:27:37 2024 +0000 +++ b/.hgignore Wed May 15 01:44:46 2024 +0000 @@ -1,13 +1,15 @@ syntax: regexp \.[oa]$ +^config\.defs$ -^rtp-cont-check$ -^rtp-g711-extr$ -^rtp-gsmfr-dump$ -^rtp-gsmfr-extr$ -^rtp-jitter-view$ -^rtp-stream-dump$ -^rtp-stream-gen$ -^rtp-tfo-trace$ -^udp-test-sink$ +^net-traffic/rtp-stream-gen$ +^net-traffic/udp-test-sink$ + +^pcap-study/rtp-cont-check$ +^pcap-study/rtp-g711-extr$ +^pcap-study/rtp-gsmfr-dump$ +^pcap-study/rtp-gsmfr-extr$ +^pcap-study/rtp-jitter-view$ +^pcap-study/rtp-stream-dump$ +^pcap-study/rtp-tfo-trace$
--- a/Makefile Sun Mar 10 02:27:37 2024 +0000 +++ b/Makefile Wed May 15 01:44:46 2024 +0000 @@ -1,42 +1,20 @@ -CC= gcc -CFLAGS= -O2 -PROGS= rtp-cont-check rtp-g711-extr rtp-gsmfr-dump rtp-gsmfr-extr \ - rtp-jitter-view rtp-stream-dump rtp-stream-gen rtp-tfo-trace \ - udp-test-sink -INSTBIN=/opt/freecalypso/bin - -all: ${PROGS} +SUBDIR= net-traffic pcap-study -rtp-cont-check: rtp-cont-check.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap - -rtp-g711-extr: rtp-g711-extr.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap +all: ${SUBDIR} -rtp-gsmfr-dump: rtp-gsmfr-dump.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap -lgsmefr -lgsm - -rtp-gsmfr-extr: rtp-gsmfr-extr.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap +${SUBDIR}: FRC config.defs + cd $@; ${MAKE} ${MFLAGS} -rtp-jitter-view: rtp-jitter-view.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap - -rtp-stream-dump: rtp-stream-dump.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap - -rtp-stream-gen: rtp-stream-gen.c - ${CC} ${CFLAGS} -o $@ $@.c +config.defs: + @echo 'You must run ./configure before make' + @false -rtp-tfo-trace: rtp-tfo-trace.c - ${CC} ${CFLAGS} -o $@ $@.c -lpcap - -udp-test-sink: udp-test-sink.c - ${CC} ${CFLAGS} -o $@ $@.c +install: FRC + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} \ + DESTDIR=${DESTDIR} install); done -install: - mkdir -p ${INSTBIN} - install -c ${PROGS} ${INSTBIN} +clean: FRC + rm -f a.out core errs + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} clean); done -clean: - rm -f *.o *.out ${PROGS} +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configure Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,68 @@ +#!/bin/sh +# This configure script is custom and hand-coded; +# it is NOT a product of GNU Autoconf or any other such tools! + +set -e + +if [ ! -f configure ] +then + echo "This script needs to be run from the top of the source tree" 1>&2 + exit 1 +fi + +# defaults that can be overridden +CC=gcc +CFLAGS=-O2 +prefix=/usr/local +exec_prefix= +bindir= + +while [ $# != 0 ] +do + case "$1" in + --prefix=*) + prefix=`echo $1 | cut -c 10-` + ;; + --exec-prefix=*) + exec_prefix=`echo $1 | cut -c 15-` + ;; + --bindir=*) + bindir=`echo $1 | cut -c 10-` + ;; + CC=*) + CC=`echo $1 | cut -c 4-` + ;; + CFLAGS=*) + CFLAGS=`echo $1 | cut -c 8-` + ;; + *) + echo "error: non-understood option $1" 1>&2 + exit 1; + ;; + esac + shift +done + +# inheritance rules for install directories + +if [ -z "$exec_prefix" ] +then + exec_prefix="$prefix" +fi +if [ -z "$bindir" ] +then + bindir="$exec_prefix/bin" +fi + +# report the final configuration + +echo "C code will be compiled with:" +echo " CC=$CC" +echo " CFLAGS=$CFLAGS" +echo "Installation directory:" +echo " bindir=$bindir" + +# emit the Makefile include fragment +echo "CC=$CC" > config.defs +echo "CFLAGS=$CFLAGS" >> config.defs +echo "bindir=$bindir" >> config.defs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net-traffic/Makefile Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,18 @@ +PROGS= rtp-stream-gen udp-test-sink + +include ../config.defs + +all: ${PROGS} + +rtp-stream-gen: rtp-stream-gen.c + ${CC} ${CFLAGS} -o $@ $@.c + +udp-test-sink: udp-test-sink.c + ${CC} ${CFLAGS} -o $@ $@.c + +install: + mkdir -p ${DESTDIR}${bindir} + install -c ${PROGS} ${DESTDIR}${bindir} + +clean: + rm -f *.o *.out ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net-traffic/rtp-stream-gen.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,162 @@ +/* + * This program generates a dummy RTP stream, sending RTP packets with + * a dummy payload to the specified destination IP:port, paced in time + * every 20 ms. The purpose is to test the behaviour of affordably-available + * Internet connections when presented with such traffic: the intent is + * to capture this packet stream on the receiving end with tcpdump and then + * analyze the pcap for problem signs of packet loss, jitter and reordering. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#define RTP_PACKET_HDR_SIZE 12 +#define RTP_MAX_PAYLOAD 160 +#define GSM_FR_BYTES 33 + +struct rtp_packet { + uint8_t v_p_x_cc; + uint8_t m_pt; + uint16_t seq; + uint32_t tstamp; + uint32_t ssrc; + uint8_t payload[RTP_MAX_PAYLOAD]; +}; + +static const uint8_t gsmfr_silence_frame[GSM_FR_BYTES] = { + 0xDA, 0xA7, 0xAA, 0xA5, 0x1A, + 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, + 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, + 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, + 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, +}; + +static struct sockaddr_in sin_src, sin_dest; +static struct rtp_packet rtp_pkt; +static unsigned rtp_pkt_len, req_packet_count; +static int udp_fd; + +static void +parse_ip_port(arg, sin) + char *arg; + struct sockaddr_in *sin; +{ + char *cp; + int rc; + + cp = index(arg, ':'); + if (!cp) { + fprintf(stderr, "error: missing ':' in IP:port argument\n"); + exit(1); + } + *cp++ = '\0'; + sin->sin_family = AF_INET; + rc = inet_aton(arg, &sin->sin_addr); + if (!rc) { + fprintf(stderr, "error: invalid IP address argument\n"); + exit(1); + } + sin->sin_port = htons(atoi(cp)); +} + +static void +prepare_rtp_payload(type_arg) + char *type_arg; +{ + unsigned pl_len; + + if (!strcmp(type_arg, "pcmu")) { + rtp_pkt.m_pt = 0; + memset(rtp_pkt.payload, 0xFF, RTP_MAX_PAYLOAD); + pl_len = RTP_MAX_PAYLOAD; + } else if (!strcmp(type_arg, "pcma")) { + rtp_pkt.m_pt = 8; + memset(rtp_pkt.payload, 0xD5, RTP_MAX_PAYLOAD); + pl_len = RTP_MAX_PAYLOAD; + } else if (!strcmp(type_arg, "gsm")) { + rtp_pkt.m_pt = 3; + memcpy(rtp_pkt.payload, gsmfr_silence_frame, GSM_FR_BYTES); + pl_len = GSM_FR_BYTES; + } else { + fprintf(stderr, "error: invalid PL type argument \"%s\"\n", + type_arg); + exit(1); + } + rtp_pkt_len = RTP_PACKET_HDR_SIZE + pl_len; +} + +static void +assign_rtpout_ssrc() +{ + struct timeval curtime; + + gettimeofday(&curtime, 0); + rtp_pkt.ssrc = curtime.tv_sec ^ curtime.tv_usec ^ getpid(); +} + +static void +prepare_udp_socket() +{ + int rc; + + udp_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (udp_fd < 0) { + perror("socket(AF_INET, SOCK_DGRAM, 0)"); + exit(1); + } + rc = bind(udp_fd, (struct sockaddr *) &sin_src, sizeof sin_src); + if (rc < 0) { + perror("bind"); + exit(1); + } + rc = connect(udp_fd, (struct sockaddr *) &sin_dest, sizeof sin_dest); + if (rc < 0) { + perror("connect"); + exit(1); + } +} + +static void +send_out_packets() +{ + unsigned n, seq, ts; + + seq = 0; + ts = 0; + for (n = 0; n < req_packet_count; n++) { + rtp_pkt.seq = htons(seq); + rtp_pkt.tstamp = htonl(ts); + send(udp_fd, &rtp_pkt, rtp_pkt_len, 0); + seq++; + ts += 160; + usleep(20000); + } +} + +main(argc, argv) + char **argv; +{ + if (argc != 5) { + fprintf(stderr, "usage: %s src-IP:port dest-IP:port type num\n", + argv[0]); + exit(1); + } + parse_ip_port(argv[1], &sin_src); + parse_ip_port(argv[2], &sin_dest); + prepare_rtp_payload(argv[3]); + rtp_pkt.v_p_x_cc = 0x80; + assign_rtpout_ssrc(); + req_packet_count = atoi(argv[4]); + prepare_udp_socket(); + send_out_packets(); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net-traffic/udp-test-sink.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,96 @@ +/* + * This program is a simple sink for UDP: it binds to a UDP port and sinks + * (reads and discards) all packets that arrive at it. Upon receiving a + * burst or stream of packets followed by a prolonged pause, it prints + * the number of packets that were received. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +static void +parse_ip_port(arg, sin) + char *arg; + struct sockaddr_in *sin; +{ + char *cp; + int rc; + + cp = index(arg, ':'); + if (!cp) { + fprintf(stderr, "error: missing ':' in IP:port argument\n"); + exit(1); + } + *cp++ = '\0'; + sin->sin_family = AF_INET; + rc = inet_aton(arg, &sin->sin_addr); + if (!rc) { + fprintf(stderr, "error: invalid IP address argument\n"); + exit(1); + } + sin->sin_port = htons(atoi(cp)); +} + +main(argc, argv) + char **argv; +{ + struct sockaddr_in bindsin; + int udp_fd, rc; + unsigned idle_sec, rx_count; + fd_set fds; + struct timeval tv; + u_char dummybuf[256]; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "usage: bind-IP:port [idle-sec]\n", argv[0]); + exit(1); + } + parse_ip_port(argv[1], &bindsin); + if (argc >= 3) + idle_sec = atoi(argv[2]); + else + idle_sec = 0; + udp_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (udp_fd < 0) { + perror("socket(AF_INET, SOCK_DGRAM, 0)"); + exit(1); + } + rc = bind(udp_fd, (struct sockaddr *) &bindsin, sizeof bindsin); + if (rc < 0) { + perror("bind"); + exit(1); + } + for (rx_count = 0; ; ) { + FD_ZERO(&fds); + FD_SET(udp_fd, &fds); + if (rx_count && idle_sec) { + tv.tv_sec = idle_sec; + tv.tv_usec = 0; + rc = select(udp_fd+1, &fds, 0, 0, &tv); + } else + rc = select(udp_fd+1, &fds, 0, 0, 0); + if (rc < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (FD_ISSET(udp_fd, &fds)) { + recv(udp_fd, dummybuf, sizeof dummybuf, 0); + rx_count++; + } else { + printf("Received %u packet%s\n", rx_count, + rx_count != 1 ? "s" : ""); + rx_count = 0; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/Makefile Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,34 @@ +PROGS= rtp-cont-check rtp-g711-extr rtp-gsmfr-dump rtp-gsmfr-extr \ + rtp-jitter-view rtp-stream-dump rtp-tfo-trace + +include ../config.defs + +all: ${PROGS} + +rtp-cont-check: rtp-cont-check.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap + +rtp-g711-extr: rtp-g711-extr.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap + +rtp-gsmfr-dump: rtp-gsmfr-dump.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap -lgsmefr -lgsm + +rtp-gsmfr-extr: rtp-gsmfr-extr.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap + +rtp-jitter-view: rtp-jitter-view.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap + +rtp-stream-dump: rtp-stream-dump.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap + +rtp-tfo-trace: rtp-tfo-trace.c + ${CC} ${CFLAGS} -o $@ $@.c -lpcap + +install: + mkdir -p ${DESTDIR}${bindir} + install -c ${PROGS} ${DESTDIR}${bindir} + +clean: + rm -f *.o *.out ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-cont-check.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,234 @@ +/* + * This program reads a pcap file, extracts packets belonging to a + * particular RTP stream as identified by a source or destination + * IP:port, and checks its continuity: verifies that the sequence + * number always increments by 1 and that the timestamp always + * increments by 160 units. Finally, this program prints out + * the minimum and maximum observed capture time deltas between + * successive packets of the stream. + * + * The codec can be anything, and this program can also be used to + * check continuity of RTP streams coming from PSTN/SIP, but the + * core assumption is that packets must arrive every 20 ms, with + * the timestamp field incrementing by 160 units each time. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned iphdr_addr_offset, udphdr_port_offset; +static unsigned link_hdr_len, ethertype_offset; +static int stream_init_flag, deltat_init_flag; +static unsigned last_seq, last_tstamp, stream_ssrc; +static struct timeval last_pkt_time; +static unsigned deltat_min, deltat_max; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx, pkt_time) + u_char *rtp_hdr; + unsigned pkt_idx; + struct timeval *pkt_time; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + struct timeval deltat; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (stream_init_flag) { + if (cur_ssrc != stream_ssrc) { + fprintf(stderr, + "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", + pkt_idx, stream_ssrc, cur_ssrc); + exit(1); + } + if (cur_seq != last_seq + 1 && + (cur_seq != 0 || last_seq != 0xFFFF)) { + fprintf(stderr, + "error in packet #%u: seq break from 0x%04X to 0x%04X\n", + pkt_idx, last_seq, cur_seq); + exit(1); + } + if (cur_tstamp != last_tstamp + 160) { + fprintf(stderr, + "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", + pkt_idx, last_tstamp, cur_tstamp); + exit(1); + } + if (timercmp(pkt_time, &last_pkt_time, <)) { + fprintf(stderr, + "packet #%u timing error: Rx time goes backward\n", + pkt_idx); + exit(1); + } + timersub(pkt_time, &last_pkt_time, &deltat); + if (deltat.tv_sec) { + fprintf(stderr, + "packet #%u timing error: Rx time gap >= 1 s\n", + pkt_idx); + exit(1); + } + if (deltat_init_flag) { + if (deltat.tv_usec < deltat_min) + deltat_min = deltat.tv_usec; + if (deltat.tv_usec > deltat_max) + deltat_max = deltat.tv_usec; + } else { + deltat_min = deltat.tv_usec; + deltat_max = deltat.tv_usec; + deltat_init_flag = 1; + } + } else { + stream_init_flag = 1; + stream_ssrc = cur_ssrc; + } + last_seq = cur_seq; + last_tstamp = cur_tstamp; + bcopy(pkt_time, &last_pkt_time, sizeof(struct timeval)); +} + +static void +process_packet(pkt, caplen, pkt_idx, pkt_time) + u_char *pkt; + unsigned caplen, pkt_idx; + struct timeval *pkt_time; +{ + unsigned udplen; + + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) + return; + /* check UDP header */ + if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) + return; + /* it is our target - now scrutinize it */ + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + fprintf(stderr, + "error: packet #%u is truncated in the capture\n", + pkt_idx); + exit(1); + } + if (udplen < 20) { + fprintf(stderr, + "error in packet #%u: UDP length is too short for RTP header\n", + pkt_idx); + exit(1); + } + if (pkt[28] != 0x80) { + fprintf(stderr, + "error in packet #%u: unsupported RTP header structure\n", + pkt_idx); + exit(1); + } + rtp_stream_logic(pkt + 28, pkt_idx, pkt_time); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx; + + if (argc != 5) { + fprintf(stderr, + "usage: %s pcap-file src|dest ip-addr udp-port\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + if (!strcmp(argv[2], "src")) { + iphdr_addr_offset = 12; + udphdr_port_offset = 0; + } else if (!strcmp(argv[2], "dest")) { + iphdr_addr_offset = 16; + udphdr_port_offset = 2; + } else { + fprintf(stderr, + "error: direction argument must be \"src\" or \"dest\"\n"); + exit(1); + } + match_ip_addr = inet_addr(argv[3]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[4], 0, 0)); + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx, + &pkthdr.ts); + } + if (!stream_init_flag) { + fprintf(stderr, "error: specified RTP stream not found\n"); + exit(1); + } + if (!deltat_init_flag) { + fprintf(stderr, "error: found only one matching packet\n"); + exit(1); + } + printf("Minimum time delta: %u us\n", deltat_min); + printf("Maximum time delta: %u us\n", deltat_max); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-g711-extr.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,212 @@ +/* + * This program reads a pcap file, extracts packets belonging to a + * particular RTP stream as identified by a source or destination + * IP:port, and verifies that an unbroken RTP stream is present, + * with 160-byte payloads corresponding to timestamp increments + * of 160 units per packet, as expected for a G.711 (PCMU or PCMA) + * RTP stream with 20 ms packetization. The extracted G.711 stream + * is written to a raw binary file. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned iphdr_addr_offset, udphdr_port_offset; +static unsigned link_hdr_len, ethertype_offset; +static FILE *outfile; +static int stream_init_flag; +static unsigned last_seq, last_tstamp, stream_ssrc; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx) + u_char *rtp_hdr; + unsigned pkt_idx; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (stream_init_flag) { + if (cur_ssrc != stream_ssrc) { + fprintf(stderr, + "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", + pkt_idx, stream_ssrc, cur_ssrc); + exit(1); + } + if (cur_seq != last_seq + 1 && + (cur_seq != 0 || last_seq != 0xFFFF)) { + fprintf(stderr, + "error in packet #%u: seq break from 0x%04X to 0x%04X\n", + pkt_idx, last_seq, cur_seq); + exit(1); + } + if (cur_tstamp != last_tstamp + 160) { + fprintf(stderr, + "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", + pkt_idx, last_tstamp, cur_tstamp); + exit(1); + } + } else { + stream_init_flag = 1; + stream_ssrc = cur_ssrc; + } + last_seq = cur_seq; + last_tstamp = cur_tstamp; +} + +static void +process_packet(pkt, caplen, pkt_idx) + u_char *pkt; + unsigned caplen, pkt_idx; +{ + unsigned udplen, payload_len; + + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) + return; + /* check UDP header */ + if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) + return; + /* it is our target - now scrutinize it */ + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + fprintf(stderr, + "error: packet #%u is truncated in the capture\n", + pkt_idx); + exit(1); + } + if (udplen < 20) { + fprintf(stderr, + "error in packet #%u: UDP length is too short for RTP header\n", + pkt_idx); + exit(1); + } + if (pkt[28] != 0x80) { + fprintf(stderr, + "error in packet #%u: unsupported RTP header structure\n", + pkt_idx); + exit(1); + } + rtp_stream_logic(pkt + 28, pkt_idx); + payload_len = udplen - 20; + if (payload_len != 160) { + fprintf(stderr, "error in packet #%u: unsupported payload\n", + pkt_idx); + exit(1); + } + fwrite(pkt + 40, 1, payload_len, outfile); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx, skip_num; + + if (argc < 6 || argc > 7) { + fprintf(stderr, + "usage: %s pcap-file src|dest ip-addr udp-port outfile [skip-count]\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + if (!strcmp(argv[2], "src")) { + iphdr_addr_offset = 12; + udphdr_port_offset = 0; + } else if (!strcmp(argv[2], "dest")) { + iphdr_addr_offset = 16; + udphdr_port_offset = 2; + } else { + fprintf(stderr, + "error: direction argument must be \"src\" or \"dest\"\n"); + exit(1); + } + match_ip_addr = inet_addr(argv[3]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[4], 0, 0)); + outfile = fopen(argv[5], "w"); + if (!outfile) { + perror(argv[5]); + exit(1); + } + if (argv[6]) + skip_num = strtoul(argv[6], 0, 0); + else + skip_num = 0; + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + if (pkt_idx < skip_num) + continue; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); + } + if (!stream_init_flag) { + fprintf(stderr, "error: specified RTP stream not found\n"); + exit(1); + } + fclose(outfile); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-gsmfr-dump.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,276 @@ +/* + * This program is a combination of rtp-gsmfr-extr and gsmrec-dump into + * one step: it reads a pcap file, extracts packets belonging to a + * particular RTP stream as identified by a source or destination + * IP:port, verifies that an unbroken RTP stream is present, which is + * expected to be in GSM FR or EFR codec, but instead of writing this + * FR/EFR frame stream to a gsmx file, decodes it like gsmrec-dump. + * + * The advantage of this program over running rtp-gsmfr-extr followed + * by gsmrec-dump is that TRAUlike Extension Headers (if present) are + * dumped for analysis, rather than discarded. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> +#include <gsm.h> +#include <gsm_efr.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned iphdr_addr_offset, udphdr_port_offset; +static unsigned link_hdr_len, ethertype_offset; +static int stream_init_flag; +static unsigned last_seq, last_tstamp, stream_ssrc; +static gsm dummy_state; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx) + u_char *rtp_hdr; + unsigned pkt_idx; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (stream_init_flag) { + if (cur_ssrc != stream_ssrc) { + printf( + "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", + pkt_idx, stream_ssrc, cur_ssrc); + } else if (cur_seq != last_seq + 1 && + (cur_seq != 0 || last_seq != 0xFFFF)) { + printf( + "error in packet #%u: seq break from 0x%04X to 0x%04X\n", + pkt_idx, last_seq, cur_seq); + } else if (cur_tstamp != last_tstamp + 160) { + printf( + "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", + pkt_idx, last_tstamp, cur_tstamp); + } + } else + stream_init_flag = 1; + last_seq = cur_seq; + last_tstamp = cur_tstamp; + stream_ssrc = cur_ssrc; +} + +static void +process_payload(payload, payload_len) + u_char *payload; + unsigned payload_len; +{ + gsm_signal params[76]; + int i, j, n; + + printf("seq 0x%04X ts 0x%08X: ", last_seq, last_tstamp); + switch (payload_len) { + case 0: + printf("zero-length payload\n"); + return; + case 1: + if ((payload[0] & 0xF6) != 0xE6) + break; + printf("TEH 0x%02X\n", payload[0]); + return; + case 2: + if (payload[0] != 0xBF) + break; + printf("old BFI TAF=%u\n", payload[1] & 1); + return; + case 31: + if ((payload[0] & 0xF0) != 0xC0) + break; + printf("std EFR SID=%d LPC", EFR_sid_classify(payload)); + EFR_frame2params(payload, params); + print_efr: + n = 0; + for (i = 0; i < 5; i++) + printf(" %d", params[n++]); + putchar('\n'); + for (i = 0; i < 4; i++) { + putchar(' '); + for (j = 0; j < 13; j++) + printf(" %d", params[n++]); + putchar('\n'); + } + return; + case 32: + if ((payload[0] & 0xF4) != 0xE0) + break; + if ((payload[1] & 0xF0) != 0xC0) + break; + printf("TEH 0x%02X EFR SID=%d LPC", payload[0], + EFR_sid_classify(payload+1)); + EFR_frame2params(payload+1, params); + goto print_efr; + case 33: + if ((payload[0] & 0xF0) != 0xD0) + break; + fputs("std FR", stdout); + gsm_explode(dummy_state, payload, params); + print_fr: + n = 0; + for (i = 0; i < 8; i++) + printf(" %d", params[n++]); + putchar('\n'); + for (i = 0; i < 4; i++) { + putchar(' '); + for (j = 0; j < 17; j++) + printf(" %d", params[n++]); + putchar('\n'); + } + return; + case 34: + if ((payload[0] & 0xF4) != 0xE0) + break; + if ((payload[1] & 0xF0) != 0xD0) + break; + printf("TEH 0x%02X FR", payload[0]); + gsm_explode(dummy_state, payload+1, params); + goto print_fr; + } + printf("unknown payload format, length=%u\n", payload_len); +} + +static void +process_packet(pkt, caplen, pkt_idx) + u_char *pkt; + unsigned caplen, pkt_idx; +{ + unsigned udplen, payload_len; + + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) + return; + /* check UDP header */ + if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) + return; + /* it is our target - now scrutinize it */ + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + fprintf(stderr, + "error: packet #%u is truncated in the capture\n", + pkt_idx); + exit(1); + } + if (udplen < 20) { + fprintf(stderr, + "error in packet #%u: UDP length is too short for RTP header\n", + pkt_idx); + exit(1); + } + if (pkt[28] != 0x80) { + fprintf(stderr, + "error in packet #%u: unsupported RTP header structure\n", + pkt_idx); + exit(1); + } + rtp_stream_logic(pkt + 28, pkt_idx); + process_payload(pkt + 40, udplen - 20); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx; + + if (argc != 5) { + fprintf(stderr, + "usage: %s pcap-file src|dest ip-addr udp-port\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + if (!strcmp(argv[2], "src")) { + iphdr_addr_offset = 12; + udphdr_port_offset = 0; + } else if (!strcmp(argv[2], "dest")) { + iphdr_addr_offset = 16; + udphdr_port_offset = 2; + } else { + fprintf(stderr, + "error: direction argument must be \"src\" or \"dest\"\n"); + exit(1); + } + match_ip_addr = inet_addr(argv[3]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[4], 0, 0)); + dummy_state = gsm_create(); + if (!dummy_state) { + fprintf(stderr, "gsm_create() failed!\n"); + exit(1); + } + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); + } + if (!stream_init_flag) { + fprintf(stderr, "error: specified RTP stream not found\n"); + exit(1); + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-gsmfr-extr.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,249 @@ +/* + * This program reads a pcap file, extracts packets belonging to a + * particular RTP stream as identified by a source or destination + * IP:port, verifies that an unbroken RTP stream is present, in + * GSM FR or EFR codec, and writes the FR/EFR frame stream to our + * extended-libgsm format binary file, to be fed to decoding test + * programs. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned iphdr_addr_offset, udphdr_port_offset; +static unsigned link_hdr_len, ethertype_offset; +static FILE *outfile; +static int stream_init_flag; +static unsigned last_seq, last_tstamp, stream_ssrc; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx) + u_char *rtp_hdr; + unsigned pkt_idx; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (stream_init_flag) { + if (cur_ssrc != stream_ssrc) { + fprintf(stderr, + "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", + pkt_idx, stream_ssrc, cur_ssrc); + exit(1); + } + if (cur_seq != last_seq + 1 && + (cur_seq != 0 || last_seq != 0xFFFF)) { + fprintf(stderr, + "error in packet #%u: seq break from 0x%04X to 0x%04X\n", + pkt_idx, last_seq, cur_seq); + exit(1); + } + if (cur_tstamp != last_tstamp + 160) { + fprintf(stderr, + "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", + pkt_idx, last_tstamp, cur_tstamp); + exit(1); + } + } else { + stream_init_flag = 1; + stream_ssrc = cur_ssrc; + } + last_seq = cur_seq; + last_tstamp = cur_tstamp; +} + +static void +process_packet(pkt, caplen, pkt_idx) + u_char *pkt; + unsigned caplen, pkt_idx; +{ + unsigned udplen, payload_len; + u_char synth_bfi[2]; + + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) + return; + /* check UDP header */ + if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) + return; + /* it is our target - now scrutinize it */ + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + fprintf(stderr, + "error: packet #%u is truncated in the capture\n", + pkt_idx); + exit(1); + } + if (udplen < 20) { + fprintf(stderr, + "error in packet #%u: UDP length is too short for RTP header\n", + pkt_idx); + exit(1); + } + if (pkt[28] != 0x80) { + fprintf(stderr, + "error in packet #%u: unsupported RTP header structure\n", + pkt_idx); + exit(1); + } + rtp_stream_logic(pkt + 28, pkt_idx); + payload_len = udplen - 20; + switch (payload_len) { + case 0: + synth_bfi[0] = 0xBF; + synth_bfi[1] = 0; + emit_synth_bfi: + fwrite(synth_bfi, 1, 2, outfile); + return; + case 1: + if ((pkt[40] & 0xF6) != 0xE6) + break; + traulike_bfi: + synth_bfi[0] = 0xBF; + synth_bfi[1] = pkt[40] & 1; + goto emit_synth_bfi; + case 2: + if (pkt[40] != 0xBF) + break; + emit_payload: + fwrite(pkt + 40, 1, payload_len, outfile); + return; + case 31: + if ((pkt[40] & 0xF0) != 0xC0) + break; + goto emit_payload; + case 32: + if ((pkt[40] & 0xF4) != 0xE0) + break; + if ((pkt[41] & 0xF0) != 0xC0) + break; + if (pkt[40] & 2) + goto traulike_bfi; + fwrite(pkt + 41, 1, 31, outfile); + return; + case 33: + if ((pkt[40] & 0xF0) != 0xD0) + break; + goto emit_payload; + case 34: + if ((pkt[40] & 0xF4) != 0xE0) + break; + if ((pkt[41] & 0xF0) != 0xD0) + break; + if (pkt[40] & 2) + goto traulike_bfi; + fwrite(pkt + 41, 1, 33, outfile); + return; + } + fprintf(stderr, "error in packet #%u: unsupported payload\n", pkt_idx); + exit(1); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx; + + if (argc != 6) { + fprintf(stderr, + "usage: %s pcap-file src|dest ip-addr udp-port outfile\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + if (!strcmp(argv[2], "src")) { + iphdr_addr_offset = 12; + udphdr_port_offset = 0; + } else if (!strcmp(argv[2], "dest")) { + iphdr_addr_offset = 16; + udphdr_port_offset = 2; + } else { + fprintf(stderr, + "error: direction argument must be \"src\" or \"dest\"\n"); + exit(1); + } + match_ip_addr = inet_addr(argv[3]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[4], 0, 0)); + outfile = fopen(argv[5], "w"); + if (!outfile) { + perror(argv[5]); + exit(1); + } + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); + } + if (!stream_init_flag) { + fprintf(stderr, "error: specified RTP stream not found\n"); + exit(1); + } + fclose(outfile); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-jitter-view.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,220 @@ +/* + * This program reads a pcap file, extracts packets belonging to a + * particular RTP stream as identified by a source or destination + * IP:port, checks its continuity at the packet header level + * (verifies that the sequence number always increments by 1 and + * that the timestamp always increments by 160 units) and prints out + * the Rx time delta of each stream packet (the capture time of + * the current packet minus the capture time of the previous packet) + * on stdout, allowing visual analysis of timing jitter. + * + * The codec can be anything, and this program can also be used to + * examine the jitter of RTP streams coming from PSTN/SIP, but the + * core assumption is that packets must arrive every 20 ms, with + * the timestamp field incrementing by 160 units each time. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned iphdr_addr_offset, udphdr_port_offset; +static unsigned link_hdr_len, ethertype_offset; +static int stream_init_flag; +static unsigned last_seq, last_tstamp, stream_ssrc; +static struct timeval last_pkt_time; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx, pkt_time) + u_char *rtp_hdr; + unsigned pkt_idx; + struct timeval *pkt_time; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + struct timeval deltat; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (stream_init_flag) { + if (cur_ssrc != stream_ssrc) { + fprintf(stderr, + "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", + pkt_idx, stream_ssrc, cur_ssrc); + exit(1); + } + if (cur_seq != last_seq + 1 && + (cur_seq != 0 || last_seq != 0xFFFF)) { + fprintf(stderr, + "error in packet #%u: seq break from 0x%04X to 0x%04X\n", + pkt_idx, last_seq, cur_seq); + exit(1); + } + if (cur_tstamp != last_tstamp + 160) { + fprintf(stderr, + "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", + pkt_idx, last_tstamp, cur_tstamp); + exit(1); + } + if (timercmp(pkt_time, &last_pkt_time, <)) { + fprintf(stderr, + "packet #%u timing error: Rx time goes backward\n", + pkt_idx); + exit(1); + } + timersub(pkt_time, &last_pkt_time, &deltat); + if (deltat.tv_sec) { + fprintf(stderr, + "packet #%u timing error: Rx time gap >= 1 s\n", + pkt_idx); + exit(1); + } + printf("Packet #%u: time delta %u us\n", pkt_idx, + (unsigned) deltat.tv_usec); + } else { + stream_init_flag = 1; + stream_ssrc = cur_ssrc; + } + last_seq = cur_seq; + last_tstamp = cur_tstamp; + bcopy(pkt_time, &last_pkt_time, sizeof(struct timeval)); +} + +static void +process_packet(pkt, caplen, pkt_idx, pkt_time) + u_char *pkt; + unsigned caplen, pkt_idx; + struct timeval *pkt_time; +{ + unsigned udplen; + + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) + return; + /* check UDP header */ + if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) + return; + /* it is our target - now scrutinize it */ + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + fprintf(stderr, + "error: packet #%u is truncated in the capture\n", + pkt_idx); + exit(1); + } + if (udplen < 20) { + fprintf(stderr, + "error in packet #%u: UDP length is too short for RTP header\n", + pkt_idx); + exit(1); + } + if (pkt[28] != 0x80) { + fprintf(stderr, + "error in packet #%u: unsupported RTP header structure\n", + pkt_idx); + exit(1); + } + rtp_stream_logic(pkt + 28, pkt_idx, pkt_time); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx; + + if (argc != 5) { + fprintf(stderr, + "usage: %s pcap-file src|dest ip-addr udp-port\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + if (!strcmp(argv[2], "src")) { + iphdr_addr_offset = 12; + udphdr_port_offset = 0; + } else if (!strcmp(argv[2], "dest")) { + iphdr_addr_offset = 16; + udphdr_port_offset = 2; + } else { + fprintf(stderr, + "error: direction argument must be \"src\" or \"dest\"\n"); + exit(1); + } + match_ip_addr = inet_addr(argv[3]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[4], 0, 0)); + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx, + &pkthdr.ts); + } + if (!stream_init_flag) { + fprintf(stderr, "error: specified RTP stream not found\n"); + exit(1); + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-stream-dump.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,188 @@ +/* + * This program is an aid for analyzing arbitrary RTP streams: + * it reads a pcap file, extracts packets belonging to a particular + * RTP stream as identified by a source or destination IP:port, + * and displays a one-line summary of every RTP packet. + * Discontinuities are treated as non-fatal errors: an error message + * is printed, but analysis continues. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned iphdr_addr_offset, udphdr_port_offset; +static unsigned link_hdr_len, ethertype_offset; +static int stream_init_flag; +static unsigned last_seq, last_tstamp, stream_ssrc; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx) + u_char *rtp_hdr; + unsigned pkt_idx; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (stream_init_flag) { + if (cur_ssrc != stream_ssrc) { + printf( + "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", + pkt_idx, stream_ssrc, cur_ssrc); + } else if (cur_seq != last_seq + 1 && + (cur_seq != 0 || last_seq != 0xFFFF)) { + printf( + "error in packet #%u: seq break from 0x%04X to 0x%04X\n", + pkt_idx, last_seq, cur_seq); + } else if (cur_tstamp != last_tstamp + 160) { + printf( + "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", + pkt_idx, last_tstamp, cur_tstamp); + } + } else + stream_init_flag = 1; + last_seq = cur_seq; + last_tstamp = cur_tstamp; + stream_ssrc = cur_ssrc; +} + +static void +process_packet(pkt, caplen, pkt_idx) + u_char *pkt; + unsigned caplen, pkt_idx; +{ + unsigned udplen, payload_len; + + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) + return; + /* check UDP header */ + if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) + return; + /* it is our target - now scrutinize it */ + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + fprintf(stderr, + "error: packet #%u is truncated in the capture\n", + pkt_idx); + exit(1); + } + if (udplen < 20) { + fprintf(stderr, + "error in packet #%u: UDP length is too short for RTP header\n", + pkt_idx); + exit(1); + } + if (pkt[28] != 0x80) { + fprintf(stderr, + "error in packet #%u: unsupported RTP header structure\n", + pkt_idx); + exit(1); + } + rtp_stream_logic(pkt + 28, pkt_idx); + printf("pkt #%u seq 0x%04X ts 0x%08X: pt=%u M=%u len=%u\n", pkt_idx, + last_seq, last_tstamp, pkt[29] & 0x7F, pkt[29] >> 7, + udplen - 20); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx; + + if (argc != 5) { + fprintf(stderr, + "usage: %s pcap-file src|dest ip-addr udp-port\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + if (!strcmp(argv[2], "src")) { + iphdr_addr_offset = 12; + udphdr_port_offset = 0; + } else if (!strcmp(argv[2], "dest")) { + iphdr_addr_offset = 16; + udphdr_port_offset = 2; + } else { + fprintf(stderr, + "error: direction argument must be \"src\" or \"dest\"\n"); + exit(1); + } + match_ip_addr = inet_addr(argv[3]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[4], 0, 0)); + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); + } + if (!stream_init_flag) { + fprintf(stderr, "error: specified RTP stream not found\n"); + exit(1); + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pcap-study/rtp-tfo-trace.c Wed May 15 01:44:46 2024 +0000 @@ -0,0 +1,338 @@ +/* + * This program reads a pcap file containing RTP packets of a PSTN call + * (PCMU or PCMA, 160 samples per RTP packet), flowing in one or both + * directions, and looks for TFO IS messages. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pcap/pcap.h> + +static pcap_t *pcap; +static in_addr_t match_ip_addr; +static u_short match_udp_port; +static unsigned link_hdr_len, ethertype_offset; + +static struct onedir { + int init_flag; + unsigned last_seq; + unsigned last_tstamp; + unsigned stream_ssrc; + u_char is_hunt_buf[320]; + int is_state; + unsigned is_hunt_fill; + unsigned is_offset; + unsigned is_alignment; + unsigned is_bit_count; + unsigned is_rx_word; +} rx_state, tx_state; + +static const u_char hdr_pattern[20] = {0, 1, 0, 1, 0, 1, 1, 0, 1, 0, + 0, 1, 1, 0, 1, 0, 1, 0, 0, 1}; + +static void +check_dl_type() +{ + int dltype; + + dltype = pcap_datalink(pcap); + switch (dltype) { + case DLT_EN10MB: + link_hdr_len = 14; + ethertype_offset = 12; + break; + case DLT_RAW: + link_hdr_len = 0; + break; + case DLT_LINUX_SLL: + link_hdr_len = 16; + ethertype_offset = 14; + break; + default: + fprintf(stderr, "error: unsupported data link type %d\n", + dltype); + exit(1); + } +} + +static void +rtp_stream_logic(rtp_hdr, pkt_idx, st, dir_str) + u_char *rtp_hdr; + unsigned pkt_idx; + struct onedir *st; + char *dir_str; +{ + unsigned cur_seq, cur_tstamp, cur_ssrc; + + cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; + cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | + (rtp_hdr[6] << 8) | rtp_hdr[7]; + cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | + (rtp_hdr[10] << 8) | rtp_hdr[11]; + if (st->init_flag) { + if (cur_ssrc != st->stream_ssrc) { + printf( + "error in %s packet #%u: SSRC change from 0x%08X to 0x%08X\n", + dir_str, pkt_idx, st->stream_ssrc, cur_ssrc); + } else if (cur_seq != st->last_seq + 1 && + (cur_seq != 0 || st->last_seq != 0xFFFF)) { + printf( + "error in %s packet #%u: seq break from 0x%04X to 0x%04X\n", + dir_str, pkt_idx, st->last_seq, cur_seq); + } else if (cur_tstamp != st->last_tstamp + 160) { + printf( + "error in %s packet #%u: timestamp break from 0x%08X to 0x%08X\n", + dir_str, pkt_idx, st->last_tstamp, cur_tstamp); + } + } else + st->init_flag = 1; + st->last_seq = cur_seq; + st->last_tstamp = cur_tstamp; + st->stream_ssrc = cur_ssrc; +} + +static void +is_rx_hunt(input_pos, pkt_idx, st, dir_str) + unsigned input_pos; + unsigned pkt_idx; + struct onedir *st; + char *dir_str; +{ + unsigned offset, n; + + for (offset = 0; offset < 16; offset++) { + for (n = 0; n < 20; n++) + if ((st->is_hunt_buf[offset + n*16] & 1) != + hdr_pattern[n]) + break; + if (n == 20) + break; + } + if (n != 20) + return; + st->is_offset = offset; + st->is_alignment = input_pos * 16 + offset; + st->is_state = 1; + st->is_bit_count = 0; + st->is_rx_word = 0; + st->is_hunt_fill = 0; +} + +static void +is_process_cmd(pkt_idx, st, dir_str) + unsigned pkt_idx; + struct onedir *st; + char *dir_str; +{ + int cont; + + printf("#%u: %s (align %u) ", pkt_idx, dir_str, st->is_alignment); + switch (st->is_rx_word) { + case 0x05D: + printf("IS_REQ\n"); + cont = 1; + break; + case 0x0BA: + printf("IS_ACK\n"); + cont = 1; + break; + case 0x0E7: + printf("IS_IPE\n"); + cont = 1; + break; + case 0x129: + printf("IS_FILL\n"); + cont = 0; + break; + case 0x174: + printf("IS_DUP\n"); + cont = 0; + break; + case 0x193: + printf("IS_SYL\n"); + cont = 0; + break; + default: + printf("Unknown IS_Command 0x%03X\n", st->is_rx_word); + cont = 0; + } + if (cont) { + st->is_state = 2; + st->is_bit_count = 0; + st->is_rx_word = 0; + } else + st->is_state = 0; +} + +static void +is_process_ext(pkt_idx, st, dir_str) + unsigned pkt_idx; + struct onedir *st; + char *dir_str; +{ + printf("#%u: %s IS_Extension: 0x%05X", pkt_idx, dir_str, + st->is_rx_word); + if (st->is_rx_word & 0x80200) { + printf(" (bad sync)\n"); + st->is_state = 0; + return; + } + switch (st->is_rx_word & 3) { + case 0: + printf(" (final)\n"); + st->is_state = 0; + return; + case 3: + printf(" (continue)\n"); + st->is_state = 2; + st->is_bit_count = 0; + st->is_rx_word = 0; + return; + default: + printf(" (bad EX)\n"); + st->is_state = 0; + } +} + +static void +is_rx_process(input, input_pos, pkt_idx, st, dir_str) + uint8_t *input; + unsigned input_pos; + unsigned pkt_idx; + struct onedir *st; + char *dir_str; +{ + unsigned new_bit; + + memmove(st->is_hunt_buf, st->is_hunt_buf + 16, 304); + memcpy(st->is_hunt_buf + 304, input, 16); + if (!st->is_state) { + if (st->is_hunt_fill < 20) + st->is_hunt_fill++; + if (st->is_hunt_fill == 20) + is_rx_hunt(input_pos, pkt_idx, st, dir_str); + return; + } + new_bit = input[st->is_offset] & 1; + st->is_rx_word <<= 1; + st->is_rx_word |= new_bit; + st->is_bit_count++; + if (st->is_state == 1 && st->is_bit_count == 10) + is_process_cmd(pkt_idx, st, dir_str); + else if (st->is_state == 2 && st->is_bit_count == 20) + is_process_ext(pkt_idx, st, dir_str); +} + +static void +process_packet_onedir(pkt, caplen, pkt_idx, st, dir_str) + u_char *pkt; + unsigned caplen, pkt_idx; + struct onedir *st; + char *dir_str; +{ + unsigned udplen, payload_len; + unsigned is_chunk; + + udplen = (pkt[24] << 8) | pkt[25]; + if (caplen < udplen + 20) { + printf("error: %s packet #%u is truncated in the capture\n", + dir_str, pkt_idx); + return; + } + if (udplen < 20) { + printf( + "error in %s packet #%u: UDP length is too short for RTP header\n", + dir_str, pkt_idx); + return; + } + if (pkt[28] != 0x80) { + printf( + "error in %s packet #%u: unsupported RTP header structure\n", + dir_str, pkt_idx); + return; + } + rtp_stream_logic(pkt + 28, pkt_idx, st, dir_str); + payload_len = udplen - 20; + if (payload_len != 160) { + printf("error in %s packet #%u: wrong payload length\n", + dir_str, pkt_idx); + return; + } + for (is_chunk = 0; is_chunk < 10; is_chunk++) + is_rx_process(pkt + 40 + is_chunk * 16, is_chunk, pkt_idx, st, + dir_str); +} + +static void +process_packet(pkt, caplen, pkt_idx) + u_char *pkt; + unsigned caplen, pkt_idx; +{ + if (caplen < link_hdr_len + 28) + return; + if (link_hdr_len) { + if (pkt[ethertype_offset] != 0x08) + return; + if (pkt[ethertype_offset+1] != 0x00) + return; + pkt += link_hdr_len; + caplen -= link_hdr_len; + } + /* check IP header */ + if (pkt[0] != 0x45) + return; + if (pkt[9] != 17) /* UDP */ + return; + if (!bcmp(pkt + 12, &match_ip_addr, 4) && + !bcmp(pkt + 20, &match_udp_port, 2)) + process_packet_onedir(pkt, caplen, pkt_idx, &tx_state, "-->"); + else if (!bcmp(pkt + 16, &match_ip_addr, 4) && + !bcmp(pkt + 22, &match_udp_port, 2)) + process_packet_onedir(pkt, caplen, pkt_idx, &rx_state, "<--"); +} + +main(argc, argv) + char **argv; +{ + char errbuf[PCAP_ERRBUF_SIZE]; + u_char *pkt; + struct pcap_pkthdr pkthdr; + unsigned pkt_idx; + + if (argc != 4) { + fprintf(stderr, "usage: %s pcap-file ip-addr udp-port\n", + argv[0]); + exit(1); + } + pcap = pcap_open_offline(argv[1], errbuf); + if (!pcap) { + fprintf(stderr, "%s: %s\n", argv[1], errbuf); + exit(1); + } + check_dl_type(); + match_ip_addr = inet_addr(argv[2]); + if (match_ip_addr == INADDR_NONE) { + fprintf(stderr, "error: IP address argument is invalid\n"); + exit(1); + } + match_udp_port = htons(strtoul(argv[3], 0, 0)); + for (pkt_idx = 0; ; pkt_idx++) { + pkt = pcap_next(pcap, &pkthdr); + if (!pkt) + break; + process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); + } + if (!tx_state.init_flag) + printf( + "Warning: found no packets with src matching specified IP:port\n"); + if (!rx_state.init_flag) + printf( + "Warning: found no packets with dest matching specified IP:port\n"); + exit(0); +}
--- a/rtp-cont-check.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* - * This program reads a pcap file, extracts packets belonging to a - * particular RTP stream as identified by a source or destination - * IP:port, and checks its continuity: verifies that the sequence - * number always increments by 1 and that the timestamp always - * increments by 160 units. Finally, this program prints out - * the minimum and maximum observed capture time deltas between - * successive packets of the stream. - * - * The codec can be anything, and this program can also be used to - * check continuity of RTP streams coming from PSTN/SIP, but the - * core assumption is that packets must arrive every 20 ms, with - * the timestamp field incrementing by 160 units each time. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned iphdr_addr_offset, udphdr_port_offset; -static unsigned link_hdr_len, ethertype_offset; -static int stream_init_flag, deltat_init_flag; -static unsigned last_seq, last_tstamp, stream_ssrc; -static struct timeval last_pkt_time; -static unsigned deltat_min, deltat_max; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx, pkt_time) - u_char *rtp_hdr; - unsigned pkt_idx; - struct timeval *pkt_time; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - struct timeval deltat; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (stream_init_flag) { - if (cur_ssrc != stream_ssrc) { - fprintf(stderr, - "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", - pkt_idx, stream_ssrc, cur_ssrc); - exit(1); - } - if (cur_seq != last_seq + 1 && - (cur_seq != 0 || last_seq != 0xFFFF)) { - fprintf(stderr, - "error in packet #%u: seq break from 0x%04X to 0x%04X\n", - pkt_idx, last_seq, cur_seq); - exit(1); - } - if (cur_tstamp != last_tstamp + 160) { - fprintf(stderr, - "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", - pkt_idx, last_tstamp, cur_tstamp); - exit(1); - } - if (timercmp(pkt_time, &last_pkt_time, <)) { - fprintf(stderr, - "packet #%u timing error: Rx time goes backward\n", - pkt_idx); - exit(1); - } - timersub(pkt_time, &last_pkt_time, &deltat); - if (deltat.tv_sec) { - fprintf(stderr, - "packet #%u timing error: Rx time gap >= 1 s\n", - pkt_idx); - exit(1); - } - if (deltat_init_flag) { - if (deltat.tv_usec < deltat_min) - deltat_min = deltat.tv_usec; - if (deltat.tv_usec > deltat_max) - deltat_max = deltat.tv_usec; - } else { - deltat_min = deltat.tv_usec; - deltat_max = deltat.tv_usec; - deltat_init_flag = 1; - } - } else { - stream_init_flag = 1; - stream_ssrc = cur_ssrc; - } - last_seq = cur_seq; - last_tstamp = cur_tstamp; - bcopy(pkt_time, &last_pkt_time, sizeof(struct timeval)); -} - -static void -process_packet(pkt, caplen, pkt_idx, pkt_time) - u_char *pkt; - unsigned caplen, pkt_idx; - struct timeval *pkt_time; -{ - unsigned udplen; - - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) - return; - /* check UDP header */ - if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) - return; - /* it is our target - now scrutinize it */ - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - fprintf(stderr, - "error: packet #%u is truncated in the capture\n", - pkt_idx); - exit(1); - } - if (udplen < 20) { - fprintf(stderr, - "error in packet #%u: UDP length is too short for RTP header\n", - pkt_idx); - exit(1); - } - if (pkt[28] != 0x80) { - fprintf(stderr, - "error in packet #%u: unsupported RTP header structure\n", - pkt_idx); - exit(1); - } - rtp_stream_logic(pkt + 28, pkt_idx, pkt_time); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx; - - if (argc != 5) { - fprintf(stderr, - "usage: %s pcap-file src|dest ip-addr udp-port\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - if (!strcmp(argv[2], "src")) { - iphdr_addr_offset = 12; - udphdr_port_offset = 0; - } else if (!strcmp(argv[2], "dest")) { - iphdr_addr_offset = 16; - udphdr_port_offset = 2; - } else { - fprintf(stderr, - "error: direction argument must be \"src\" or \"dest\"\n"); - exit(1); - } - match_ip_addr = inet_addr(argv[3]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[4], 0, 0)); - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx, - &pkthdr.ts); - } - if (!stream_init_flag) { - fprintf(stderr, "error: specified RTP stream not found\n"); - exit(1); - } - if (!deltat_init_flag) { - fprintf(stderr, "error: found only one matching packet\n"); - exit(1); - } - printf("Minimum time delta: %u us\n", deltat_min); - printf("Maximum time delta: %u us\n", deltat_max); - exit(0); -}
--- a/rtp-g711-extr.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -/* - * This program reads a pcap file, extracts packets belonging to a - * particular RTP stream as identified by a source or destination - * IP:port, and verifies that an unbroken RTP stream is present, - * with 160-byte payloads corresponding to timestamp increments - * of 160 units per packet, as expected for a G.711 (PCMU or PCMA) - * RTP stream with 20 ms packetization. The extracted G.711 stream - * is written to a raw binary file. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned iphdr_addr_offset, udphdr_port_offset; -static unsigned link_hdr_len, ethertype_offset; -static FILE *outfile; -static int stream_init_flag; -static unsigned last_seq, last_tstamp, stream_ssrc; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx) - u_char *rtp_hdr; - unsigned pkt_idx; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (stream_init_flag) { - if (cur_ssrc != stream_ssrc) { - fprintf(stderr, - "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", - pkt_idx, stream_ssrc, cur_ssrc); - exit(1); - } - if (cur_seq != last_seq + 1 && - (cur_seq != 0 || last_seq != 0xFFFF)) { - fprintf(stderr, - "error in packet #%u: seq break from 0x%04X to 0x%04X\n", - pkt_idx, last_seq, cur_seq); - exit(1); - } - if (cur_tstamp != last_tstamp + 160) { - fprintf(stderr, - "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", - pkt_idx, last_tstamp, cur_tstamp); - exit(1); - } - } else { - stream_init_flag = 1; - stream_ssrc = cur_ssrc; - } - last_seq = cur_seq; - last_tstamp = cur_tstamp; -} - -static void -process_packet(pkt, caplen, pkt_idx) - u_char *pkt; - unsigned caplen, pkt_idx; -{ - unsigned udplen, payload_len; - - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) - return; - /* check UDP header */ - if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) - return; - /* it is our target - now scrutinize it */ - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - fprintf(stderr, - "error: packet #%u is truncated in the capture\n", - pkt_idx); - exit(1); - } - if (udplen < 20) { - fprintf(stderr, - "error in packet #%u: UDP length is too short for RTP header\n", - pkt_idx); - exit(1); - } - if (pkt[28] != 0x80) { - fprintf(stderr, - "error in packet #%u: unsupported RTP header structure\n", - pkt_idx); - exit(1); - } - rtp_stream_logic(pkt + 28, pkt_idx); - payload_len = udplen - 20; - if (payload_len != 160) { - fprintf(stderr, "error in packet #%u: unsupported payload\n", - pkt_idx); - exit(1); - } - fwrite(pkt + 40, 1, payload_len, outfile); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx, skip_num; - - if (argc < 6 || argc > 7) { - fprintf(stderr, - "usage: %s pcap-file src|dest ip-addr udp-port outfile [skip-count]\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - if (!strcmp(argv[2], "src")) { - iphdr_addr_offset = 12; - udphdr_port_offset = 0; - } else if (!strcmp(argv[2], "dest")) { - iphdr_addr_offset = 16; - udphdr_port_offset = 2; - } else { - fprintf(stderr, - "error: direction argument must be \"src\" or \"dest\"\n"); - exit(1); - } - match_ip_addr = inet_addr(argv[3]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[4], 0, 0)); - outfile = fopen(argv[5], "w"); - if (!outfile) { - perror(argv[5]); - exit(1); - } - if (argv[6]) - skip_num = strtoul(argv[6], 0, 0); - else - skip_num = 0; - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - if (pkt_idx < skip_num) - continue; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); - } - if (!stream_init_flag) { - fprintf(stderr, "error: specified RTP stream not found\n"); - exit(1); - } - fclose(outfile); - exit(0); -}
--- a/rtp-gsmfr-dump.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -/* - * This program is a combination of rtp-gsmfr-extr and gsmrec-dump into - * one step: it reads a pcap file, extracts packets belonging to a - * particular RTP stream as identified by a source or destination - * IP:port, verifies that an unbroken RTP stream is present, which is - * expected to be in GSM FR or EFR codec, but instead of writing this - * FR/EFR frame stream to a gsmx file, decodes it like gsmrec-dump. - * - * The advantage of this program over running rtp-gsmfr-extr followed - * by gsmrec-dump is that TRAUlike Extension Headers (if present) are - * dumped for analysis, rather than discarded. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> -#include <gsm.h> -#include <gsm_efr.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned iphdr_addr_offset, udphdr_port_offset; -static unsigned link_hdr_len, ethertype_offset; -static int stream_init_flag; -static unsigned last_seq, last_tstamp, stream_ssrc; -static gsm dummy_state; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx) - u_char *rtp_hdr; - unsigned pkt_idx; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (stream_init_flag) { - if (cur_ssrc != stream_ssrc) { - printf( - "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", - pkt_idx, stream_ssrc, cur_ssrc); - } else if (cur_seq != last_seq + 1 && - (cur_seq != 0 || last_seq != 0xFFFF)) { - printf( - "error in packet #%u: seq break from 0x%04X to 0x%04X\n", - pkt_idx, last_seq, cur_seq); - } else if (cur_tstamp != last_tstamp + 160) { - printf( - "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", - pkt_idx, last_tstamp, cur_tstamp); - } - } else - stream_init_flag = 1; - last_seq = cur_seq; - last_tstamp = cur_tstamp; - stream_ssrc = cur_ssrc; -} - -static void -process_payload(payload, payload_len) - u_char *payload; - unsigned payload_len; -{ - gsm_signal params[76]; - int i, j, n; - - printf("seq 0x%04X ts 0x%08X: ", last_seq, last_tstamp); - switch (payload_len) { - case 0: - printf("zero-length payload\n"); - return; - case 1: - if ((payload[0] & 0xF6) != 0xE6) - break; - printf("TEH 0x%02X\n", payload[0]); - return; - case 2: - if (payload[0] != 0xBF) - break; - printf("old BFI TAF=%u\n", payload[1] & 1); - return; - case 31: - if ((payload[0] & 0xF0) != 0xC0) - break; - printf("std EFR SID=%d LPC", EFR_sid_classify(payload)); - EFR_frame2params(payload, params); - print_efr: - n = 0; - for (i = 0; i < 5; i++) - printf(" %d", params[n++]); - putchar('\n'); - for (i = 0; i < 4; i++) { - putchar(' '); - for (j = 0; j < 13; j++) - printf(" %d", params[n++]); - putchar('\n'); - } - return; - case 32: - if ((payload[0] & 0xF4) != 0xE0) - break; - if ((payload[1] & 0xF0) != 0xC0) - break; - printf("TEH 0x%02X EFR SID=%d LPC", payload[0], - EFR_sid_classify(payload+1)); - EFR_frame2params(payload+1, params); - goto print_efr; - case 33: - if ((payload[0] & 0xF0) != 0xD0) - break; - fputs("std FR", stdout); - gsm_explode(dummy_state, payload, params); - print_fr: - n = 0; - for (i = 0; i < 8; i++) - printf(" %d", params[n++]); - putchar('\n'); - for (i = 0; i < 4; i++) { - putchar(' '); - for (j = 0; j < 17; j++) - printf(" %d", params[n++]); - putchar('\n'); - } - return; - case 34: - if ((payload[0] & 0xF4) != 0xE0) - break; - if ((payload[1] & 0xF0) != 0xD0) - break; - printf("TEH 0x%02X FR", payload[0]); - gsm_explode(dummy_state, payload+1, params); - goto print_fr; - } - printf("unknown payload format, length=%u\n", payload_len); -} - -static void -process_packet(pkt, caplen, pkt_idx) - u_char *pkt; - unsigned caplen, pkt_idx; -{ - unsigned udplen, payload_len; - - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) - return; - /* check UDP header */ - if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) - return; - /* it is our target - now scrutinize it */ - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - fprintf(stderr, - "error: packet #%u is truncated in the capture\n", - pkt_idx); - exit(1); - } - if (udplen < 20) { - fprintf(stderr, - "error in packet #%u: UDP length is too short for RTP header\n", - pkt_idx); - exit(1); - } - if (pkt[28] != 0x80) { - fprintf(stderr, - "error in packet #%u: unsupported RTP header structure\n", - pkt_idx); - exit(1); - } - rtp_stream_logic(pkt + 28, pkt_idx); - process_payload(pkt + 40, udplen - 20); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx; - - if (argc != 5) { - fprintf(stderr, - "usage: %s pcap-file src|dest ip-addr udp-port\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - if (!strcmp(argv[2], "src")) { - iphdr_addr_offset = 12; - udphdr_port_offset = 0; - } else if (!strcmp(argv[2], "dest")) { - iphdr_addr_offset = 16; - udphdr_port_offset = 2; - } else { - fprintf(stderr, - "error: direction argument must be \"src\" or \"dest\"\n"); - exit(1); - } - match_ip_addr = inet_addr(argv[3]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[4], 0, 0)); - dummy_state = gsm_create(); - if (!dummy_state) { - fprintf(stderr, "gsm_create() failed!\n"); - exit(1); - } - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); - } - if (!stream_init_flag) { - fprintf(stderr, "error: specified RTP stream not found\n"); - exit(1); - } - exit(0); -}
--- a/rtp-gsmfr-extr.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,249 +0,0 @@ -/* - * This program reads a pcap file, extracts packets belonging to a - * particular RTP stream as identified by a source or destination - * IP:port, verifies that an unbroken RTP stream is present, in - * GSM FR or EFR codec, and writes the FR/EFR frame stream to our - * extended-libgsm format binary file, to be fed to decoding test - * programs. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned iphdr_addr_offset, udphdr_port_offset; -static unsigned link_hdr_len, ethertype_offset; -static FILE *outfile; -static int stream_init_flag; -static unsigned last_seq, last_tstamp, stream_ssrc; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx) - u_char *rtp_hdr; - unsigned pkt_idx; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (stream_init_flag) { - if (cur_ssrc != stream_ssrc) { - fprintf(stderr, - "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", - pkt_idx, stream_ssrc, cur_ssrc); - exit(1); - } - if (cur_seq != last_seq + 1 && - (cur_seq != 0 || last_seq != 0xFFFF)) { - fprintf(stderr, - "error in packet #%u: seq break from 0x%04X to 0x%04X\n", - pkt_idx, last_seq, cur_seq); - exit(1); - } - if (cur_tstamp != last_tstamp + 160) { - fprintf(stderr, - "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", - pkt_idx, last_tstamp, cur_tstamp); - exit(1); - } - } else { - stream_init_flag = 1; - stream_ssrc = cur_ssrc; - } - last_seq = cur_seq; - last_tstamp = cur_tstamp; -} - -static void -process_packet(pkt, caplen, pkt_idx) - u_char *pkt; - unsigned caplen, pkt_idx; -{ - unsigned udplen, payload_len; - u_char synth_bfi[2]; - - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) - return; - /* check UDP header */ - if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) - return; - /* it is our target - now scrutinize it */ - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - fprintf(stderr, - "error: packet #%u is truncated in the capture\n", - pkt_idx); - exit(1); - } - if (udplen < 20) { - fprintf(stderr, - "error in packet #%u: UDP length is too short for RTP header\n", - pkt_idx); - exit(1); - } - if (pkt[28] != 0x80) { - fprintf(stderr, - "error in packet #%u: unsupported RTP header structure\n", - pkt_idx); - exit(1); - } - rtp_stream_logic(pkt + 28, pkt_idx); - payload_len = udplen - 20; - switch (payload_len) { - case 0: - synth_bfi[0] = 0xBF; - synth_bfi[1] = 0; - emit_synth_bfi: - fwrite(synth_bfi, 1, 2, outfile); - return; - case 1: - if ((pkt[40] & 0xF6) != 0xE6) - break; - traulike_bfi: - synth_bfi[0] = 0xBF; - synth_bfi[1] = pkt[40] & 1; - goto emit_synth_bfi; - case 2: - if (pkt[40] != 0xBF) - break; - emit_payload: - fwrite(pkt + 40, 1, payload_len, outfile); - return; - case 31: - if ((pkt[40] & 0xF0) != 0xC0) - break; - goto emit_payload; - case 32: - if ((pkt[40] & 0xF4) != 0xE0) - break; - if ((pkt[41] & 0xF0) != 0xC0) - break; - if (pkt[40] & 2) - goto traulike_bfi; - fwrite(pkt + 41, 1, 31, outfile); - return; - case 33: - if ((pkt[40] & 0xF0) != 0xD0) - break; - goto emit_payload; - case 34: - if ((pkt[40] & 0xF4) != 0xE0) - break; - if ((pkt[41] & 0xF0) != 0xD0) - break; - if (pkt[40] & 2) - goto traulike_bfi; - fwrite(pkt + 41, 1, 33, outfile); - return; - } - fprintf(stderr, "error in packet #%u: unsupported payload\n", pkt_idx); - exit(1); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx; - - if (argc != 6) { - fprintf(stderr, - "usage: %s pcap-file src|dest ip-addr udp-port outfile\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - if (!strcmp(argv[2], "src")) { - iphdr_addr_offset = 12; - udphdr_port_offset = 0; - } else if (!strcmp(argv[2], "dest")) { - iphdr_addr_offset = 16; - udphdr_port_offset = 2; - } else { - fprintf(stderr, - "error: direction argument must be \"src\" or \"dest\"\n"); - exit(1); - } - match_ip_addr = inet_addr(argv[3]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[4], 0, 0)); - outfile = fopen(argv[5], "w"); - if (!outfile) { - perror(argv[5]); - exit(1); - } - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); - } - if (!stream_init_flag) { - fprintf(stderr, "error: specified RTP stream not found\n"); - exit(1); - } - fclose(outfile); - exit(0); -}
--- a/rtp-jitter-view.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -/* - * This program reads a pcap file, extracts packets belonging to a - * particular RTP stream as identified by a source or destination - * IP:port, checks its continuity at the packet header level - * (verifies that the sequence number always increments by 1 and - * that the timestamp always increments by 160 units) and prints out - * the Rx time delta of each stream packet (the capture time of - * the current packet minus the capture time of the previous packet) - * on stdout, allowing visual analysis of timing jitter. - * - * The codec can be anything, and this program can also be used to - * examine the jitter of RTP streams coming from PSTN/SIP, but the - * core assumption is that packets must arrive every 20 ms, with - * the timestamp field incrementing by 160 units each time. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned iphdr_addr_offset, udphdr_port_offset; -static unsigned link_hdr_len, ethertype_offset; -static int stream_init_flag; -static unsigned last_seq, last_tstamp, stream_ssrc; -static struct timeval last_pkt_time; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx, pkt_time) - u_char *rtp_hdr; - unsigned pkt_idx; - struct timeval *pkt_time; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - struct timeval deltat; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (stream_init_flag) { - if (cur_ssrc != stream_ssrc) { - fprintf(stderr, - "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", - pkt_idx, stream_ssrc, cur_ssrc); - exit(1); - } - if (cur_seq != last_seq + 1 && - (cur_seq != 0 || last_seq != 0xFFFF)) { - fprintf(stderr, - "error in packet #%u: seq break from 0x%04X to 0x%04X\n", - pkt_idx, last_seq, cur_seq); - exit(1); - } - if (cur_tstamp != last_tstamp + 160) { - fprintf(stderr, - "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", - pkt_idx, last_tstamp, cur_tstamp); - exit(1); - } - if (timercmp(pkt_time, &last_pkt_time, <)) { - fprintf(stderr, - "packet #%u timing error: Rx time goes backward\n", - pkt_idx); - exit(1); - } - timersub(pkt_time, &last_pkt_time, &deltat); - if (deltat.tv_sec) { - fprintf(stderr, - "packet #%u timing error: Rx time gap >= 1 s\n", - pkt_idx); - exit(1); - } - printf("Packet #%u: time delta %u us\n", pkt_idx, - (unsigned) deltat.tv_usec); - } else { - stream_init_flag = 1; - stream_ssrc = cur_ssrc; - } - last_seq = cur_seq; - last_tstamp = cur_tstamp; - bcopy(pkt_time, &last_pkt_time, sizeof(struct timeval)); -} - -static void -process_packet(pkt, caplen, pkt_idx, pkt_time) - u_char *pkt; - unsigned caplen, pkt_idx; - struct timeval *pkt_time; -{ - unsigned udplen; - - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) - return; - /* check UDP header */ - if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) - return; - /* it is our target - now scrutinize it */ - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - fprintf(stderr, - "error: packet #%u is truncated in the capture\n", - pkt_idx); - exit(1); - } - if (udplen < 20) { - fprintf(stderr, - "error in packet #%u: UDP length is too short for RTP header\n", - pkt_idx); - exit(1); - } - if (pkt[28] != 0x80) { - fprintf(stderr, - "error in packet #%u: unsupported RTP header structure\n", - pkt_idx); - exit(1); - } - rtp_stream_logic(pkt + 28, pkt_idx, pkt_time); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx; - - if (argc != 5) { - fprintf(stderr, - "usage: %s pcap-file src|dest ip-addr udp-port\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - if (!strcmp(argv[2], "src")) { - iphdr_addr_offset = 12; - udphdr_port_offset = 0; - } else if (!strcmp(argv[2], "dest")) { - iphdr_addr_offset = 16; - udphdr_port_offset = 2; - } else { - fprintf(stderr, - "error: direction argument must be \"src\" or \"dest\"\n"); - exit(1); - } - match_ip_addr = inet_addr(argv[3]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[4], 0, 0)); - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx, - &pkthdr.ts); - } - if (!stream_init_flag) { - fprintf(stderr, "error: specified RTP stream not found\n"); - exit(1); - } - exit(0); -}
--- a/rtp-stream-dump.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * This program is an aid for analyzing arbitrary RTP streams: - * it reads a pcap file, extracts packets belonging to a particular - * RTP stream as identified by a source or destination IP:port, - * and displays a one-line summary of every RTP packet. - * Discontinuities are treated as non-fatal errors: an error message - * is printed, but analysis continues. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned iphdr_addr_offset, udphdr_port_offset; -static unsigned link_hdr_len, ethertype_offset; -static int stream_init_flag; -static unsigned last_seq, last_tstamp, stream_ssrc; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx) - u_char *rtp_hdr; - unsigned pkt_idx; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (stream_init_flag) { - if (cur_ssrc != stream_ssrc) { - printf( - "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n", - pkt_idx, stream_ssrc, cur_ssrc); - } else if (cur_seq != last_seq + 1 && - (cur_seq != 0 || last_seq != 0xFFFF)) { - printf( - "error in packet #%u: seq break from 0x%04X to 0x%04X\n", - pkt_idx, last_seq, cur_seq); - } else if (cur_tstamp != last_tstamp + 160) { - printf( - "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n", - pkt_idx, last_tstamp, cur_tstamp); - } - } else - stream_init_flag = 1; - last_seq = cur_seq; - last_tstamp = cur_tstamp; - stream_ssrc = cur_ssrc; -} - -static void -process_packet(pkt, caplen, pkt_idx) - u_char *pkt; - unsigned caplen, pkt_idx; -{ - unsigned udplen, payload_len; - - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4)) - return; - /* check UDP header */ - if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2)) - return; - /* it is our target - now scrutinize it */ - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - fprintf(stderr, - "error: packet #%u is truncated in the capture\n", - pkt_idx); - exit(1); - } - if (udplen < 20) { - fprintf(stderr, - "error in packet #%u: UDP length is too short for RTP header\n", - pkt_idx); - exit(1); - } - if (pkt[28] != 0x80) { - fprintf(stderr, - "error in packet #%u: unsupported RTP header structure\n", - pkt_idx); - exit(1); - } - rtp_stream_logic(pkt + 28, pkt_idx); - printf("pkt #%u seq 0x%04X ts 0x%08X: pt=%u M=%u len=%u\n", pkt_idx, - last_seq, last_tstamp, pkt[29] & 0x7F, pkt[29] >> 7, - udplen - 20); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx; - - if (argc != 5) { - fprintf(stderr, - "usage: %s pcap-file src|dest ip-addr udp-port\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - if (!strcmp(argv[2], "src")) { - iphdr_addr_offset = 12; - udphdr_port_offset = 0; - } else if (!strcmp(argv[2], "dest")) { - iphdr_addr_offset = 16; - udphdr_port_offset = 2; - } else { - fprintf(stderr, - "error: direction argument must be \"src\" or \"dest\"\n"); - exit(1); - } - match_ip_addr = inet_addr(argv[3]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[4], 0, 0)); - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); - } - if (!stream_init_flag) { - fprintf(stderr, "error: specified RTP stream not found\n"); - exit(1); - } - exit(0); -}
--- a/rtp-stream-gen.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/* - * This program generates a dummy RTP stream, sending RTP packets with - * a dummy payload to the specified destination IP:port, paced in time - * every 20 ms. The purpose is to test the behaviour of affordably-available - * Internet connections when presented with such traffic: the intent is - * to capture this packet stream on the receiving end with tcpdump and then - * analyze the pcap for problem signs of packet loss, jitter and reordering. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> - -#define RTP_PACKET_HDR_SIZE 12 -#define RTP_MAX_PAYLOAD 160 -#define GSM_FR_BYTES 33 - -struct rtp_packet { - uint8_t v_p_x_cc; - uint8_t m_pt; - uint16_t seq; - uint32_t tstamp; - uint32_t ssrc; - uint8_t payload[RTP_MAX_PAYLOAD]; -}; - -static const uint8_t gsmfr_silence_frame[GSM_FR_BYTES] = { - 0xDA, 0xA7, 0xAA, 0xA5, 0x1A, - 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, - 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, - 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, - 0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B, -}; - -static struct sockaddr_in sin_src, sin_dest; -static struct rtp_packet rtp_pkt; -static unsigned rtp_pkt_len, req_packet_count; -static int udp_fd; - -static void -parse_ip_port(arg, sin) - char *arg; - struct sockaddr_in *sin; -{ - char *cp; - int rc; - - cp = index(arg, ':'); - if (!cp) { - fprintf(stderr, "error: missing ':' in IP:port argument\n"); - exit(1); - } - *cp++ = '\0'; - sin->sin_family = AF_INET; - rc = inet_aton(arg, &sin->sin_addr); - if (!rc) { - fprintf(stderr, "error: invalid IP address argument\n"); - exit(1); - } - sin->sin_port = htons(atoi(cp)); -} - -static void -prepare_rtp_payload(type_arg) - char *type_arg; -{ - unsigned pl_len; - - if (!strcmp(type_arg, "pcmu")) { - rtp_pkt.m_pt = 0; - memset(rtp_pkt.payload, 0xFF, RTP_MAX_PAYLOAD); - pl_len = RTP_MAX_PAYLOAD; - } else if (!strcmp(type_arg, "pcma")) { - rtp_pkt.m_pt = 8; - memset(rtp_pkt.payload, 0xD5, RTP_MAX_PAYLOAD); - pl_len = RTP_MAX_PAYLOAD; - } else if (!strcmp(type_arg, "gsm")) { - rtp_pkt.m_pt = 3; - memcpy(rtp_pkt.payload, gsmfr_silence_frame, GSM_FR_BYTES); - pl_len = GSM_FR_BYTES; - } else { - fprintf(stderr, "error: invalid PL type argument \"%s\"\n", - type_arg); - exit(1); - } - rtp_pkt_len = RTP_PACKET_HDR_SIZE + pl_len; -} - -static void -assign_rtpout_ssrc() -{ - struct timeval curtime; - - gettimeofday(&curtime, 0); - rtp_pkt.ssrc = curtime.tv_sec ^ curtime.tv_usec ^ getpid(); -} - -static void -prepare_udp_socket() -{ - int rc; - - udp_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (udp_fd < 0) { - perror("socket(AF_INET, SOCK_DGRAM, 0)"); - exit(1); - } - rc = bind(udp_fd, (struct sockaddr *) &sin_src, sizeof sin_src); - if (rc < 0) { - perror("bind"); - exit(1); - } - rc = connect(udp_fd, (struct sockaddr *) &sin_dest, sizeof sin_dest); - if (rc < 0) { - perror("connect"); - exit(1); - } -} - -static void -send_out_packets() -{ - unsigned n, seq, ts; - - seq = 0; - ts = 0; - for (n = 0; n < req_packet_count; n++) { - rtp_pkt.seq = htons(seq); - rtp_pkt.tstamp = htonl(ts); - send(udp_fd, &rtp_pkt, rtp_pkt_len, 0); - seq++; - ts += 160; - usleep(20000); - } -} - -main(argc, argv) - char **argv; -{ - if (argc != 5) { - fprintf(stderr, "usage: %s src-IP:port dest-IP:port type num\n", - argv[0]); - exit(1); - } - parse_ip_port(argv[1], &sin_src); - parse_ip_port(argv[2], &sin_dest); - prepare_rtp_payload(argv[3]); - rtp_pkt.v_p_x_cc = 0x80; - assign_rtpout_ssrc(); - req_packet_count = atoi(argv[4]); - prepare_udp_socket(); - send_out_packets(); - exit(0); -}
--- a/rtp-tfo-trace.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * This program reads a pcap file containing RTP packets of a PSTN call - * (PCMU or PCMA, 160 samples per RTP packet), flowing in one or both - * directions, and looks for TFO IS messages. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <pcap/pcap.h> - -static pcap_t *pcap; -static in_addr_t match_ip_addr; -static u_short match_udp_port; -static unsigned link_hdr_len, ethertype_offset; - -static struct onedir { - int init_flag; - unsigned last_seq; - unsigned last_tstamp; - unsigned stream_ssrc; - u_char is_hunt_buf[320]; - int is_state; - unsigned is_hunt_fill; - unsigned is_offset; - unsigned is_alignment; - unsigned is_bit_count; - unsigned is_rx_word; -} rx_state, tx_state; - -static const u_char hdr_pattern[20] = {0, 1, 0, 1, 0, 1, 1, 0, 1, 0, - 0, 1, 1, 0, 1, 0, 1, 0, 0, 1}; - -static void -check_dl_type() -{ - int dltype; - - dltype = pcap_datalink(pcap); - switch (dltype) { - case DLT_EN10MB: - link_hdr_len = 14; - ethertype_offset = 12; - break; - case DLT_RAW: - link_hdr_len = 0; - break; - case DLT_LINUX_SLL: - link_hdr_len = 16; - ethertype_offset = 14; - break; - default: - fprintf(stderr, "error: unsupported data link type %d\n", - dltype); - exit(1); - } -} - -static void -rtp_stream_logic(rtp_hdr, pkt_idx, st, dir_str) - u_char *rtp_hdr; - unsigned pkt_idx; - struct onedir *st; - char *dir_str; -{ - unsigned cur_seq, cur_tstamp, cur_ssrc; - - cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3]; - cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) | - (rtp_hdr[6] << 8) | rtp_hdr[7]; - cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) | - (rtp_hdr[10] << 8) | rtp_hdr[11]; - if (st->init_flag) { - if (cur_ssrc != st->stream_ssrc) { - printf( - "error in %s packet #%u: SSRC change from 0x%08X to 0x%08X\n", - dir_str, pkt_idx, st->stream_ssrc, cur_ssrc); - } else if (cur_seq != st->last_seq + 1 && - (cur_seq != 0 || st->last_seq != 0xFFFF)) { - printf( - "error in %s packet #%u: seq break from 0x%04X to 0x%04X\n", - dir_str, pkt_idx, st->last_seq, cur_seq); - } else if (cur_tstamp != st->last_tstamp + 160) { - printf( - "error in %s packet #%u: timestamp break from 0x%08X to 0x%08X\n", - dir_str, pkt_idx, st->last_tstamp, cur_tstamp); - } - } else - st->init_flag = 1; - st->last_seq = cur_seq; - st->last_tstamp = cur_tstamp; - st->stream_ssrc = cur_ssrc; -} - -static void -is_rx_hunt(input_pos, pkt_idx, st, dir_str) - unsigned input_pos; - unsigned pkt_idx; - struct onedir *st; - char *dir_str; -{ - unsigned offset, n; - - for (offset = 0; offset < 16; offset++) { - for (n = 0; n < 20; n++) - if ((st->is_hunt_buf[offset + n*16] & 1) != - hdr_pattern[n]) - break; - if (n == 20) - break; - } - if (n != 20) - return; - st->is_offset = offset; - st->is_alignment = input_pos * 16 + offset; - st->is_state = 1; - st->is_bit_count = 0; - st->is_rx_word = 0; - st->is_hunt_fill = 0; -} - -static void -is_process_cmd(pkt_idx, st, dir_str) - unsigned pkt_idx; - struct onedir *st; - char *dir_str; -{ - int cont; - - printf("#%u: %s (align %u) ", pkt_idx, dir_str, st->is_alignment); - switch (st->is_rx_word) { - case 0x05D: - printf("IS_REQ\n"); - cont = 1; - break; - case 0x0BA: - printf("IS_ACK\n"); - cont = 1; - break; - case 0x0E7: - printf("IS_IPE\n"); - cont = 1; - break; - case 0x129: - printf("IS_FILL\n"); - cont = 0; - break; - case 0x174: - printf("IS_DUP\n"); - cont = 0; - break; - case 0x193: - printf("IS_SYL\n"); - cont = 0; - break; - default: - printf("Unknown IS_Command 0x%03X\n", st->is_rx_word); - cont = 0; - } - if (cont) { - st->is_state = 2; - st->is_bit_count = 0; - st->is_rx_word = 0; - } else - st->is_state = 0; -} - -static void -is_process_ext(pkt_idx, st, dir_str) - unsigned pkt_idx; - struct onedir *st; - char *dir_str; -{ - printf("#%u: %s IS_Extension: 0x%05X", pkt_idx, dir_str, - st->is_rx_word); - if (st->is_rx_word & 0x80200) { - printf(" (bad sync)\n"); - st->is_state = 0; - return; - } - switch (st->is_rx_word & 3) { - case 0: - printf(" (final)\n"); - st->is_state = 0; - return; - case 3: - printf(" (continue)\n"); - st->is_state = 2; - st->is_bit_count = 0; - st->is_rx_word = 0; - return; - default: - printf(" (bad EX)\n"); - st->is_state = 0; - } -} - -static void -is_rx_process(input, input_pos, pkt_idx, st, dir_str) - uint8_t *input; - unsigned input_pos; - unsigned pkt_idx; - struct onedir *st; - char *dir_str; -{ - unsigned new_bit; - - memmove(st->is_hunt_buf, st->is_hunt_buf + 16, 304); - memcpy(st->is_hunt_buf + 304, input, 16); - if (!st->is_state) { - if (st->is_hunt_fill < 20) - st->is_hunt_fill++; - if (st->is_hunt_fill == 20) - is_rx_hunt(input_pos, pkt_idx, st, dir_str); - return; - } - new_bit = input[st->is_offset] & 1; - st->is_rx_word <<= 1; - st->is_rx_word |= new_bit; - st->is_bit_count++; - if (st->is_state == 1 && st->is_bit_count == 10) - is_process_cmd(pkt_idx, st, dir_str); - else if (st->is_state == 2 && st->is_bit_count == 20) - is_process_ext(pkt_idx, st, dir_str); -} - -static void -process_packet_onedir(pkt, caplen, pkt_idx, st, dir_str) - u_char *pkt; - unsigned caplen, pkt_idx; - struct onedir *st; - char *dir_str; -{ - unsigned udplen, payload_len; - unsigned is_chunk; - - udplen = (pkt[24] << 8) | pkt[25]; - if (caplen < udplen + 20) { - printf("error: %s packet #%u is truncated in the capture\n", - dir_str, pkt_idx); - return; - } - if (udplen < 20) { - printf( - "error in %s packet #%u: UDP length is too short for RTP header\n", - dir_str, pkt_idx); - return; - } - if (pkt[28] != 0x80) { - printf( - "error in %s packet #%u: unsupported RTP header structure\n", - dir_str, pkt_idx); - return; - } - rtp_stream_logic(pkt + 28, pkt_idx, st, dir_str); - payload_len = udplen - 20; - if (payload_len != 160) { - printf("error in %s packet #%u: wrong payload length\n", - dir_str, pkt_idx); - return; - } - for (is_chunk = 0; is_chunk < 10; is_chunk++) - is_rx_process(pkt + 40 + is_chunk * 16, is_chunk, pkt_idx, st, - dir_str); -} - -static void -process_packet(pkt, caplen, pkt_idx) - u_char *pkt; - unsigned caplen, pkt_idx; -{ - if (caplen < link_hdr_len + 28) - return; - if (link_hdr_len) { - if (pkt[ethertype_offset] != 0x08) - return; - if (pkt[ethertype_offset+1] != 0x00) - return; - pkt += link_hdr_len; - caplen -= link_hdr_len; - } - /* check IP header */ - if (pkt[0] != 0x45) - return; - if (pkt[9] != 17) /* UDP */ - return; - if (!bcmp(pkt + 12, &match_ip_addr, 4) && - !bcmp(pkt + 20, &match_udp_port, 2)) - process_packet_onedir(pkt, caplen, pkt_idx, &tx_state, "-->"); - else if (!bcmp(pkt + 16, &match_ip_addr, 4) && - !bcmp(pkt + 22, &match_udp_port, 2)) - process_packet_onedir(pkt, caplen, pkt_idx, &rx_state, "<--"); -} - -main(argc, argv) - char **argv; -{ - char errbuf[PCAP_ERRBUF_SIZE]; - u_char *pkt; - struct pcap_pkthdr pkthdr; - unsigned pkt_idx; - - if (argc != 4) { - fprintf(stderr, "usage: %s pcap-file ip-addr udp-port\n", - argv[0]); - exit(1); - } - pcap = pcap_open_offline(argv[1], errbuf); - if (!pcap) { - fprintf(stderr, "%s: %s\n", argv[1], errbuf); - exit(1); - } - check_dl_type(); - match_ip_addr = inet_addr(argv[2]); - if (match_ip_addr == INADDR_NONE) { - fprintf(stderr, "error: IP address argument is invalid\n"); - exit(1); - } - match_udp_port = htons(strtoul(argv[3], 0, 0)); - for (pkt_idx = 0; ; pkt_idx++) { - pkt = pcap_next(pcap, &pkthdr); - if (!pkt) - break; - process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx); - } - if (!tx_state.init_flag) - printf( - "Warning: found no packets with src matching specified IP:port\n"); - if (!rx_state.init_flag) - printf( - "Warning: found no packets with dest matching specified IP:port\n"); - exit(0); -}
--- a/udp-test-sink.c Sun Mar 10 02:27:37 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * This program is a simple sink for UDP: it binds to a UDP port and sinks - * (reads and discards) all packets that arrive at it. Upon receiving a - * burst or stream of packets followed by a prolonged pause, it prints - * the number of packets that were received. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/errno.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> - -static void -parse_ip_port(arg, sin) - char *arg; - struct sockaddr_in *sin; -{ - char *cp; - int rc; - - cp = index(arg, ':'); - if (!cp) { - fprintf(stderr, "error: missing ':' in IP:port argument\n"); - exit(1); - } - *cp++ = '\0'; - sin->sin_family = AF_INET; - rc = inet_aton(arg, &sin->sin_addr); - if (!rc) { - fprintf(stderr, "error: invalid IP address argument\n"); - exit(1); - } - sin->sin_port = htons(atoi(cp)); -} - -main(argc, argv) - char **argv; -{ - struct sockaddr_in bindsin; - int udp_fd, rc; - unsigned idle_sec, rx_count; - fd_set fds; - struct timeval tv; - u_char dummybuf[256]; - - if (argc < 2 || argc > 3) { - fprintf(stderr, "usage: bind-IP:port [idle-sec]\n", argv[0]); - exit(1); - } - parse_ip_port(argv[1], &bindsin); - if (argc >= 3) - idle_sec = atoi(argv[2]); - else - idle_sec = 0; - udp_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (udp_fd < 0) { - perror("socket(AF_INET, SOCK_DGRAM, 0)"); - exit(1); - } - rc = bind(udp_fd, (struct sockaddr *) &bindsin, sizeof bindsin); - if (rc < 0) { - perror("bind"); - exit(1); - } - for (rx_count = 0; ; ) { - FD_ZERO(&fds); - FD_SET(udp_fd, &fds); - if (rx_count && idle_sec) { - tv.tv_sec = idle_sec; - tv.tv_usec = 0; - rc = select(udp_fd+1, &fds, 0, 0, &tv); - } else - rc = select(udp_fd+1, &fds, 0, 0, 0); - if (rc < 0) { - if (errno == EINTR) - continue; - perror("select"); - exit(1); - } - if (FD_ISSET(udp_fd, &fds)) { - recv(udp_fd, dummybuf, sizeof dummybuf, 0); - rx_count++; - } else { - printf("Received %u packet%s\n", rx_count, - rx_count != 1 ? "s" : ""); - rx_count = 0; - } - } -}