pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/37248?usp=email )
Change subject: asterisk: test Precondition extension in IMS MO call ......................................................................
asterisk: test Precondition extension in IMS MO call
Related: SYS#6969 Change-Id: I1e26f3bb9e54be5b5e15a003b2000ae3e88b9027 --- M asterisk/Asterisk_Tests.ttcn M asterisk/IMS_ConnectionHandler.ttcn M asterisk/expected-results.xml M library/SIP_Templates.ttcn 4 files changed, 209 insertions(+), 10 deletions(-)
Approvals: pespin: Looks good to me, approved Jenkins Builder: Verified
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn index 05b1638..981d5f1 100644 --- a/asterisk/Asterisk_Tests.ttcn +++ b/asterisk/Asterisk_Tests.ttcn @@ -49,7 +49,7 @@ charstring mp_ami_user := "test_user"; charstring mp_ami_secret := "1234"; charstring mp_volte_ims_outbound_registration := "volte_ims"; - /* Current default by pjproject (timeout_timer_val) to 32s, and not changed by Asterisk */ + /* Current default by pjproject (timeout_timer_val) is set to 32s, and not changed by Asterisk */ integer mp_volte_ims_outbound_register_timeout := 32; }
@@ -561,8 +561,8 @@ true, false); }
-/* Test SIP registration of local clients */ -private function f_TC_ims_call_mo(charstring id) runs on IMS_ConnHdlr { +/* Test IMS MO call emulating an MT which doesn't support precondition */ +private function f_TC_ims_call_mo_IMS_ConnHdlr(charstring id) runs on IMS_ConnHdlr { f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.subscr.registrar_sip_record.addr))); if (ispresent(g_pars.subscr.cp.called)) { f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr))); @@ -576,7 +576,7 @@ setverdict(pass); as_IMS_unregister(); } -testcase TC_ims_call_mo() runs on test_CT { +private function f_TC_ims_call_mo(boolean use_precondition_ext) runs on test_CT { var SIPConnHdlrPars sip_pars; var IMS_ConnHdlrPars ims_pars; var SIPConnHdlr vc_conn_sip; @@ -595,8 +595,10 @@ ts_UserInfo(ims_pars.subscr.msisdn))); ims_pars.subscr.cp.called := valueof(ts_SipAddr(ts_HostPort(ims_pars.realm), ts_UserInfo(c_ext_msisdn))); + ims_pars.subscr.cp.support_precondition_ext := use_precondition_ext; + ims_pars.subscr.cp.require_precondition_ext := use_precondition_ext;
- vc_conn_ims := f_start_handler_IMS(refers(f_TC_ims_call_mo), ims_pars); + vc_conn_ims := f_start_handler_IMS(refers(f_TC_ims_call_mo_IMS_ConnHdlr), ims_pars); vc_conn_sip := f_start_handler(refers(f_TC_internal_call_mo), sip_pars);
COORD.receive(COORD_CMD_REGISTERED) from vc_conn_sip; @@ -623,6 +625,12 @@ vc_conn_ims.done; f_shutdown(); } +testcase TC_ims_call_mo() runs on test_CT { + f_TC_ims_call_mo(true); +} +testcase TC_ims_call_mo_noprecondition() runs on test_CT { + f_TC_ims_call_mo(false); +}
/* Test SIP registration of local clients */ private function f_TC_ims_call_mt(charstring id) runs on IMS_ConnHdlr { @@ -706,6 +714,7 @@ execute( TC_ims_registration_timeout_protected_100Trying() ); execute( TC_ims_registration_timeout_protected_200OK() ); execute( TC_ims_call_mo() ); + execute( TC_ims_call_mo_noprecondition() ); execute( TC_ims_call_mt() ); }
diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn index 4f3cbb7..860b799 100644 --- a/asterisk/IMS_ConnectionHandler.ttcn +++ b/asterisk/IMS_ConnectionHandler.ttcn @@ -138,6 +138,8 @@ charstring local_rtp_addr, uint16_t local_rtp_port,
+ boolean support_precondition_ext, + boolean require_precondition_ext, SDP_Message peer_sdp optional, IMS_CallParsMT mt } @@ -155,6 +157,8 @@ sip_body := omit, local_rtp_addr := local_rtp_addr, local_rtp_port := local_rtp_port, + support_precondition_ext := true, + require_precondition_ext := false, peer_sdp := omit, mt := t_IMS_CallParsMT } @@ -1104,24 +1108,106 @@ var template (value) PDU_SIP_Response tx_resp; var Via via; var charstring tx_sdp; + var boolean peer_support_precondition := match(g_rx_sip_req.msgHeader.supported.optionsTags, + superset("100rel", "precondition"));
/* Obtain params: */ f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req); via := g_rx_sip_req.msgHeader.via;
f_ims_validate_register_P_Access_Network_info(g_rx_sip_req, exp_present := true); + if (g_pars.subscr.cp.require_precondition_ext and not peer_support_precondition) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str(g_name & ": Missing '100rel,precondition' in INVITE Supported header: ", + g_rx_sip_req.msgHeader.supported)); + }
- - /* Tx 180 Ringing */ - tx_resp := ts_SIP_Response_Ringing(g_pars.subscr.cp.sip_call_id, + /* Tx 100 Tyring */ + tx_resp := ts_SIP_Response_Trying(g_pars.subscr.cp.sip_call_id, g_pars.subscr.cp.from_addr, g_pars.subscr.cp.to_addr, via, - g_pars.subscr.cp.sip_seq_nr); + g_pars.subscr.cp.sip_seq_nr, + "INVITE", + allow := omit, + server := g_pars.server_name, + userAgent := omit); SIP.send(tx_resp);
- /* Tx 200 OK */ tx_sdp := f_gen_sdp(); + + /* Use precondition ? */ + if (g_pars.subscr.cp.require_precondition_ext or + (g_pars.subscr.cp.support_precondition_ext and peer_support_precondition)) { + /* Tx 183 Session Progress */ + /* TODO: add a=curr:qos, a=des:qos and a=conf:qos fields to SDP */ + tx_resp := ts_SIP_Response_SessionProgress(g_pars.subscr.cp.sip_call_id, + g_pars.subscr.cp.from_addr, + g_pars.subscr.cp.to_addr, + via, + g_pars.subscr.cp.sip_seq_nr, + rseq := ts_RSeq(1), + body := tx_sdp); + SIP.send(tx_resp); + + /* Rx PRACK */ + exp_req := tr_SIP_PRACK(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)), + g_pars.subscr.cp.sip_call_id, + g_pars.subscr.cp.from_addr, + g_pars.subscr.cp.to_addr, + f_tr_Via_response(via), + g_pars.subscr.cp.sip_seq_nr + 1, + rack := tr_RAck(1, g_pars.subscr.cp.sip_seq_nr, "INVITE"), + body := omit); + as_SIP_expect_req(exp_req); + + /* Tx 200 OK (PRACK) */ + tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id, + g_pars.subscr.cp.from_addr, + g_pars.subscr.cp.to_addr, + "PRACK", 200, + g_pars.subscr.cp.sip_seq_nr, + "OK", + via, + body := omit); + SIP.send(tx_resp); + + /* Rx UPDATE */ + exp_req := tr_SIP_UPDATE(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)), + g_pars.subscr.cp.sip_call_id, + g_pars.subscr.cp.from_addr, + g_pars.subscr.cp.to_addr, + f_tr_Via_response(via), + g_pars.subscr.cp.sip_seq_nr + 1, + require := tr_Require(superset("precondition")), + body := ?); + as_SIP_expect_req(exp_req); + + /* Tx 200 OK (UPDATE) */ + /* TODO: add a=curr:qos, a=des:qos and a=conf:qos fields to SDP */ + tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id, + g_pars.subscr.cp.from_addr, + g_pars.subscr.cp.to_addr, + "UPDATE", 200, + g_pars.subscr.cp.sip_seq_nr, + "OK", + via, + body := tx_sdp); + SIP.send(tx_resp); + + g_pars.subscr.cp.sip_seq_nr := g_pars.subscr.cp.sip_seq_nr + 1; + } + + /* Tx 180 Ringing */ + tx_resp := ts_SIP_Response_Ringing(g_pars.subscr.cp.sip_call_id, + g_pars.subscr.cp.from_addr, + g_pars.subscr.cp.to_addr, + via, + g_pars.subscr.cp.sip_seq_nr); + SIP.send(tx_resp); + + + /* Tx 200 OK */ tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id, g_pars.subscr.cp.from_addr, g_pars.subscr.cp.to_addr, diff --git a/asterisk/expected-results.xml b/asterisk/expected-results.xml index 6b5def5..e9d2b82 100644 --- a/asterisk/expected-results.xml +++ b/asterisk/expected-results.xml @@ -13,5 +13,6 @@ <testcase classname='Asterisk_Tests' name='TC_ims_registration_timeout_protected_100Trying' time='MASKED'/> <testcase classname='Asterisk_Tests' name='TC_ims_registration_timeout_protected_200OK' time='MASKED'/> <testcase classname='Asterisk_Tests' name='TC_ims_call_mo' time='MASKED'/> + <testcase classname='Asterisk_Tests' name='TC_ims_call_mo_noprecondition' time='MASKED'/> <testcase classname='Asterisk_Tests' name='TC_ims_call_mt' time='MASKED'/> </testsuite> diff --git a/library/SIP_Templates.ttcn b/library/SIP_Templates.ttcn index 77d4ee0..cfe21eb 100644 --- a/library/SIP_Templates.ttcn +++ b/library/SIP_Templates.ttcn @@ -284,6 +284,24 @@ p_assoc_uris := p_assoc_uris }
+// RFC 3262 +template (value) RAck ts_RAck(template (value) integer response_num, + template (value) integer seq_nr, + template (value) charstring method := "INVITE") := { + fieldName := RACK_E, + response_num := response_num, + seqNumber := seq_nr, + method := method +} +template (present) RAck tr_RAck(template (present) integer response_num := ?, + template (present) integer seq_nr := ?, + template (present) charstring method := ?) := { + fieldName := RACK_E, + response_num := response_num, + seqNumber := seq_nr, + method := method +} + // [20.32] template (value) Require ts_Require(template (value) OptionTag_List optionsTags := {}) := { fieldName := REQUIRE_E, @@ -294,6 +312,16 @@ optionsTags := optionsTags }
+// RFC 3262 +template (value) RSeq ts_RSeq(template (value) integer response_num) := { + fieldName := RSEQ_E, + response_num := response_num +} +template (present) RSeq tr_RSeq(template (present) integer response_num := ?) := { + fieldName := RSEQ_E, + response_num := response_num +} + // [20.35 RFC2616 14.38] template (value) Server ts_Server(template (value) ServerVal_List serverBody := {}) := { fieldName := SERVER_E, @@ -652,7 +680,9 @@ template (omit) Allow allow := ts_Allow(c_SIP_defaultMethods), template (omit) Expires expires := omit, template (omit) P_Associated_Uri p_associated_uri := omit, + template (omit) RAck rack := omit, template (omit) Require require := omit, + template (omit) RSeq rseq := omit, template (omit) Security_client security_client := omit, template (omit) Security_server security_server := omit, template (omit) Server server := omit, @@ -677,7 +707,9 @@ expires := expires, fromField := from_addr, p_associated_uri := p_associated_uri, + rack := rack, require := require, + rseq := rseq, security_client := security_client, security_server := security_server, server := server, @@ -702,6 +734,7 @@ template Authorization authorization := *, template Expires expires := *, template P_Associated_Uri p_associated_uri := *, + template RAck rack := *, template Require require := *, template Security_client security_client := *, template Security_server security_server := *, @@ -727,6 +760,7 @@ expires := expires, fromField := from_addr, p_associated_uri := p_associated_uri, + rack := rack, require := require, security_client := security_client, security_server := security_server, @@ -905,6 +939,42 @@ payload := omit }
+template (present) PDU_SIP_Request +tr_SIP_PRACK(template (present) SipUrl uri, + template CallidString call_id, + template From from_addr, + template To to_addr, + template Via via, + template integer seq_nr, + template RAck rack := tr_RAck(?, ?, ?), + template charstring body := *) := { + requestLine := tr_SIP_ReqLine(PRACK_E, uri), + msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *, + via, + "PRACK", seq_nr, + rack := rack), + messageBody := body, + payload := omit +} + +template (present) PDU_SIP_Request +tr_SIP_UPDATE(template (present) SipUrl uri, + template CallidString call_id, + template From from_addr, + template To to_addr, + template Via via, + template integer seq_nr, + template Require require := *, + template charstring body) := { + requestLine := tr_SIP_ReqLine(UPDATE_E, uri), + msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *, + via, + "UPDATE", seq_nr, + require := require), + messageBody := body, + payload := omit +} + template (value) PDU_SIP_Response ts_SIP_Response(template (value) CallidString call_id, template (value) From from_addr, @@ -979,6 +1049,29 @@ payload := omit }
+/* 183 Session Progress */ +template (value) PDU_SIP_Response +ts_SIP_Response_SessionProgress( + template (value) CallidString call_id, + template (value) From from_addr, + template (value) To to_addr, + Via via, + integer seq_nr, + charstring method := "INVITE", + template (omit) Require require := ts_Require({"100rel", "precondition"}), + template (omit) RSeq rseq := ts_RSeq(1), + template (omit) charstring body := omit) := { + statusLine := ts_SIP_StatusLine(183, "Session Progress"), + msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr, + via, + content_length := f_ContentLength(body), + content_type := f_ContentTypeOrOmit(ts_CT_SDP, body), + require := require, + rseq := rseq), + messageBody := body, + payload := omit +} + /* 401 Unauthorized */ template (value) PDU_SIP_Response ts_SIP_Response_Unauthorized(