Compare commits

...

4 Commits

Author SHA1 Message Date
Pau Espin f2b4411a72 WIP: asterisk: Introduce test TC_internal_call_momt
Related: SYS#6782
Change-Id: I7621ee867202b74a40e40516cdca673781cb1f51
2024-04-08 21:34:48 +02:00
Pau Espin 6331f5c033 SIP_Emulation: Match empty port as default port 5060
Change-Id: I8415571a5bdc99e8cc007bb4b57bcb73b7afd4fb
2024-04-08 21:34:48 +02:00
Pau Espin 0169e6038d SIP_Emulation: Fix SIPEM_register when several conns are active
"Dynamic test case error: Port CLIENT_PROC has more than one active
connections. Message can be sent on it only with explicit addressing.".

Change-Id: Ibf868394ce2c495a78ab943ddec278a45bf71088
2024-04-08 21:02:52 +02:00
Pau Espin 65dde83956 library/SIP_Templates: Fix wrong method name in tr_SIP_REGISTER
Change-Id: Ieec2124417a3294cfb469180f44285e880a46177
2024-04-08 18:17:15 +02:00
3 changed files with 294 additions and 47 deletions

View File

@ -31,8 +31,16 @@ modulepar {
integer mp_remote_sip_port := 5060;
}
type port Coord_PT message
{
inout charstring;
} with { extension "internal" };
private const charstring COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
private const charstring COORD_CMD_START := "COORD_CMD_START";
type component test_CT {
var SIP_Emulation_CT vc_SIP;
port Coord_PT COORD;
}
type component ConnHdlr extends SIP_ConnHdlr {
@ -40,11 +48,14 @@ type component ConnHdlr extends SIP_ConnHdlr {
timer g_Tguard;
var PDU_SIP_Request g_rx_sip_req;
var PDU_SIP_Response g_rx_sip_resp;
port Coord_PT COORD;
}
type record ConnHdlrPars {
float t_guard,
charstring user,
charstring display_name,
charstring password,
SipUrl registrar_sip_url,
SipAddr registrar_sip_record,
@ -57,15 +68,17 @@ type record ConnHdlrPars {
}
template (value) ConnHdlrPars t_Pars(charstring user,
charstring displayname := "\"Anonymous\"",
charstring password := "secret") := {
charstring display_name := "Anonymous",
charstring password := "secret",
template (value) CallPars cp := t_CallPars()) := {
t_guard := 30.0,
user := user,
display_name := f_sip_str_quote(display_name),
password := password,
registrar_sip_url := valueof(ts_SipUrlHost(mp_remote_sip_host)),
registrar_sip_record := ts_SipAddr(ts_HostPort(mp_remote_sip_host),
ts_UserInfo(user),
displayName := displayname),
f_sip_str_quote(display_name)),
registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & mp_local_sip_host,
registrar_via := ts_Via_from(ts_HostPort(mp_local_sip_host, mp_local_sip_port)),
registrar_sip_seq_nr := f_sip_rand_seq_nr(),
@ -79,46 +92,38 @@ template (value) ConnHdlrPars t_Pars(charstring user,
ts_UserInfo(user))),
omit)
})),
cp := omit
cp := cp
}
function f_init_ConnHdlrPars(integer idx := 1) runs on test_CT return ConnHdlrPars {
var ConnHdlrPars pars := valueof(t_Pars("0" & int2str(500 + idx)));
return pars;
var template (value) CallPars cp := t_CallPars(idx := idx);
var template (value) ConnHdlrPars pars := t_Pars("0" & int2str(500 + idx),
cp := cp);
return valueof(pars);
}
type record CallPars {
boolean is_mo,
charstring calling,
charstring called,
SipAddr calling optional,
SipAddr called optional,
CallParsComputed comp optional,
charstring sip_rtp_addr,
uint16_t sip_rtp_port,
charstring cn_rtp_addr,
uint16_t cn_rtp_port
}
type record CallParsComputed {
CallidString sip_call_id,
integer sip_seq_nr,
charstring sip_body,
integer sip_seq_nr
charstring local_rtp_addr,
uint16_t local_rtp_port
}
private template (value) CallPars t_CallPars(boolean is_mo) := {
is_mo := is_mo,
calling := "12345",
called := "98766",
comp := {
sip_call_id := hex2str(f_rnd_hexstring(15)),
sip_body := "",
sip_seq_nr := f_sip_rand_seq_nr()
},
sip_rtp_addr := "1.2.3.4",
sip_rtp_port := 1234,
cn_rtp_addr := "5.6.7.8",
cn_rtp_port := 5678
private template (value) CallPars t_CallPars(integer idx := 1,
template (omit) SipAddr calling := omit,
template (omit) SipAddr called := omit) := {
calling := calling,
called := called,
sip_call_id := hex2str(f_rnd_hexstring(15)),
sip_seq_nr := f_sip_rand_seq_nr(),
sip_body := "",
local_rtp_addr := mp_local_sip_host,
local_rtp_port := 1234 + idx
}
function f_init() runs on test_CT {
@ -131,13 +136,15 @@ type function void_fn(charstring id) runs on ConnHdlr;
function f_start_handler(void_fn fn, ConnHdlrPars pars)
runs on test_CT return ConnHdlr {
var ConnHdlr vc_conn;
var charstring id := testcasename();
var charstring id := testcasename() & "-ConnHdlr-" & pars.user;
vc_conn := ConnHdlr.create(id);
connect(vc_conn:SIP, vc_SIP:CLIENT);
connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
connect(vc_conn:COORD, self:COORD);
vc_conn.start(f_handler_init(fn, id, pars));
return vc_conn;
}
@ -163,7 +170,7 @@ runs on ConnHdlr {
fn.apply(id);
}
altstep as_SIP_expect_req(template PDU_SIP_Request sip_expect) runs on ConnHdlr
altstep as_SIP_expect_req(template (present) PDU_SIP_Request sip_expect) runs on ConnHdlr
{
[] SIP.receive(sip_expect) -> value g_rx_sip_req;
[] SIP.receive {
@ -172,15 +179,23 @@ altstep as_SIP_expect_req(template PDU_SIP_Request sip_expect) runs on ConnHdlr
}
}
altstep as_SIP_expect_resp(template PDU_SIP_Response sip_expect) runs on ConnHdlr
altstep as_SIP_expect_resp(template (present) PDU_SIP_Response sip_expect, boolean fail_others := true) runs on ConnHdlr
{
[] SIP.receive(sip_expect) -> value g_rx_sip_resp;
[] SIP.receive {
[fail_others] SIP.receive {
log("FAIL: expected SIP message ", sip_expect);
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
}
}
altstep as_SIP_ignore_resp(template PDU_SIP_Response sip_expect := ?) runs on ConnHdlr
{
[] SIP.receive(sip_expect) -> value g_rx_sip_resp {
log("Ignoring ", g_rx_sip_resp);
repeat;
}
}
private function f_tr_Via_response(Via via_req) return template (present) Via {
template (present) SemicolonParam_List via_resp_params := ?;
@ -196,6 +211,10 @@ private function f_tr_To_response(SipAddr to_req) return template (present) SipA
return tr_SipAddr_from_val(to_req);
}
private function f_tr_From(SipAddr from_req) return template (present) SipAddr {
return tr_SipAddr_from_val(from_req);
}
function f_SIP_register() runs on ConnHdlr return PDU_SIP_Response
{
var template (present) PDU_SIP_Response exp;
@ -220,7 +239,7 @@ function f_SIP_register() runs on ConnHdlr return PDU_SIP_Response
g_pars.local_contact,
ts_Expires("7200")));
exp := tr_SIP_Response_REGISTER_Unauthorized(
exp := tr_SIP_Response_Unauthorized(
g_pars.registrar_sip_call_id,
from_sipaddr,
f_tr_To_response(g_pars.registrar_sip_record),
@ -269,6 +288,100 @@ function f_SIP_register() runs on ConnHdlr return PDU_SIP_Response
return g_rx_sip_resp;
}
function f_SIP_mo_call_setup() runs on ConnHdlr
{
var template (value) PDU_SIP_Request req;
var template (present) PDU_SIP_Response exp;
var SipAddr from_sipaddr := g_pars.cp.calling;
var default d;
/* RFC 3261 8.1.1.3 From */
//from_sipaddr.addr.nameAddr.addrSpec.hostPort.portField := omit;
from_sipaddr.params := f_sip_param_set(from_sipaddr.params, "tag", f_sip_rand_tag());
req := ts_SIP_INVITE(g_pars.cp.sip_call_id,
from_sipaddr,
g_pars.cp.called,
g_pars.cp.sip_seq_nr,
g_pars.cp.sip_body);
SIP.send(req);
/* RFC 3261 22.2: */
exp := tr_SIP_Response_Unauthorized(
g_pars.cp.sip_call_id,
f_tr_From(from_sipaddr),
f_tr_To_response(g_pars.cp.called),
tr_Via_from(tr_HostPort(g_pars.cp.calling.addr.nameAddr.addrSpec.hostPort)),
*,
tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
g_pars.cp.sip_seq_nr, "INVITE");
as_SIP_expect_resp(exp);
/* Digest Auth: RFC 2617 */
req.msgHeader.authorization := f_sip_digest_gen_Authorization(
g_rx_sip_resp.msgHeader.wwwAuthenticate,
g_pars.user, g_pars.password,
"INVITE", "sip:" & mp_remote_sip_host)
g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
f_sip_Request_inc_seq_nr(req);
SIP.send(req);
/* Conditionally match and accept 100 Trying. TODO: 180 Ringing */
exp := tr_SIP_Response_Trying(g_pars.cp.sip_call_id,
from_sipaddr,
f_tr_To_response(g_pars.cp.called),
tr_Via_from(tr_HostPort(g_pars.cp.calling.addr.nameAddr.addrSpec.hostPort)),
g_pars.cp.sip_seq_nr, "INVITE");
d := activate(as_SIP_ignore_resp(exp));
/* Wait for OK answer */
exp := tr_SIP_Response(
g_pars.cp.sip_call_id,
from_sipaddr,
f_tr_To_response(g_pars.cp.called),
tr_Via_from(tr_HostPort(from_sipaddr.addr.nameAddr.addrSpec.hostPort)),
*,
"INVITE", 200,
g_pars.cp.sip_seq_nr, "OK");
as_SIP_expect_resp(exp, fail_others := false);
deactivate(d);
/* TODO: transmit ACK */
}
function f_SIP_mt_call_accept() runs on ConnHdlr
{
var template (present) PDU_SIP_Request exp_req;
var template (value) PDU_SIP_Response tx_resp;
var template (value) SipAddr from_addr;
var template (value) SipAddr to_addr;
exp_req := tr_SIP_INVITE(?, f_tr_From(g_pars.cp.calling), g_pars.cp.called, ?, ?);
as_SIP_expect_req(exp_req);
from_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.fromField.addressField,
g_rx_sip_req.msgHeader.fromField.fromParams);
to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
g_rx_sip_req.msgHeader.toField.toParams);
tx_resp := ts_SIP_Response_Trying(g_rx_sip_req.msgHeader.callId.callid,
from_addr,
to_addr,
g_rx_sip_req.msgHeader.via,
g_rx_sip_req.msgHeader.cSeq.seqNumber);
SIP.send(tx_resp);
exp_req := tr_SIP_ACK(g_rx_sip_req.msgHeader.callId.callid,
from_addr,
to_addr,
g_rx_sip_req.msgHeader.cSeq.seqNumber /* +1?*/, *);
as_SIP_expect_req(exp_req);
}
/* Test SIP registration of local clients */
private function f_TC_internal_registration(charstring id) runs on ConnHdlr {
@ -276,7 +389,6 @@ private function f_TC_internal_registration(charstring id) runs on ConnHdlr {
// f_SIP_deregister();
setverdict(pass);
}
testcase TC_internal_registration() runs on test_CT {
var ConnHdlrPars pars;
var ConnHdlr vc_conn;
@ -286,6 +398,56 @@ testcase TC_internal_registration() runs on test_CT {
vc_conn.done;
}
/* Successful SIP MO-MT Call between local clients: */
private function f_TC_internal_call_mo(charstring id) runs on ConnHdlr {
f_SIP_register();
COORD.send(COORD_CMD_REGISTERED);
COORD.receive(COORD_CMD_START);
f_SIP_mo_call_setup();
setverdict(pass);
}
private function f_TC_internal_call_mt(charstring id) runs on ConnHdlr {
f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.cp.called.addr)));
f_SIP_register();
COORD.send(COORD_CMD_REGISTERED);
f_SIP_mt_call_accept();
setverdict(pass);
}
testcase TC_internal_call_momt() runs on test_CT {
var ConnHdlrPars pars[2];
var ConnHdlr vc_conn[2];
f_init();
pars[0] := f_init_ConnHdlrPars(idx := 1);
pars[1] := f_init_ConnHdlrPars(idx := 2);
pars[0].cp.calling := pars[0].sip_url_ext;
pars[0].cp.called := pars[1].sip_url_ext;
pars[1].cp.calling := pars[0].sip_url_ext;
pars[1].cp.called := pars[1].sip_url_ext;
vc_conn[0] := f_start_handler(refers(f_TC_internal_call_mo), pars[0]);
vc_conn[1] := f_start_handler(refers(f_TC_internal_call_mt), pars[1]);
interleave {
[] COORD.receive(COORD_CMD_REGISTERED) from vc_conn[0];
[] COORD.receive(COORD_CMD_REGISTERED) from vc_conn[1];
}
COORD.send(COORD_CMD_START) to vc_conn[0];
vc_conn[0].done;
vc_conn[1].done;
}
testcase TC_selftest() runs on test_CT {
f_sip_digest_selftest();
setverdict(pass);
@ -293,6 +455,7 @@ testcase TC_selftest() runs on test_CT {
control {
execute( TC_internal_registration() );
execute( TC_internal_call_momt() );
}
}

View File

@ -326,9 +326,9 @@ runs on SIP_Emulation_CT {
SIP.send(sip_resp);
}
[] CLIENT_PROC.getcall(SIPEM_register:{?,?}) -> param(sip_to, vc_hdlr) {
[] CLIENT_PROC.getcall(SIPEM_register:{?,?}) -> param(sip_to, vc_hdlr) sender vc_conn {
f_create_expect(sip_to, vc_hdlr);
CLIENT_PROC.reply(SIPEM_register:{sip_to, vc_hdlr});
CLIENT_PROC.reply(SIPEM_register:{sip_to, vc_hdlr}) to vc_conn;
}
}
@ -380,6 +380,9 @@ runs on SIP_Emulation_CT return SIP_ConnHdlr {
}
if (not ispresent(t_exp.hostPort.portField)) {
t_exp.hostPort.portField := *;
} else if (valueof(t_exp.hostPort.portField) == 5060) {
/* if the port number is 5060, it may be omitted */
t_exp.hostPort.portField := 5060 ifpresent;
}
if (not ispresent(t_exp.urlParameters)) {
t_exp.urlParameters := *;

View File

@ -55,6 +55,15 @@ template (present) SipUrl tr_SipUrl(template (present) HostPort host_port := ?,
template (value) SipUrl ts_SipUrlHost(template (value) charstring host)
:= ts_SipUrl(ts_HostPort(host));
function ts_SipUrl_from_Addr_Union(template (value) Addr_Union au)
return template (value) SipUrl {
if (ischosen(au.nameAddr)) {
return au.nameAddr.addrSpec;
} else { /* au.addrSpecUnion */
return au.addrSpecUnion;
}
}
template (value) Credentials ts_Credentials_DigestResponse(template (value) CommaParam_List digestResponse) := {
digestResponse := digestResponse
}
@ -217,6 +226,11 @@ function tr_SipAddr_from_val(SipAddr tin) return template (present) SipAddr {
if (tin.addr.nameAddr.displayName == omit) {
ret.addr.nameAddr.displayName := *;
}
/* if the port number is 5060, it may be omitted */
if (ispresent(tin.addr.nameAddr.addrSpec.hostPort.portField) and
valueof(tin.addr.nameAddr.addrSpec.hostPort.portField) == 5060) {
ret.addr.nameAddr.addrSpec.hostPort.portField := 5060 ifpresent;
}
if (tin.addr.nameAddr.addrSpec.userInfo.password == omit) {
ret.addr.nameAddr.addrSpec.userInfo.password := *;
}
@ -226,12 +240,30 @@ function tr_SipAddr_from_val(SipAddr tin) return template (present) SipAddr {
return ret;
}
function ts_SipAddr_from_Addr_Union(template (value) Addr_Union au,
template (omit) SemicolonParam_List params := omit)
return template (value) SipAddr {
var template (value) SipUrl addrSpec := ts_SipUrl_from_Addr_Union(au);
var template (omit) charstring displayName;
if (ischosen(au.nameAddr)) {
displayName := au.nameAddr.displayName;
} else { /* au.addrSpecUnion */
displayName := omit
}
return ts_SipAddr(addrSpec.hostPort,
addrSpec.userInfo,
displayName,
params);
}
template (value) HostPort ts_HostPort(template (omit) charstring host := omit,
template (omit) integer portField := omit) := {
host := host,
portField := portField
}
function tr_HostPort(template HostPort hp) return template HostPort {
function tr_HostPort(template (present) HostPort hp) return template (present) HostPort {
var template HostPort hpout := hp;
/* if the port number is 5060, it may be omitted */
if (isvalue(hp.portField) and valueof(hp.portField) == 5060) {
@ -516,7 +548,7 @@ tr_SIP_REGISTER(template (present) SipUrl sip_url_host_port := ?,
requestLine := tr_SIP_ReqLine(REGISTER_E, sip_url_host_port),
msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
tr_Via_from(tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort)),
"INVITE", *, seq_nr,
"REGISTER", *, seq_nr,
expires := expires),
messageBody := body,
payload := omit
@ -610,9 +642,9 @@ tr_SIP_ACK(template CallidString call_id,
}
template (value) PDU_SIP_Response
ts_SIP_Response(CallidString call_id,
SipAddr from_addr,
SipAddr to_addr,
ts_SIP_Response(template (value) CallidString call_id,
template (value) SipAddr from_addr,
template (value) SipAddr to_addr,
charstring method,
integer status_code,
integer seq_nr,
@ -626,6 +658,23 @@ ts_SIP_Response(CallidString call_id,
payload := omit
}
/* 180 Ringing */
template (value) PDU_SIP_Response
ts_SIP_Response_Trying(
template (value) CallidString call_id,
template (value) SipAddr from_addr,
template (value) SipAddr to_addr,
Via via,
integer seq_nr,
charstring method := "INVITE",
template (omit) charstring body := omit) := {
statusLine := ts_SIP_StatusLine(180, "Ringing"),
msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
messageBody := body,
payload := omit
}
template (present) PDU_SIP_Response
tr_SIP_Response(template CallidString call_id,
template SipAddr from_addr,
@ -645,9 +694,9 @@ tr_SIP_Response(template CallidString call_id,
payload := omit
}
/* Expect during first REGISTER when authorization is required: */
/* Expect during first REGISTER/INVITE/... when authorization is required: */
template (present) PDU_SIP_Response
tr_SIP_Response_REGISTER_Unauthorized(
tr_SIP_Response_Unauthorized(
template CallidString call_id,
template SipAddr from_addr,
template SipAddr to_addr,
@ -668,6 +717,30 @@ tr_SIP_Response_REGISTER_Unauthorized(
payload := omit
}
/* 100 Trying */
template (present) PDU_SIP_Response
tr_SIP_Response_Trying(
template CallidString call_id,
template SipAddr from_addr,
template SipAddr to_addr,
template (present) Via via := tr_Via_from(?),
template integer seq_nr := ?,
template charstring method := "INVITE",
template integer status_code := 100,
template charstring reason := "Trying",
template charstring body := *) := {
statusLine := tr_SIP_StatusLine(status_code, reason),
msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
via,
method, *, seq_nr),
messageBody := body,
payload := omit
}
/****************
* FUNCTIONS:
****************/
function f_sip_param_find(GenericParam_List li,
template (present) charstring id := ?)
return template (omit) GenericParam {
@ -998,6 +1071,14 @@ function f_sip_rand_seq_nr() return integer {
return f_rnd_int(2147483648)
}
function f_sip_next_seq_nr(integer seq_nr) return integer {
return (seq_nr + 1) mod 2147483648;
}
function f_sip_Request_inc_seq_nr(inout template (value) PDU_SIP_Request req) {
req.msgHeader.cSeq.seqNumber := f_sip_next_seq_nr(valueof(req.msgHeader.cSeq.seqNumber));
}
/* Tags shall have at least 32 bit of randomness */
function f_sip_rand_tag() return charstring {
var integer rnd_int := f_rnd_int(4294967296);