From 7249bab0d179c49ac37a899a87b68ff3d0a26a4e Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Wed, 3 Jul 2013 09:44:18 +0200 Subject: [PATCH] Initial version. One single start point: run_test.sh Each test on its directory. Normalized filenames. --- check.py | 131 +++++++++++++++ config_debug.pl | 26 +++ create_domain.pl | 62 +++++++ create_subscribers.pl | 115 +++++++++++++ delete_domain.pl | 62 +++++++ graph_flow.pl | 60 +++++++ restart_log.sh | 6 + run_tests.sh | 28 ++++ scenarios/callee.csv | 2 + scenarios/caller.csv | 2 + scenarios/check.sh | 122 ++++++++++++++ scenarios/invite_offline/0001_test.yml | 27 +++ scenarios/invite_offline/0003_test.yml | 80 +++++++++ scenarios/invite_offline/0005_test.yml | 76 +++++++++ scenarios/invite_offline/sipp_scenario.xml | 164 +++++++++++++++++++ scenarios/register/0001_test.yml | 25 +++ scenarios/register/0002_test.yml | 30 ++++ scenarios/register/sipp_scenario.xml | 55 +++++++ scenarios/register_allowip/0001_test.yml | 27 +++ scenarios/register_allowip/0002_test.yml | 84 ++++++++++ scenarios/register_allowip/prefs.yml | 2 + scenarios/register_allowip/sipp_scenario.xml | 55 +++++++ set_subscribers_preferences.pl | 71 ++++++++ show_flow.pl | 23 +++ sipp.sh | 14 ++ ulog_parser.pl | 106 ++++++++++++ 26 files changed, 1455 insertions(+) create mode 100755 check.py create mode 100755 config_debug.pl create mode 100755 create_domain.pl create mode 100755 create_subscribers.pl create mode 100755 delete_domain.pl create mode 100755 graph_flow.pl create mode 100755 restart_log.sh create mode 100755 run_tests.sh create mode 100644 scenarios/callee.csv create mode 100644 scenarios/caller.csv create mode 100755 scenarios/check.sh create mode 100644 scenarios/invite_offline/0001_test.yml create mode 100644 scenarios/invite_offline/0003_test.yml create mode 100644 scenarios/invite_offline/0005_test.yml create mode 100644 scenarios/invite_offline/sipp_scenario.xml create mode 100644 scenarios/register/0001_test.yml create mode 100644 scenarios/register/0002_test.yml create mode 100644 scenarios/register/sipp_scenario.xml create mode 100644 scenarios/register_allowip/0001_test.yml create mode 100644 scenarios/register_allowip/0002_test.yml create mode 100644 scenarios/register_allowip/prefs.yml create mode 100644 scenarios/register_allowip/sipp_scenario.xml create mode 100755 set_subscribers_preferences.pl create mode 100755 show_flow.pl create mode 100755 sipp.sh create mode 100755 ulog_parser.pl diff --git a/check.py b/check.py new file mode 100755 index 00000000..b08e2597 --- /dev/null +++ b/check.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +import io, sys, re +from yaml import load +from pprint import pprint +try: + from yaml import CLoader as Loader +except: + from yaml import Loader + +class Test: + """ Class to create TAP output """ + _step = [] + _errflag = False + + def comment(self, msg): + """ Add a comment """ + self._step.append({'result': None, 'msg_ok': msg}) + + def ok(self, msg = None): + """ Add a ok result """ + self._step.append({'result': True, 'msg_ok': msg}) + + def error(self, msg_err): + """ Add an error result""" + self._step.append({'result': False, 'msg_err': msg_err}) + self._errflag = True + + def test(self, value_expected, value, msg_err, msg_ok = None): + """ Test two values and add the result""" + result = (value_expected == value) + self._step.append({'result': result, 'msg_err': msg_err, 'msg_ok': msg_ok}) + if not result: + self._errflag = True + + def isError(self): + return self._errflag + + def _num_tests(self): + """get the num of tests""" + test = 0 + for s in self._step: + if (s['result'] is not None): + test = test + 1 + return test + + def __str__(self): + """get the TAP output""" + output = "1..%s\n" % self._num_tests() + test = 1 + for s in self._step: + if (s['result'] is None): + output += '# %s\n' % s['msg_ok'] + continue + elif (s['result']): + if (s['msg_ok'] is not None): + output += "ok %d - %s\n" % (test, s['msg_ok']) + else: + output += "ok %d\n" % test + else: + output += "not ok %d - %s\n" % (test, s['msg_err']) + test = test + 1 + return output + +def check_flow(scen, check, test): + """ checks the flow and the vars inside""" + for i in range(len(scen)): + (sk, sv) = scen[i].popitem() + try: + (ck, cv) = check[i].popitem() + except: + test.error('wrong flow. Expected: %s but is nothing there' % sk) + continue + if(sk != ck): + test.error('wrong flow. Expected: %s but is %s' % (sk, ck)) + continue + if sv is None: + test.ok('flow[%s] no var to check' % sk) + continue + else: + test.ok('flow[%s]' % sk) + for k in sv.iterkeys(): + if(not cv.has_key(k)): + test.error('Expected var %d on flow[%s]' % (k,sk)) + else: + test.test(sv[k], cv[k], 'flow[%s] expected %s == %s but is %s' % (sk, k, sv[k], cv[k]), 'flow[%s] %s' % (sk, k)) + if(len(check)>len(scen)): + l = [] + for i in check: + for k in i.keys(): + l.append(k) + test.error('Expected to end but there are more flows %s' % l) + +def check_sip(scen, msg, test): + for rule in scen: + result = re.search(rule, msg) + if result is not None: + test.ok('%s match' % rule) + continue + test.error('%s not match' % rule) + +def check_sip_out(scen, msgs, test): + num_msgs = len(msgs) + for i in (range(len(scen))): + if(inew; +my $file = "/etc/ngcp-config/config.yml"; + +$yaml = YAML::Tiny->read($file) or die "File $file could not be read"; + + +if ($#ARGV eq 0 && lc($ARGV[0]) eq "off") +{ + $yaml->[0]->{kamailio}{lb}{debug} = 'no'; + $yaml->[0]->{kamailio}{proxy}{debug} = 'no'; + $yaml->[0]->{checktools}{sip_check_enable} = 1; +} +else +{ + $yaml->[0]->{kamailio}{lb}{debug} = 'no'; + $yaml->[0]->{kamailio}{proxy}{debug} = 'yes'; + $yaml->[0]->{checktools}{sip_check_enable} = 0; +} +open(my $fh, '>', "$file") or die "Could not open $file for writing"; +print $fh $yaml->write_string() or die "Could not write YAML to $file"; diff --git a/create_domain.pl b/create_domain.pl new file mode 100755 index 00000000..7d8bdb52 --- /dev/null +++ b/create_domain.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Data::Dumper; +use Getopt::Std; +use Sipwise::Provisioning::Billing; + +our %CONFIG = ( + admin => 'administrator', + password => 'administrator', + ); + +die usage() unless ($#ARGV == 0); + +sub main { + my ($bprov) = @_; + call_prov( $bprov, 'create_domain', + { + domain => $ARGV[0] + } + ); + exit; +} + +sub call_prov { + # scalar, scalar, hash-ref + my ($bprov, $function, $parameter) = @_; + my $result; + + eval { + $result = $bprov->handle_request( $function, + { + authentication => { + type => 'admin', + username => $CONFIG{admin}, + password => $CONFIG{password}, + }, + parameters => $parameter, + }); + }; + + if($@) { + if(ref $@ eq 'SOAP::Fault') { + die "Billing\::$function failed: ". $@->faultstring; + } else { + die "Billing\::$function failed: $@"; + } + } + + return $result; +} + +sub usage { + die "Usage:\n$0 \n". + "\ne.g.: $0 sip.sipwise.com\n"; +} + +my $bprov = Sipwise::Provisioning::Billing->new(); + +main($bprov); + diff --git a/create_subscribers.pl b/create_subscribers.pl new file mode 100755 index 00000000..ef1f689d --- /dev/null +++ b/create_subscribers.pl @@ -0,0 +1,115 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Data::Dumper; +use Getopt::Std; +use Sipwise::Provisioning::Billing; + +our %CONFIG = ( + admin => 'administrator', + password => 'administrator', + ); +our %BILLING = ( +# product => 'handle', + billing_profile => 'default', + ); + +sub usage { + die "Usage:\n$0 -v <#accounts> -s <#subscribers> -d -u -c -a -n [-p ]\n". + "\ne.g.: $0 -v 200 -s 5 -d sip.sipwise.com -u test -a 720 -n 555000\n\n". + "Options:\n". + " -v <#accounts> how many voip accounts to create\n". + " -s <#subscribers> number of subscribers per voip account\n". + " -d existing domain for subscribers\n". + " -u prefix number with this string for SIP usernames\n". + " -c country code for subscriber numbers\n". + " -a area code for subscriber numbers\n". + " -n lowest number in available numberblock\n". + " -p static password for all users\n"; +} + +my %opts; +getopts('v:s:d:u:c:a:n:p:', \%opts); + +die usage() unless defined $opts{v} and defined $opts{s} and defined $opts{d} + and defined $opts{u} and defined $opts{a} and defined $opts{n} + and defined $opts{c}; + +sub main { + my ($bprov) = @_; + print "$0 ". scalar(localtime time) . " starting\n"; + + print "\nCreating $opts{v} accounts with $opts{s} subscribers each.\n"; + print "Numbers go from +$opts{c}-$opts{a}-$opts{n} to +$opts{c}-$opts{a}-".($opts{n} + ($opts{v} * $opts{s} - 1))."\n"; + print "$0 ". scalar(localtime time) . " working\n"; + + my $foo = $opts{n}; + my $i = 0; + my $mod = $opts{s}; + $mod *= int(100/$mod) if $mod < 100; + for(1 .. $opts{v}) { + my @subscribers; + for(1 .. $opts{s}) { + push @subscribers, { username => $opts{u} . $foo, + domain => $opts{d}, + password => defined $opts{p} ? $opts{p} : $opts{u} . $foo, + cc => $opts{c}, + ac => $opts{a}, + sn => $foo, + admin => $_ == 1 ? 1 : 0, + }; + + $foo++; + $i++; + } + + call_prov( $bprov, 'create_voip_account', + { + data => { + %BILLING, + subscribers => \@subscribers, + } + } + ); + print "Created $i subscribers.\n" unless $i % $mod; + } + + print "Created $i subscribers.\n" if $i % 100; + print "$0 ". scalar(localtime time) . " finished\n"; + + exit; +} + + +sub call_prov { + # scalar, scalar, hash-ref + my ($bprov, $function, $parameter) = @_; + my $result; + + eval { + $result = $bprov->handle_request( $function, + { + authentication => { + type => 'admin', + username => $CONFIG{admin}, + password => $CONFIG{password}, + }, + parameters => $parameter, + }); + }; + + if($@) { + if(ref $@ eq 'SOAP::Fault') { + die "Billing\::$function failed: ". $@->faultstring; + } else { + die "Billing\::$function failed: $@"; + } + } + + return $result; +} + +my $bprov = Sipwise::Provisioning::Billing->new(); + +main($bprov); + diff --git a/delete_domain.pl b/delete_domain.pl new file mode 100755 index 00000000..0b20c947 --- /dev/null +++ b/delete_domain.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Data::Dumper; +use Getopt::Std; +use Sipwise::Provisioning::Billing; + +our %CONFIG = ( + admin => 'administrator', + password => 'administrator', + ); + +die usage() unless ($#ARGV == 0); + +sub main { + my ($bprov) = @_; + call_prov( $bprov, 'delete_domain', + { + domain => $ARGV[0] + } + ); + exit; +} + +sub call_prov { + # scalar, scalar, hash-ref + my ($bprov, $function, $parameter) = @_; + my $result; + + eval { + $result = $bprov->handle_request( $function, + { + authentication => { + type => 'admin', + username => $CONFIG{admin}, + password => $CONFIG{password}, + }, + parameters => $parameter, + }); + }; + + if($@) { + if(ref $@ eq 'SOAP::Fault') { + die "Billing\::$function failed: ". $@->faultstring; + } else { + die "Billing\::$function failed: $@"; + } + } + + return $result; +} + +sub usage { + die "Usage:\n$0 \n". + "\ne.g.: $0 sip.sipwise.com\n"; +} + +my $bprov = Sipwise::Provisioning::Billing->new(); + +main($bprov); + diff --git a/graph_flow.pl b/graph_flow.pl new file mode 100755 index 00000000..e42dbff5 --- /dev/null +++ b/graph_flow.pl @@ -0,0 +1,60 @@ +#!/usr/bin/env perl +use 5.014; +use strict; +use warnings; +use YAML; +use Cwd 'abs_path'; +use Data::Dumper; +use GraphViz; + +my $g = GraphViz->new(); + +if($#ARGV!=1) +{ + die "usage: show_flow.pl file.yml destfile.png\n"; +} +my $filename = abs_path($ARGV[0]); +my $outfilename = $ARGV[1]; +my $ylog = YAML::LoadFile($filename); + +my @prevs = (); +my $name = ''; +my $action = ''; +my $prev; +my $cont = 1; +$g->add_node(name => 'END', shape =>'box'); + +foreach my $i (@{$ylog->{'flow'}}) +{ + foreach my $key (keys %{$i}) + { + #print "$key\n"; + if(($action, $name) = ($key =~ m/(exit|start|end)\|(\w+)/)) + { + if ($action eq "start") + { + $prev = $prevs[-1]; + + if ($prev) + { + $g->add_node(name => $name); + $g->add_edge( $prev => $name, label => $cont++); + } + else + { + $g->add_node(name => $name, shape=> 'diamond'); + } + push(@prevs, $name); + } + else + { + pop(@prevs); # this is me. + $prev = $prevs[-1]; + if ($action eq "end") { $g->add_edge($name => $prev, label => $cont++); } + else { @prevs = (); $g->add_edge($name => 'END', label => $cont++); } + } + } + } +} +$g->as_png($outfilename); +#EOF diff --git a/restart_log.sh b/restart_log.sh new file mode 100755 index 00000000..b4269d81 --- /dev/null +++ b/restart_log.sh @@ -0,0 +1,6 @@ +#!/bin/sh +#ngcpcfg build /etc/kamailio/proxy/ +invoke-rc.d kamailio-proxy stop +rm -rf /var/log/ngcp/kamailio-proxy.log +invoke-rc.d rsyslog restart +invoke-rc.d kamailio-proxy start diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 00000000..a8805a74 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,28 @@ +#!/bin/bash +BASE_DIR="/usr/local/src/log_parser" + +while getopts 'ct' opt; do + case $opt in + c) SKIP=1;; + t) TEST=1;; + esac +done + +if [ -z $SKIP ]; then + ${BASE_DIR}/config_debug.pl + ngcpcfg apply +fi + +rm -rf ${BASE_DIR}/result/* + +for t in $(find ${BASE_DIR}/scenarios/ -depth -maxdepth 1 -mindepth 1 -type d ); do + echo "Run: $(basename $t)" + if [ -z $TEST ]; then + bash ${BASE_DIR}/scenarios/check.sh $(basename $t) + fi +done + +if [ -z $SKIP ]; then + ${BASE_DIR}/config_debug.pl off + ngcpcfg apply +fi diff --git a/scenarios/callee.csv b/scenarios/callee.csv new file mode 100644 index 00000000..260232f2 --- /dev/null +++ b/scenarios/callee.csv @@ -0,0 +1,2 @@ +SEQUENTIAL +testuser1003;4311003;[authentication username=testuser1003 password=testuser];127.0.0.1 diff --git a/scenarios/caller.csv b/scenarios/caller.csv new file mode 100644 index 00000000..6799604b --- /dev/null +++ b/scenarios/caller.csv @@ -0,0 +1,2 @@ +SEQUENTIAL +testuser1002;[authentication username=testuser1002 password=testuser];127.0.0.1 diff --git a/scenarios/check.sh b/scenarios/check.sh new file mode 100755 index 00000000..cd110d5c --- /dev/null +++ b/scenarios/check.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# $1 kamailio msg parsed to yml +# $2 destination png filename +function graph +{ + if [ -f $1 ]; then + ${BASE_DIR}/graph_flow.pl $1 $2 + fi +} + +# $1 unit test yml +# $2 kamailio msg parsed to yml +# $3 destination tap filename +function check_test +{ + if [ ! -f $1 ]; then + echo "File $1 does not exists" + return + fi + if [ ! -f $2 ]; then + echo "File $2 does not exists" + return + fi + + echo -n "Testing $1 againts $2 -> $3" + ${BASE_DIR}/check.py $1 $2 > $3 + if [[ $? -ne "0" ]]; then + echo " not ok" + else + echo " ok" + fi +} + +# $1 domain +function create_voip +{ + ${BASE_DIR}/create_domain.pl $1 + ${BASE_DIR}/create_subscribers.pl -v 1 -s 3 -d $1 -u testuser -c 43 -a 1 -n 1001 -p testuser +} + +# $1 prefs yml file +function create_voip_prefs +{ + if [ -f $1 ]; then + ${BASE_DIR}/set_subscribers_preferences.pl $1 + fi +} + +# $1 domain +function delete_voip +{ + ${BASE_DIR}/delete_domain.pl $1 +} + +# $1 sipp xml scenario file +function run_sipp +{ + # test LOG_DIR + # we dont want to remove "/*" don't we? + if [ -z ${LOG_DIR} ]; then + echo "LOG_DIR empty" + exit 1 + fi + rm -rf ${LOG_DIR} + mkdir -p ${LOG_DIR} + + ${BASE_DIR}/restart_log.sh + # let's fire sipp scenario + ${BASE_DIR}/sipp.sh $1 + status=$? + # copy the kamailio log + cp ${KAM_LOG} ${LOG_FILE} ${LOG_DIR}/kamailio.log + + if [[ $status -ne 0 ]]; then + echo "error in sipp" + find ${SCEN_CHECK_DIR}/ -type f -name 'sipp_scenario*errors.log' -exec mv {} ${LOG_DIR} \; + exit 2 + fi + + echo "Parsing ${LOG_DIR}/kamailio.log" + ${BASE_DIR}/ulog_parser.pl ${LOG_DIR}/kamailio.log ${LOG_DIR} +} + +while getopts 'c' opt; do + case $opt in + c) SKIP=1;; + esac +done +shift $(($OPTIND - 1)) + +if [[ $# != 1 ]]; then + echo "usage: $0 check_name" + exit 1 +fi + +NAME_CHECK="$1" +BASE_DIR="/usr/local/src/log_parser" +LOG_DIR="${BASE_DIR}/log/${NAME_CHECK}" +RESULT_DIR="${BASE_DIR}/result/${NAME_CHECK}" +KAM_LOG="/var/log/ngcp/kamailio-proxy.log" +SCEN_DIR="${BASE_DIR}/scenarios" +SCEN_CHECK_DIR="${SCEN_DIR}/${NAME_CHECK}" +DOMAIN="127.0.0.1" + +if [ -z $SKIP ]; then + delete_voip ${DOMAIN} # just to be sure nothing is there + create_voip ${DOMAIN} + create_voip_prefs ${SCEN_CHECK_DIR}/prefs.yml + run_sipp ${SCEN_CHECK_DIR}/sipp_scenario.xml + delete_voip ${DOMAIN} +fi + +# let's check the results +mkdir -p ${RESULT_DIR} +for t in ${SCEN_CHECK_DIR}/*_test.yml; do + msg=$(echo $t|sed 's/_test\.yml/\.yml/') + check_test $t ${LOG_DIR}/$(basename $msg) ${RESULT_DIR}/$(basename $t .yml).tap + graph $msg ${RESULT_DIR}/$(basename $msg .yml).png +done + +#EOF diff --git a/scenarios/invite_offline/0001_test.yml b/scenarios/invite_offline/0001_test.yml new file mode 100644 index 00000000..b206d4fa --- /dev/null +++ b/scenarios/invite_offline/0001_test.yml @@ -0,0 +1,27 @@ +# REGISTER scenario +flow: + - start|MAIN: + - start|ROUTE_NET_INFO: + - end|ROUTE_NET_INFO: + - start|ROUTE_PRX_REQUEST: + - start|ROUTE_INVITE: + - start|ROUTE_LOAD_CALLEE_DOMAIN_PREF: + - end|ROUTE_LOAD_CALLEE_DOMAIN_PREF: + - start|ROUTE_FIND_CALLER: + - start|ROUTE_AUTH: + - exit|ROUTE_AUTH: +sip_in: + - '^INVITE' + - 'Contact: sip:testuser2@' + - 'CSeq: 1 INVITE' + - 'Max-Forwards: 16' + - 'Content-Type: application/sdp' +sip_out: + - [ + '^SIP/2.0 100 Trying', + 'CSeq: 1 INVITE' + ] + - [ + '^SIP/2.0 407 Proxy Authentication Required', + 'CSeq: 1 INVITE' + ] diff --git a/scenarios/invite_offline/0003_test.yml b/scenarios/invite_offline/0003_test.yml new file mode 100644 index 00000000..30cb4dc0 --- /dev/null +++ b/scenarios/invite_offline/0003_test.yml @@ -0,0 +1,80 @@ +# REGISTER scenario +flow: + - start|MAIN: + - start|ROUTE_NET_INFO: + - end|ROUTE_NET_INFO: + - start|ROUTE_PRX_REQUEST: + - start|ROUTE_INVITE: + - start|ROUTE_LOAD_CALLEE_DOMAIN_PREF: + - end|ROUTE_LOAD_CALLEE_DOMAIN_PREF: + - start|ROUTE_FIND_CALLER: + - start|ROUTE_AUTH: + - start|ROUTE_ADD_CALLINFO_REPLY: + - end|ROUTE_ADD_CALLINFO_REPLY: + - end|ROUTE_AUTH: + - end|ROUTE_FIND_CALLER: + - start|ROUTE_LOAD_CALLER_PREF: + - start|ROUTE_CLEAR_CALLER_PREF: + - end|ROUTE_CLEAR_CALLER_PREF: + - end|ROUTE_LOAD_CALLER_PREF: + - start|ROUTE_GET_CALLER_CLI: + - end|ROUTE_GET_CALLER_CLI: + - start|ROUTE_GET_FORWARDER_CLI: + - return|ROUTE_GET_FORWARDER_CLI: + - start|ROUTE_CHECK_USERPROV_CLI: + - start|ROUTE_CHECK_CLI_ALLOWED: + - end|ROUTE_CHECK_CLI_ALLOWED: + - end|ROUTE_CHECK_USERPROV_CLI: + - start|ROUTE_CLIR: + - end|ROUTE_CLIR: + - start|ROUTE_FIND_CALLEE: + - start|ROUTE_CLEAR_CALLEE_PREF: + - end|ROUTE_CLEAR_CALLEE_PREF: + - start|ROUTE_NCOS: + - end|ROUTE_NCOS: + - start|ROUTE_NCOS: + - end|ROUTE_NCOS: + - start|ROUTE_BLOCK_OUT: + - end|ROUTE_BLOCK_OUT: + - start|ROUTE_LOAD_CALLEE_PREF: + - start|ROUTE_BLOCK_IN: + - end|ROUTE_BLOCK_IN: + - end|ROUTE_LOAD_CALLEE_PREF: + - start|ROUTE_INVITE_TO_INT: + - start|ROUTE_ACC_FAILURE: + - start|ROUTE_ACC_CALLER: + - end|ROUTE_ACC_CALLER: + - start|ROUTE_ACC_CALLEE: + - end|ROUTE_ACC_CALLEE: + - end|ROUTE_ACC_FAILURE: + - start|ROUTE_EARLY_REJECT: + - start|ROUTE_ADD_CALLINFO_REPLY: + - end|ROUTE_ADD_CALLINFO_REPLY: + - exit|ROUTE_EARLY_REJECT: +sip_in: + - '^INVITE' + - 'Contact: sip:testuser2@' + - 'CSeq: 2 INVITE' + - 'Max-Forwards: 16' + - 'Content-Type: application/sdp' + - 'Proxy-Authorization: Digest username="testuser2"' +sip_out: + - [ + '^SIP/2.0 100 Trying', + 'CSeq: 2 INVITE', + 'From: + + + + ;tag=[pid]SIPpTag00[call_number] + To: + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:[field0 file="caller.csv"]@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 8 + a=rtpmap:8 PCMA/8000 + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:[field0 file="caller.csv"]@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + + + + ;tag=[pid]SIPpTag00[call_number] + To: + Call-ID: [call_id] + CSeq: 2 INVITE + Contact: sip:[field0 file="caller.csv"]@[local_ip]:[local_port] + Max-Forwards: 70 + [field1 file="caller.csv"] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 8 + a=rtpmap:8 PCMA/8000 + + ]]> + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:[field0 file="caller.csv"]@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + + + + ;tag=[pid]SIPpTag00[call_number] + To: + Call-ID: [call_id] + CSeq: 2 INVITE + Contact: sip:[field0 file="caller.csv"]@[local_ip]:[local_port] + Max-Forwards: 70 + [field1 file="caller.csv"] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 8 + a=rtpmap:8 PCMA/8000 + + ]]> + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:[field0 file="caller.csv"]@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + + + + + +