aboutsummaryrefslogtreecommitdiffstats
path: root/sip/SIP_Tests.ttcn
diff options
context:
space:
mode:
Diffstat (limited to 'sip/SIP_Tests.ttcn')
-rw-r--r--sip/SIP_Tests.ttcn451
1 files changed, 341 insertions, 110 deletions
diff --git a/sip/SIP_Tests.ttcn b/sip/SIP_Tests.ttcn
index 053395e4..60643721 100644
--- a/sip/SIP_Tests.ttcn
+++ b/sip/SIP_Tests.ttcn
@@ -26,6 +26,7 @@ import from MNCC_Emulation all;
import from MNCC_Types all;
import from SDP_Types all;
+import from SDP_Templates all;
import from SIP_Emulation all;
import from SIPmsg_Types all;
@@ -66,7 +67,12 @@ type record CallPars {
charstring sip_rtp_addr,
uint16_t sip_rtp_port,
charstring cn_rtp_addr,
- uint16_t cn_rtp_port
+ uint16_t cn_rtp_port,
+
+ /* Send SDP to MNCC, and expect to receive SDP from MNCC. mncc_with_sdp := false tests legacy compatibility to
+ * the time when we did not include SDP in MNCC messages. mncc_with_sdp := true expects SDP to pass through the
+ * SUT osmo-sip-connector unchanged. */
+ boolean mncc_with_sdp
}
type record CallParsComputed {
@@ -77,7 +83,7 @@ type record CallParsComputed {
integer sip_seq_nr
}
-private template (value) CallPars t_CallPars(boolean is_mo) := {
+private template (value) CallPars t_CallPars(boolean is_mo, boolean mncc_with_sdp := true) := {
is_mo := is_mo,
calling := "12345",
called := "98766",
@@ -87,40 +93,28 @@ private template (value) CallPars t_CallPars(boolean is_mo) := {
sip_rtp_addr := "1.2.3.4",
sip_rtp_port := 1234,
cn_rtp_addr := "5.6.7.8",
- cn_rtp_port := 5678
+ cn_rtp_port := 5678,
+ mncc_with_sdp := mncc_with_sdp
}
private function f_CallPars_compute(inout CallPars cp) {
if (cp.is_mo) {
- cp.comp.sip_url_ext := valueof(ts_SipAddr(cp.called, mp_local_host, 5060));
- cp.comp.sip_url_gsm := valueof(ts_SipAddr(cp.calling, mp_osmosip_host, 5060));
- cp.mncc_call_id := f_rnd_int(429496725);
+ cp.comp.sip_url_ext := valueof(ts_SipAddr(ts_HostPort(mp_local_host, 5060),
+ ts_UserInfo(cp.called)));
+ cp.comp.sip_url_gsm := valueof(ts_SipAddr(ts_HostPort(mp_osmosip_host, 5060),
+ ts_UserInfo(cp.calling)));
+ cp.mncc_call_id := f_sip_rand_seq_nr();
} else {
- cp.comp.sip_url_ext := valueof(ts_SipAddr(cp.calling, mp_local_host, 5060));
- cp.comp.sip_url_gsm := valueof(ts_SipAddr(cp.called, mp_osmosip_host, 5060));
+ cp.comp.sip_url_ext := valueof(ts_SipAddr(ts_HostPort(mp_local_host, 5060),
+ ts_UserInfo(cp.calling)));
+ cp.comp.sip_url_gsm := valueof(ts_SipAddr(ts_HostPort(mp_osmosip_host, 5060),
+ ts_UserInfo(cp.called)));
cp.comp.sip_call_id := hex2str(f_rnd_hexstring(15));
}
- cp.comp.sip_seq_nr := f_rnd_int(4294967295);
+ cp.comp.sip_seq_nr := f_sip_rand_seq_nr();
cp.comp.sip_body := "";
}
-private function f_mgcp_addr2addrtype(charstring addr) return charstring {
- for (var integer i := 0; i < lengthof(addr); i := i + 1) {
- if (addr[i] == ":") {
- return "IP6";
- }
- }
- return "IP4";
-}
-
-private function f_addrstr2addr(charstring addr) return octetstring {
- if (f_addr_is_ipv6(addr)) {
- return f_inet6_addr(addr);
- } else {
- return f_inet_addr(addr);
- }
-}
-
function f_init_mncc(charstring id) runs on test_CT {
id := id & "-MNCC";
var MnccOps ops := {
@@ -128,16 +122,16 @@ function f_init_mncc(charstring id) runs on test_CT {
unitdata_cb := refers(MNCC_Emulation.DummyUnitdataCallback)
};
- vc_MNCC := MNCC_Emulation_CT.create(id);
+ vc_MNCC := MNCC_Emulation_CT.create(id) alive;
map(vc_MNCC:MNCC, system:MNCC_CODEC_PT);
vc_MNCC.start(MNCC_Emulation.main(ops, id, mp_mncc, true));
}
function f_init() runs on test_CT {
- //f_ipa_ctrl_start(mp_osmosip_host, mp_osmosip_port_ctrl);
+ //f_ipa_ctrl_start_client(mp_osmosip_host, mp_osmosip_port_ctrl);
f_init_mncc("SIP_Test");
log("end of f_init_mncc");
- f_init_sip(vc_SIP, "SIP_Test");
+ f_init_sip(vc_SIP, "SIP_Test_SIP_EMU");
log("end of f_init_sip");
map(self:SIPVTY, system:SIPVTY);
@@ -153,7 +147,7 @@ runs on test_CT return ConnHdlr {
var ConnHdlr vc_conn;
var charstring id := testcasename();
- vc_conn := ConnHdlr.create(id);
+ vc_conn := ConnHdlr.create(id) alive;
connect(vc_conn:SIP, vc_SIP:CLIENT);
connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
@@ -188,32 +182,123 @@ template (value) ConnHdlrPars t_Pars := {
g_cp := omit
}
+altstep as_SIP_expect_resp(template PDU_SIP_Response sip_expect) runs on ConnHdlr
+{
+ [] SIP.receive(sip_expect);
+ [] SIP.receive {
+ log("FAIL: expected SIP message ", sip_expect);
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
+ }
+}
+
+function f_SIP_expect_req(template PDU_SIP_Request sip_expect) runs on ConnHdlr return PDU_SIP_Request
+{
+ var PDU_SIP_Request rx;
+ alt {
+ [] SIP.receive(sip_expect) -> value rx;
+ [] SIP.receive {
+ log("FAIL: expected SIP message ", sip_expect);
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
+ }
+ }
+ return rx;
+}
+
+/* Update 'last_sdp', and match with expectation of what the current SDP should be.
+ * Useful to ensure that MNCC or SIP send and possibly resend only the expected SDP.
+ * last_sdp keeps the last non-empty rx_sdp, across multiple check_sdp() invocations.
+ * rx_sdp is the SDP charstring just received. If it is nonempty, update last_sdp to rx_sdp.
+ * After updating last_sdp as appropriate, match last_sdp with expect_sdp. */
+private function check_sdp(inout charstring last_sdp,
+ charstring rx_sdp,
+ template charstring expect_sdp)
+{
+ /* If there is new SDP, store it. */
+ if (lengthof(rx_sdp) > 0) {
+ if (last_sdp != rx_sdp) {
+ log("SDP update from ", last_sdp, " to ", rx_sdp);
+ }
+
+ /* If MNCC sent SDP data, remember it as the last valid SDP */
+ last_sdp := rx_sdp;
+ }
+ /* Validate expectations of the SDP data */
+ if (not match(last_sdp, expect_sdp)) {
+ log("FAIL: expected SDP ", expect_sdp, " but got ", last_sdp);
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "unexpected SDP");
+ }
+}
+
/* Establish a mobile terminated call described in 'cp' */
function f_establish_mt(inout CallPars cp) runs on ConnHdlr {
- var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
- var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
- var PDU_SIP_Request sip_req;
- var PDU_SIP_Response sip_resp;
+ var template (value) From from_addr := ts_From(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
+ var template (value) To to_addr := ts_To(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
+ var template (value) Via via := ts_Via_from(cp.comp.sip_url_ext.addr.nameAddr.addrSpec.hostPort);
+ var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
+ var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
+ var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
var MNCC_PDU mncc;
+ /* The last SDP that the MSC received via MNCC from osmo-sip-connector */
+ var charstring sdp_to_msc := "";
+ /* At first, allow any empty and nonempty SDP. As the test progresses, this may expect specific SDP instead. */
+ var template charstring expect_sdp_to_msc := *;
+
+ /* If cp.mncc_with_sdp == true, expect SDP forwarding like this:
+ *
+ * SDP1: SIP agent's RTP and codec info
+ * SDP2: osmo-msc's RTP and codec info
+ *
+ * MNCC osmo-sip-connector SIP
+ * |<--SDP1----- SIP Invite
+ * |-----------> SIP (Invite) Trying
+ * <--SDP1-------| MNCC SETUP req
+ * ------------->| MNCC CALL CONF ind
+ * <-------------| MNCC RTP CREATE (SDP optional, still unchanged from SDP1)
+ * -------SDP2-->| MNCC RTP CREATE
+ * ------------->| MNCC ALERT ind
+ * |--------------> SIP (Invite) Ringing
+ * (MT picks up) |
+ * ------------->| MNCC SETUP CNF
+ * <-------------| MNCC RTP CONNECT (SDP optional, still unchanged from SDP1)
+ * |--------SDP2--> SIP (Invite) OK
+ * |<-------------- SIP ACK
+ * <-------------| MNCC SETUP COMPL (SDP optional, still unchanged from SDP1)
+ */
+
/* Ask MNCC_Emulation to "expect" a call to the given called number */
f_create_mncc_expect(cp.called);
/* OSC <- SIP: A party sends SIP invite for a MT-call into OSC */
- SIP.send(ts_SIP_INVITE(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
- cp.comp.sip_seq_nr, cp.comp.sip_body));
+ SIP.send(ts_SIP_INVITE(cp.comp.sip_call_id, from_addr, to_addr,
+ via,
+ ts_Contact_SipAddr(cp.comp.sip_url_ext),
+ cp.comp.sip_seq_nr,
+ body := cp.comp.sip_body));
+ if (cp.mncc_with_sdp) {
+ /* We just sent SDP via SIP, now expect the same SDP in MNCC to the MSC */
+ expect_sdp_to_msc := cp.comp.sip_body;
+ }
+
/* OSC -> SIP */
- SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *,
- "INVITE", 100, ?, "Trying", *));
+ as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
+ via_exp,
+ *,
+ "INVITE", 100, ?, "Trying", *));
alt {
/* MSC <- OSC: OSC generates MNCC_SETUP_REQ from INVITE */
[] MNCC.receive(tr_MNCC_SETUP_req) -> value mncc {
- cp.mncc_call_id := mncc.u.signal.callref;
+ cp.mncc_call_id := mncc.u.signal.callref;
+ /* Expect the SDP sent via SIP to arrive in MNCC */
+ check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
}
[] SIP.receive {
- setverdict(fail, "Received unexpected respose");
- SIP.send(ts_SIP_ACK(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
+ setverdict(fail, "Received unexpected SIP response");
+ SIP.send(ts_SIP_ACK(to_addr.addressField.nameAddr.addrSpec,
+ cp.comp.sip_call_id,
+ from_addr, to_addr,
+ via,
cp.comp.sip_seq_nr, omit));
mtc.stop;
}
@@ -222,119 +307,226 @@ function f_establish_mt(inout CallPars cp) runs on ConnHdlr {
/* MSC -> OSC: After MS sends CALL CONF in response to SETUP */
MNCC.send(ts_MNCC_CALL_CONF_ind(cp.mncc_call_id));
/* MSC <- OSC: OSC asks MSC to create RTP socket */
- MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id));
+ MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.rtp.sdp, expect_sdp_to_msc);
+ }
+
+ /* MSC -> OSC: SDP that the MSC will send via MNCC */
+ var charstring cn_sdp := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
+ f_sdp_addr2addrtype(cp.cn_rtp_addr) & " " & cp.cn_rtp_addr &
+ "\r\nt=0 0\r\nm=audio " & int2str(cp.cn_rtp_port) &
+ " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
+ /* OSC -> SIP: what SDP to expect in SIP from osmo-sip-connector */
+ var template charstring expect_sdp_to_sip := pattern "*" & cp.cn_rtp_addr & "*";
+
mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
mncc.u.rtp.is_ipv6 := f_addr_is_ipv6(cp.cn_rtp_addr);
mncc.u.rtp.ip := f_addrstr2addr(cp.cn_rtp_addr);
mncc.u.rtp.rtp_port := cp.cn_rtp_port;
+ if (cp.mncc_with_sdp) {
+ /* MSC -> OSC: tell OSC our RTP info in SDP form */
+ mncc.u.rtp.sdp := cn_sdp;
+ /* OSC -> SIP: and expect it unchanged on SIP later, but allow osmo-sip-connector to append an
+ * "a=sendrecv;" */
+ expect_sdp_to_sip := pattern cn_sdp & "*";
+ }
MNCC.send(mncc);
/* MSC -> OSC: After MS is ringing and sent CC ALERTING */
MNCC.send(ts_MNCC_ALERT_ind(cp.mncc_call_id));
+
+ /* Now expect SIP response "Ringing" back to MO, containing the same SDP information as in the MNCC RTP CREATE
+ * sent to OSC above */
SIP.clear;
- alt {
- [] SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *,
- "INVITE", 180, ?, "Ringing", *));
- [] SIP.receive {
- setverdict(fail, "Received unexpected respose");
- SIP.send(ts_SIP_ACK(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
- cp.comp.sip_seq_nr, omit));
- mtc.stop;
- }
- }
+
+ /* 180 Ringing should not contain any SDP. */
+ as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
+ via_exp,
+ *,
+ "INVITE", 180, ?, "Ringing", omit));
/* MSC -> OSC: After MT user has picked up and sent CC CONNECT */
MNCC.send(ts_MNCC_SETUP_CNF(cp.mncc_call_id));
SIP.clear;
- interleave {
/* MSC <- OSC: OSC asks MSC to connect its RTP stream to remote end */
- [] MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id, f_addrstr2addr(cp.sip_rtp_addr), cp.sip_rtp_port)) {}
- /* OSC -> SIP: OSC confirms call establishment to SIP side */
- [] SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, ?,
- "INVITE", 200, ?, "OK", ?)) -> value sip_resp {
- if (not match(sip_resp.messageBody, pattern "*" & cp.cn_rtp_addr & "*")) {
- setverdict(fail, "wrong ip addr sent in SIP SDP, not containing ", cp.cn_rtp_addr);
- mtc.stop;
- }
- }
+ MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id, f_addrstr2addr(cp.sip_rtp_addr), cp.sip_rtp_port))
+ -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.rtp.sdp, expect_sdp_to_msc);
}
+
+ /* OSC -> SIP: OSC confirms call establishment to SIP side */
+ as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
+ via_exp,
+ contact := ?,
+ method := "INVITE", status_code := 200,
+ seq_nr := ?, reason := "OK",
+ body := expect_sdp_to_sip));
+
/* OSC <- SIP: SIP world acknowledges "200 OK" */
- SIP.send(ts_SIP_ACK(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
+ SIP.send(ts_SIP_ACK(to_addr.addressField.nameAddr.addrSpec,
+ cp.comp.sip_call_id,
+ from_addr, to_addr,
+ via,
cp.comp.sip_seq_nr, omit));
/* MSC <- OSC: OSC sends SETUP COMPL to MNCC (which triggers CC CONNECT ACK */
- MNCC.receive(tr_MNCC_SETUP_COMPL_req(cp.mncc_call_id));
+ MNCC.receive(tr_MNCC_SETUP_COMPL_req(cp.mncc_call_id)) -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
+ }
}
/* Establish a mobile originated call described in 'cp' */
function f_establish_mo(inout CallPars cp) runs on ConnHdlr {
var MNCC_number dst := valueof(ts_MNCC_number(cp.called, GSM48_TON_UNKNOWN));
var MNCC_number src := valueof(ts_MNCC_number(cp.calling, GSM48_TON_UNKNOWN));
- var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
- var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
+
+ var template (value) From from_addr := ts_From(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
+ var template (value) To to_addr := ts_To(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
+ var template (value) Via via := ts_Via_from(cp.comp.sip_url_gsm.addr.nameAddr.addrSpec.hostPort);
+ var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
+ var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
+ var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
+
+
var PDU_SIP_Request sip_req;
var integer seq_nr;
+ var MNCC_PDU mncc;
+
+ /* The last SDP that the MSC received via MNCC from osmo-sip-connector */
+ var charstring sdp_to_msc := "";
+ /* At first, allow any empty and nonempty SDP. As the test progresses, this may expect specific SDP instead. */
+ var template charstring expect_sdp_to_msc := *;
+
+ /* If cp.mncc_with_sdp == true, expect SDP forwarding like this:
+ *
+ * SDP1: osmo-msc's RTP and codec info
+ * SDP2: SIP agent's RTP and codec info
+ *
+ * MNCC osmo-sip-connector SIP
+ * -------SDP1-->| MNCC SETUP ind
+ * <-------------| MNCC RTP CREATE (?)
+ * |-----SDP1--> SIP Invite
+ * |<----------- SIP (Invite) Trying
+ * <-------------| MNCC CALL PROC req
+ * |<----------- SIP (Invite) Ringing
+ * <-------------| MNCC ALERT req
+ * | (MT picks up)
+ * |<--SDP2----- SIP (Invite) OK
+ * <--SDP2-------| MNCC RTP CONNECT (SDP optional, still unchanged from SDP2)
+ * <-------------| MNCC SETUP rsp (SDP optional, still unchanged from SDP2)
+ * ------------->| MNCC SETUP COMPL ind (SDP optional, still unchanged from SDP1)
+ * |------------> SIP ACK
+ */
+
+ var charstring cn_sdp := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
+ f_sdp_addr2addrtype(cp.cn_rtp_addr) & " " & cp.cn_rtp_addr &
+ "\r\nt=0 0\r\nm=audio " & int2str(cp.cn_rtp_port) &
+ " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
f_create_sip_expect(cp.comp.sip_url_ext.addr.nameAddr.addrSpec);
/* MSC -> OSC: MSC sends SETUP.ind after CC SETUP was received from MS */
- MNCC.send(ts_MNCC_SETUP_ind(cp.mncc_call_id, dst, src, "262420123456789"));
+ mncc := valueof(ts_MNCC_SETUP_ind(cp.mncc_call_id, dst, src, "262420123456789"));
+ if (cp.mncc_with_sdp) {
+ mncc.u.signal.sdp := cn_sdp;
+ }
+ MNCC.send(mncc);
+
/* MSC <- OSC: Create GSM side RTP socket */
MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) {
- var MNCC_PDU mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
+ mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
mncc.u.rtp.payload_msg_type := oct2int('0300'O);
+ /* FIXME: makes no sense to send cp.cn_rtp_addr back to the cn. */
mncc.u.rtp.is_ipv6 := f_addr_is_ipv6(cp.cn_rtp_addr);
mncc.u.rtp.ip := f_addrstr2addr(cp.cn_rtp_addr);
mncc.u.rtp.rtp_port := cp.cn_rtp_port;
MNCC.send(mncc);
}
+
/* OSC -> SIP: Send INVITE with GSM side IP/Port in SDP */
- SIP.receive(tr_SIP_INVITE(?, sip_addr_gsm, sip_addr_ext, ?, ?)) -> value sip_req {
- cp.comp.sip_url_gsm.params := sip_req.msgHeader.fromField.fromParams;
- cp.comp.sip_call_id := sip_req.msgHeader.callId.callid;
- seq_nr := sip_req.msgHeader.cSeq.seqNumber;
- }
+ var template charstring expect_sdp_to_sip := ?;
+ if (cp.mncc_with_sdp) {
+ /* Expect the same SDP as sent to osmo-sip-connector in MNCC, and allow osmo-sip-connector to append an
+ * "a=sendrecv;" */
+ expect_sdp_to_sip := pattern cn_sdp & "*";
+ }
+ sip_req := f_SIP_expect_req(tr_SIP_INVITE(to_addr_exp.addressField.nameAddr.addrSpec, ?,
+ from_addr_exp, to_addr_exp,
+ via_exp,
+ ?, body := expect_sdp_to_sip));
+ from_addr.fromParams := sip_req.msgHeader.fromField.fromParams;
+ cp.comp.sip_call_id := sip_req.msgHeader.callId.callid;
+ seq_nr := sip_req.msgHeader.cSeq.seqNumber;
+
/* OSC <- SIP: Notify call is proceeding */
- SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
+ SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
"INVITE", 100, seq_nr, "Trying", sip_req.msgHeader.via));
/* MSC <- OSC: "100 Trying" translated to MNCC_CALL_PROC_REQ */
- MNCC.receive(tr_MNCC_CALL_PROC_req(cp.mncc_call_id));
+ MNCC.receive(tr_MNCC_CALL_PROC_req(cp.mncc_call_id)) -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.signal.sdp, "");
+ }
- /* OSC <- SIP: SIP-terminated user is ringing now */
- SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
- "INVITE", 180, seq_nr, "Ringing", sip_req.msgHeader.via));
+ /* OSC <- SIP: SIP-terminated user is ringing now. 180 Ringing should not contain any SDP. */
+ SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
+ "INVITE", 180, seq_nr, "Ringing", sip_req.msgHeader.via, omit));
/* MSC <- OSC: "180 Ringing" translated to MNCC_ALERT_REQ */
- MNCC.receive(tr_MNCC_ALERT_req(cp.mncc_call_id)) {}
+ MNCC.receive(tr_MNCC_ALERT_req(cp.mncc_call_id)) -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
+ }
/* OSC <- SIP: SIP-terminated user has accepted the call */
- SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
+ SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
"INVITE", 200, seq_nr, "OK", sip_req.msgHeader.via,
- cp.comp.sip_body));
- MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id));
+ body := cp.comp.sip_body));
+
+ if (cp.mncc_with_sdp) {
+ /* If we expect SDP forwarding, from now on expect MNCC to reflect the SDP that we just sent on SIP. */
+ expect_sdp_to_msc := cp.comp.sip_body;
+ }
+ /* If we don't expect SDP forwarding, just keep expect_sdp_to_msc := *. */
+
+ MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id)) -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.rtp.sdp, expect_sdp_to_msc);
+ }
/* MSC <- OSC: "200 OK" translated to MNCC_SETUP_RSP */
- MNCC.receive(tr_MNCC_SETUP_rsp(cp.mncc_call_id));
+ MNCC.receive(tr_MNCC_SETUP_rsp(cp.mncc_call_id)) -> value mncc {
+ check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
+ }
/* MSC -> OSC: CC CONNECT ACK was received from MS */
MNCC.send(ts_MNCC_SETUP_COMPL_ind(cp.mncc_call_id));
/* OSC -> SIP: Acknowledge the call */
- SIP.receive(tr_SIP_ACK(cp.comp.sip_call_id, sip_addr_gsm, sip_addr_ext, ?, omit));
+ SIP.receive(tr_SIP_ACK(to_addr_exp.addressField.nameAddr.addrSpec,
+ cp.comp.sip_call_id,
+ from_addr_exp,
+ to_addr_exp,
+ via_exp,
+ ?, omit));
}
/* Release call from the mobile side */
function f_release_mobile(inout CallPars cp) runs on ConnHdlr {
- var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
- var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
+ var template (value) From from_addr := ts_From(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
+ var template (value) To to_addr := ts_To(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
+ var template (value) Via via := ts_Via_from(cp.comp.sip_url_gsm.addr.nameAddr.addrSpec.hostPort);
+ var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
+ var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
+ var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
var PDU_SIP_Request sip_req;
SIP.clear;
/* MSC -> OSC: Simulate a CC DISCONNET from the MT user */
MNCC.send(ts_MNCC_DISC_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
+
/* OSC -> SIP: Expect BYE from OSC to SIP side */
- SIP.receive(tr_SIP_BYE(cp.comp.sip_call_id, sip_addr_gsm, sip_addr_ext, ?, *)) -> value sip_req {
- cp.comp.sip_url_gsm.params := sip_req.msgHeader.fromField.fromParams;
- }
+ sip_req := f_SIP_expect_req(tr_SIP_BYE(to_addr_exp.addressField.nameAddr.addrSpec,
+ cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
+ via_exp,
+ ?, *));
+ from_addr.fromParams := sip_req.msgHeader.fromField.fromParams;
+
/* OSC <- SIP: Acknowledge the BYE */
- SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
+ SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
"BYE", 200, sip_req.msgHeader.cSeq.seqNumber, "OK",
sip_req.msgHeader.via));
/* MSC <- OSC: Send REL_REQ to MSC, triggers CC RELEASE REQ to MS */
@@ -345,18 +537,25 @@ function f_release_mobile(inout CallPars cp) runs on ConnHdlr {
/* Release call from the SIP side */
function f_release_sip(inout CallPars cp) runs on ConnHdlr {
- var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
- var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
+ var template (value) From from_addr := ts_From(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
+ var template (value) To to_addr := ts_To(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
+ var template (value) Via via := ts_Via_from(cp.comp.sip_url_ext.addr.nameAddr.addrSpec.hostPort);
+ var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
+ var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
+ var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
/* OSC <- SIP: SIP-side sends a BYE to OSC */
- SIP.send(ts_SIP_BYE(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
+ SIP.send(ts_SIP_BYE(cp.comp.sip_call_id, from_addr, to_addr,
+ via,
cp.comp.sip_seq_nr, omit));
/* MSC <- OSC: Expect OSC to cause MNCC Disconnect Request */
MNCC.receive(tr_MNCC_DISC_req(cp.mncc_call_id));
/* MSC -> OSC: Indicate GSM side release */
MNCC.send(ts_MNCC_REL_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
/* OSC -> SIP: Confirmation to SIP side */
- SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *,
- "BYE", 200, cp.comp.sip_seq_nr, "OK", omit));
+ as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
+ via_exp,
+ *,
+ "BYE", 200, cp.comp.sip_seq_nr, "OK", omit));
}
/* Successful MT Call, which is subsequently released by GSM side */
@@ -364,7 +563,7 @@ private function f_TC_mt_success_rel_gsm(charstring id) runs on ConnHdlr {
var CallPars cp := g_pars.g_cp;
f_CallPars_compute(cp);
cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
- f_mgcp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
+ f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
"\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
" RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
f_sleep(3.0)
@@ -380,7 +579,7 @@ testcase TC_mt_success_rel_gsm() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
- pars.g_cp := valueof(t_CallPars(false));
+ pars.g_cp := valueof(t_CallPars(false, false));
vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
vc_conn.done;
}
@@ -389,7 +588,7 @@ testcase TC_mt_success_rel_gsm_ipv6() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
- pars.g_cp := valueof(t_CallPars(false));
+ pars.g_cp := valueof(t_CallPars(false, false));
pars.g_cp.sip_rtp_addr := "::1";
pars.g_cp.cn_rtp_addr := "::2";
vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
@@ -398,10 +597,10 @@ testcase TC_mt_success_rel_gsm_ipv6() runs on test_CT {
/* Successful MT Call, which is subsequently released by SIP side */
private function f_TC_mt_success_rel_sip(charstring id) runs on ConnHdlr {
- var CallPars cp := valueof(t_CallPars(false));
+ var CallPars cp := g_pars.g_cp;
f_CallPars_compute(cp);
cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
- f_mgcp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
+ f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
"\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
" RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
f_sleep(3.0)
@@ -417,6 +616,7 @@ testcase TC_mt_success_rel_sip() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
+ pars.g_cp := valueof(t_CallPars(false, false));
vc_conn := f_start_handler(refers(f_TC_mt_success_rel_sip), pars);
vc_conn.done;
}
@@ -427,7 +627,7 @@ private function f_TC_mo_success_rel_gsm(charstring id) runs on ConnHdlr {
var CallPars cp := g_pars.g_cp;
f_CallPars_compute(cp);
cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
- f_mgcp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
+ f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
"\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
" RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
f_sleep(3.0)
@@ -443,7 +643,7 @@ testcase TC_mo_success_rel_gsm() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
- pars.g_cp := valueof(t_CallPars(true));
+ pars.g_cp := valueof(t_CallPars(true, false));
vc_conn := f_start_handler(refers(f_TC_mo_success_rel_gsm), pars);
vc_conn.done;
}
@@ -452,7 +652,7 @@ testcase TC_mo_success_rel_gsm_ipv6() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
- pars.g_cp := valueof(t_CallPars(true));
+ pars.g_cp := valueof(t_CallPars(true, false));
pars.g_cp.sip_rtp_addr := "::1";
pars.g_cp.cn_rtp_addr := "::2";
vc_conn := f_start_handler(refers(f_TC_mo_success_rel_gsm), pars);
@@ -461,10 +661,10 @@ testcase TC_mo_success_rel_gsm_ipv6() runs on test_CT {
/* Successful MO Call, which is subsequently released by SIP side */
private function f_TC_mo_success_rel_sip(charstring id) runs on ConnHdlr {
- var CallPars cp := valueof(t_CallPars(true));
+ var CallPars cp := g_pars.g_cp;
f_CallPars_compute(cp);
cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
- f_mgcp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
+ f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
"\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
" RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
f_sleep(3.0)
@@ -480,24 +680,29 @@ testcase TC_mo_success_rel_sip() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
+ pars.g_cp := valueof(t_CallPars(is_mo := true, mncc_with_sdp := false));
vc_conn := f_start_handler(refers(f_TC_mo_success_rel_sip), pars);
vc_conn.done;
}
/* SETUP followed by DISC results in lingering B-leg (OS#3518)*/
private function f_TC_mo_setup_disc_late_rtp(charstring id) runs on ConnHdlr {
- var CallPars cp := valueof(t_CallPars(true));
+ var CallPars cp := g_pars.g_cp;
f_CallPars_compute(cp);
cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
- f_mgcp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
+ f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
"\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
" RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
f_sleep(3.0);
var MNCC_number dst := valueof(ts_MNCC_number(cp.called, GSM48_TON_UNKNOWN));
var MNCC_number src := valueof(ts_MNCC_number(cp.calling, GSM48_TON_UNKNOWN));
- var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
- var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
+ var template (value) From from_addr := ts_From(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
+ var template (value) To to_addr := ts_To(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
+ var template (value) Via via := ts_Via_from(cp.comp.sip_url_gsm.addr.nameAddr.addrSpec.hostPort);
+ var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
+ var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
+ var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
f_create_sip_expect(cp.comp.sip_url_ext.addr.nameAddr.addrSpec);
@@ -521,7 +726,10 @@ private function f_TC_mo_setup_disc_late_rtp(charstring id) runs on ConnHdlr {
timer T := 10.0;
T.start;
alt {
- [] SIP.receive(tr_SIP_INVITE(?, sip_addr_gsm, sip_addr_ext, ?, ?)) {
+ [] SIP.receive(tr_SIP_INVITE(to_addr_exp.addressField.nameAddr.addrSpec, ?,
+ from_addr_exp, to_addr_exp,
+ via_exp,
+ ?, ?)) {
setverdict(fail, "Received unexpected INVITE");
}
[] T.timeout {
@@ -534,10 +742,31 @@ testcase TC_mo_setup_disc_late_rtp() runs on test_CT {
var ConnHdlr vc_conn;
f_init();
pars := valueof(t_Pars);
+ pars.g_cp := valueof(t_CallPars(is_mo := true, mncc_with_sdp := false));
vc_conn := f_start_handler(refers(f_TC_mo_setup_disc_late_rtp), pars);
vc_conn.done;
}
+testcase TC_mt_with_sdp() runs on test_CT {
+ var ConnHdlrPars pars;
+ var ConnHdlr vc_conn;
+ f_init();
+ pars := valueof(t_Pars);
+ pars.g_cp := valueof(t_CallPars(is_mo := false, mncc_with_sdp := true));
+ vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
+ vc_conn.done;
+}
+
+testcase TC_mo_with_sdp() runs on test_CT {
+ var ConnHdlrPars pars;
+ var ConnHdlr vc_conn;
+ f_init();
+ pars := valueof(t_Pars);
+ pars.g_cp := valueof(t_CallPars(is_mo := true, mncc_with_sdp := true));
+ vc_conn := f_start_handler(refers(f_TC_mo_success_rel_sip), pars);
+ vc_conn.done;
+}
+
control {
execute( TC_mt_success_rel_gsm() );
execute( TC_mt_success_rel_gsm_ipv6() );
@@ -546,6 +775,8 @@ control {
execute( TC_mo_success_rel_gsm_ipv6() );
execute( TC_mo_success_rel_sip() );
execute( TC_mo_setup_disc_late_rtp() );
+ execute( TC_mt_with_sdp() );
+ execute( TC_mo_with_sdp() );
}