mirror of https://github.com/sipwise/rtpengine.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
4.2 KiB
180 lines
4.2 KiB
#!/usr/bin/perl
|
|
|
|
# Usage: $0 <file> [payload type num] [payload type str]
|
|
# Ex: $0 foo.pcap
|
|
# Ex: $0 foo.pcap 97 opus/48000
|
|
use strict;
|
|
use warnings;
|
|
use Net::Pcap;
|
|
use Data::Dumper;
|
|
use Time::HiRes qw(usleep);
|
|
|
|
my $spool_dir = '/var/spool/rtpengine';
|
|
my $table = 0;
|
|
|
|
my $kfd;
|
|
open($kfd, '+>', "/proc/rtpengine/$table/control") or die $!;
|
|
|
|
my $err;
|
|
my $p = pcap_open_offline($ARGV[0], \$err) or die $err;
|
|
my $linktype = pcap_datalink($p);
|
|
|
|
my @packets;
|
|
my %src_ips;
|
|
my $tags = 0;
|
|
my $streams = 0;
|
|
|
|
print("reading pcap\n");
|
|
my $ret = pcap_loop($p, -1, \&loop_cb, '');
|
|
$ret == 0 or die $ret;
|
|
|
|
my $meta_file = "$spool_dir/" . rand() . '.meta';
|
|
|
|
my $parent = rand();
|
|
|
|
print("adding kernel call\n");
|
|
my (undef, $cid) = msg_ret(5, '', 'I I', 'I a256', 0, $parent);
|
|
print("kernel cid $cid\n");
|
|
|
|
print("starting metafile\n");
|
|
put_meta('CALL-ID', rand());
|
|
put_meta('PARENT', $parent);
|
|
|
|
print("creating kernel streams\n");
|
|
my @sids;
|
|
my @tag_keys = keys(%src_ips);
|
|
for my $key (@tag_keys) {
|
|
my $tag = $src_ips{$key};
|
|
my $tag_id = $tag->{id};
|
|
put_meta("TAG $tag_id", rand());
|
|
my @port_keys = keys(%{$tag->{ports}});
|
|
for my $port (@port_keys) {
|
|
my $stream = $tag->{ports}->{$port};
|
|
my $sname = "tag-$tag_id-media-$stream->{media_id}-".
|
|
"component-$stream->{component}-xxx-id-$stream->{stream_id}";
|
|
put_meta("STREAM $stream->{stream_id} details",
|
|
"TAG $tag_id MEDIA $stream->{media_id} COMPONENT $stream->{component} ".
|
|
"FLAGS 0");
|
|
if ($ARGV[2]) {
|
|
if ($ARGV[3]) {
|
|
put_meta("MEDIA $stream->{media_id} PTIME $ARGV[3]", '');
|
|
}
|
|
put_meta("MEDIA $stream->{media_id} PAYLOAD TYPE $ARGV[1]", $ARGV[2]);
|
|
}
|
|
my @ret = msg_ret(7, '', 'I I I I',
|
|
'I I I a256', $cid, 0, 0, $sname);
|
|
my $sid = $ret[3];
|
|
$stream->{sid} = $sid;
|
|
print("kernel sid $sid\n");
|
|
put_meta("STREAM $stream->{stream_id} interface", $sname);
|
|
push(@sids, $sid);
|
|
}
|
|
}
|
|
|
|
print("sending packets\n");
|
|
foreach my $pack (@packets) {
|
|
msg_ret(9, $pack->{eth}->{rest}, '', 'I I', $cid, $pack->{media}->{sid});
|
|
usleep(5000);
|
|
}
|
|
|
|
print("deleting call and metafile\n");
|
|
msg_ret(6, '', '', 'I', $cid);
|
|
unlink($meta_file);
|
|
|
|
print("done\n");
|
|
exit;
|
|
|
|
sub loop_cb {
|
|
my ($user_data, $header, $packet) = @_;
|
|
my %eth;
|
|
if ($linktype == DLT_EN10MB) {
|
|
@eth{qw(src dst type rest)} = unpack('a6 a6 n a*', $packet);
|
|
}
|
|
elsif ($linktype == DLT_LINUX_SLL) {
|
|
@eth{qw(direction arphdr addrlen addr type rest)} = unpack('nnn a8 n a*', $packet);
|
|
}
|
|
else {
|
|
die($linktype);
|
|
}
|
|
if ($eth{type} == 0x0800) {
|
|
my $ip = ip($eth{rest});
|
|
my $rtp = rtp($ip->{udp}->{payload});
|
|
|
|
my %pkt = ( eth => \%eth, ip => $ip, rtp => $rtp );
|
|
|
|
my $src_ip = $ip->{src};
|
|
my $tag = ($src_ips{$src_ip} //= {
|
|
id => $tags++,
|
|
ports => { },
|
|
medias => 0,
|
|
});
|
|
$pkt{tag} = $tag;
|
|
|
|
my $component = $ip->{udp}->{src} & 1;
|
|
my $base_port = $ip->{udp}->{src} - $component;
|
|
my $base_media = ($tag->{ports}->{$base_port} //= {
|
|
media_id => $tag->{medias}++,
|
|
component => 0,
|
|
stream_id => $streams++,
|
|
});
|
|
|
|
my $media = ($tag->{ports}->{$ip->{udp}->{src}} //= {
|
|
media_id => $base_media->{media_id},
|
|
component => $component,
|
|
stream_id => $streams++,
|
|
});
|
|
$pkt{media} = $media;
|
|
|
|
push(@packets, \%pkt);
|
|
}
|
|
else {
|
|
die($eth{type});
|
|
}
|
|
}
|
|
|
|
sub ip {
|
|
my ($p) = @_;
|
|
my %ret;
|
|
@ret{qw(hv diffserv totlen id flags_foff ttl proto csum src dst rest)} = unpack('C C n n n C C n N N a*', $p);
|
|
if ($ret{proto} == 17) {
|
|
$ret{udp} = udp($ret{rest});
|
|
}
|
|
else {
|
|
die $ret{proto};
|
|
}
|
|
return \%ret;
|
|
}
|
|
|
|
sub udp {
|
|
my ($p) = @_;
|
|
my %ret;
|
|
@ret{qw(src dst len csum payload)} = unpack('nnnn a*', $p);
|
|
return \%ret;
|
|
}
|
|
|
|
sub rtp {
|
|
my ($p) = @_;
|
|
my %ret;
|
|
@ret{qw(vpx pt seq ts ssrc payload)} = unpack('CC n N N', $p);
|
|
return \%ret;
|
|
}
|
|
|
|
sub put_meta {
|
|
my ($label, $content) = @_;
|
|
my $fd;
|
|
open($fd, '>>', $meta_file) or die $!;
|
|
print $fd "$label\n" . length($content) . ":\n$content\n\n";
|
|
close($fd);
|
|
}
|
|
|
|
sub msg_ret {
|
|
my ($cmd, $extra, $unpacker, $packer, @rest) = @_;
|
|
my $msg = pack('II' . $packer, $cmd, 0, @rest);
|
|
# for 32-bit:
|
|
# my $msg = pack('I' . $packer, $cmd, @rest);
|
|
$msg .= ("\0" x (840 - length($msg))); # packet length also needs adjusting for 32-bit
|
|
$msg .= ($extra // '');
|
|
sysread($kfd, $msg, length($msg)) or die $!;
|
|
return unpack($unpacker, $msg);
|
|
}
|