pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/36756?usp=email )
Change subject: WIP: asterisk: Initial IMS registration ......................................................................
WIP: asterisk: Initial IMS registration
Change-Id: Idbb390e34ab3d008009a0f1b182c4165c86100e4 --- M asterisk/AMI_Functions.ttcn M asterisk/Asterisk_Tests.ttcn M asterisk/IMS_ConnectionHandler.ttcn 3 files changed, 211 insertions(+), 6 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/56/36756/1
diff --git a/asterisk/AMI_Functions.ttcn b/asterisk/AMI_Functions.ttcn index a144239..1223051 100644 --- a/asterisk/AMI_Functions.ttcn +++ b/asterisk/AMI_Functions.ttcn @@ -26,7 +26,7 @@ }
const charstring AMI_FIELD_ACTION := "Action"; -const charstring AMI_FIELD_ACTION_ID := "ActionId"; +const charstring AMI_FIELD_ACTION_ID := "ActionID"; const charstring AMI_FIELD_USERNAME := "Username"; const charstring AMI_FIELD_SECRET := "Secret"; const charstring AMI_FIELD_RESPONSE := "Response"; @@ -115,16 +115,21 @@ * Secret: <value> */ template (value) AMI_Msg -ts_AMI_Action_Login(charstring username, charstring secret) := { +ts_AMI_Action_Login(charstring username, + charstring secret, + template (value) charstring action_id := "0001") := { ts_AMI_Field_Action("Login"), + ts_AMI_Field_ActionId(action_id), ts_AMI_Field_Username(username), ts_AMI_Field_Secret(secret) };
template (present) AMI_Msg tr_AMI_Action_Login(template(present) charstring username := ?, - template(present) charstring secret := ?) := superset( + template(present) charstring secret := ?, + template (present) charstring action_id := ?) := superset( tr_AMI_Field_Action("Login"), + tr_AMI_Field_ActionId(action_id), tr_AMI_Field_Username(username), tr_AMI_Field_Secret(secret) ); @@ -466,7 +471,8 @@ }
function f_ami_action_login(AMI_Msg_PT pt, charstring username, charstring secret) { - f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret)); + var charstring reg_action_id := f_gen_action_id(); + f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret, reg_action_id)); }
function f_ami_action_PJSIPRegister(AMI_Msg_PT pt, charstring register) { diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn index 08a5f65..acaafb8 100644 --- a/asterisk/Asterisk_Tests.ttcn +++ b/asterisk/Asterisk_Tests.ttcn @@ -37,6 +37,7 @@
charstring mp_local_ims_host := "127.0.0.3"; integer mp_local_ims_port := 5060; + charstring mp_ims_imsi := "001010000000002";
/* Asterisk AMI: */ charstring mp_ami_remote_host := "127.0.0.1"; @@ -45,6 +46,7 @@ integer mp_ami_local_port := 0; charstring mp_ami_user := "test_user"; charstring mp_ami_secret := "1234"; + charstring mp_volte_ims_outbound_registration := "volte_ims"; }
type component test_CT { @@ -74,6 +76,15 @@ return valueof(pars); }
+function f_init_IMS_ConnHdlrPars(integer idx := 1) runs on test_CT return IMS_ConnHdlrPars { + var template (value) IMS_CallPars cp := t_IMS_CallPars(mp_local_sip_host, 1234 + 2*idx); + var template (value) IMS_ConnHdlrPars pars := t_IMS_Pars(mp_local_ims_host, + mp_local_ims_port, + mp_ims_imsi, + cp := cp); + return valueof(pars); +} + /* Initialize connection towards Asterisk AMI */ private function f_init_ami() runs on test_CT { var charstring id := "Asterisk_Tests_AMI_EMU"; @@ -139,6 +150,22 @@ return vc_conn; }
+function f_start_handler_IMS(ims_void_fn fn, IMS_ConnHdlrPars pars) +runs on test_CT return IMS_ConnHdlr { + var IMS_ConnHdlr vc_conn; + var charstring id := testcasename() & "-IMS_ConnHdlr-" & pars.user; + + vc_conn := IMS_ConnHdlr.create(id) alive; + + connect(vc_conn:SIP, vc_SIP:CLIENT); + connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC); + + connect(vc_conn:COORD, self:IMS_COORD); + + vc_conn.start(f_ims_handler_init(fn, id, pars)); + return vc_conn; +} + /* Test SIP registration of local clients */ private function f_TC_internal_registration(charstring id) runs on SIPConnHdlr {
@@ -322,12 +349,48 @@ setverdict(pass); }
+/* Test SIP registration of local clients */ +private function f_TC_ims_registration(charstring id) runs on IMS_ConnHdlr { + as_IMS_register(); + setverdict(pass); +} +testcase TC_ims_registration() runs on test_CT { + var IMS_ConnHdlrPars pars; + var IMS_ConnHdlr vc_conn; + f_init(); + pars := f_init_IMS_ConnHdlrPars(); + vc_conn := f_start_handler_IMS(refers(f_TC_ims_registration), pars); + + /* Clear events: */ + AMI_CLIENT.clear; + /* Trigger registration: */ + f_ami_action_PJSIPRegister(AMI_CLIENT, mp_volte_ims_outbound_registration); + /* TODO: Rx "Event: AuthRequest" */ + /* TODO: Tx "Action: AuthResponse" */ + /* TODO: Rx "Response: Success" */ + /* TODO: once registration is successful, rx: + * Event: Registry + * ChannelType: pjsip + * Username: <value> + * Domain: <value> + * Status: <value> + * Cause: <value> */ + + /* TODO: test "Action: PJSIPUnregister" */ + + /* TODO: in another test emulating a call, test "Action: DedicatedBearerStatus" */ + + vc_conn.done; + f_shutdown(); +} + control { execute( TC_internal_registration() ); execute( TC_internal_call_momt() ); execute( TC_internal_call_all_2registered() ); execute( TC_internal_call_all_3registered() ); execute( TC_internal_call_all_4registered() ); + execute( TC_ims_registration() ); }
} diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn index a1baeb4..cded5fc 100644 --- a/asterisk/IMS_ConnectionHandler.ttcn +++ b/asterisk/IMS_ConnectionHandler.ttcn @@ -43,8 +43,8 @@
type record IMS_ConnHdlrPars { float t_guard, - charstring remote_sip_host, - uint16_t remote_sip_port, + charstring remote_sip_host optional, + uint16_t remote_sip_port optional, charstring user, charstring display_name, charstring password, @@ -66,6 +66,10 @@ /* Whether to expect CANCEL instead of ACK as answer to our OK */ boolean exp_cancel } +template (value) IMS_CallParsMT t_IMS_CallParsMT := { + wait_coord_cmd_pickup := false, + exp_cancel := false +}
type record IMS_CallPars { SipAddr calling optional, @@ -85,4 +89,127 @@ IMS_CallParsMT mt }
+template (value) IMS_CallPars t_IMS_CallPars(charstring local_rtp_addr, + uint16_t local_rtp_port := 0, + template (omit) SipAddr calling := omit, + template (omit) SipAddr called := omit) := { + calling := calling, + called := called, + from_addr := omit, + to_addr := omit, + sip_call_id := hex2str(f_rnd_hexstring(15)), + sip_seq_nr := f_sip_rand_seq_nr(), + sip_body := omit, + local_rtp_addr := local_rtp_addr, + local_rtp_port := local_rtp_port, + peer_sdp := omit, + mt := t_IMS_CallParsMT +} + +template (value) IMS_ConnHdlrPars t_IMS_Pars(charstring local_sip_host, + uint16_t local_sip_port, + charstring user, + charstring display_name := "Anonymous", + charstring password := "secret", + template (omit) IMS_CallPars cp := omit) := { + t_guard := 30.0, + remote_sip_host := omit, + remote_sip_port := omit, + user := user, + display_name := f_sip_str_quote(display_name), + password := password, + registrar_sip_req_uri := valueof(ts_SipUrlHost(local_sip_host)), + registrar_sip_record := ts_SipAddr(ts_HostPort(local_sip_host), + ts_UserInfo(user), + f_sip_str_quote(display_name)), + registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & local_sip_host, + registrar_sip_seq_nr := f_sip_rand_seq_nr(), + local_via := ts_Via_from(ts_HostPort(local_sip_host, local_sip_port)), + local_sip_url_ext := ts_SipUrl(ts_HostPort(local_sip_host, local_sip_port), + ts_UserInfo(user)), + local_sip_record := ts_SipAddr(ts_HostPort(local_sip_host), + ts_UserInfo(user)), + local_contact := valueof(ts_Contact({ + ts_ContactAddress( + ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort( + local_sip_host, + local_sip_port), + ts_UserInfo(user))), + omit) + })), + cp := cp +} + +private altstep as_Tguard() runs on IMS_ConnHdlr { + [] g_Tguard.timeout { + setverdict(fail, "Tguard timeout"); + mtc.stop; + } +} + +type function ims_void_fn(charstring id) runs on IMS_ConnHdlr; +function f_ims_handler_init(ims_void_fn fn, charstring id, IMS_ConnHdlrPars pars) +runs on IMS_ConnHdlr { + g_name := id; + g_pars := pars; + g_Tguard.start(pars.t_guard); + activate(as_Tguard()); + + /* call the user-supied test case function */ + fn.apply(id); +} + +private altstep as_SIP_fail_req(charstring exp_msg_str := "") runs on IMS_ConnHdlr +{ + var PDU_SIP_Request sip_req; + [] SIP.receive(PDU_SIP_Request:?) -> value sip_req { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str(g_name & ": Received unexpected SIP Req message := ", sip_req, "\nvs exp := ", exp_msg_str)); + } +} + +private altstep as_SIP_fail_resp(charstring exp_msg_str := "") runs on IMS_ConnHdlr +{ + var PDU_SIP_Response sip_resp; + [] SIP.receive(PDU_SIP_Response:?) -> value sip_resp { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str(g_name & ": Received unexpected SIP Resp message := ", sip_resp, "\nvs exp := ", exp_msg_str)); + } +} + +/* Peer is calling us, accept it: */ +altstep as_IMS_register(boolean exp_update_to_direct_rtp := true, + boolean fail_others := true) runs on IMS_ConnHdlr +{ + var template (present) PDU_SIP_Request exp_req := + tr_SIP_REGISTER(g_pars.registrar_sip_req_uri, + ?, + tr_SipAddr(), + tr_SipAddr(), + tr_Via_from(?)); + var charstring sip_expect_str := log2str(exp_req); + + [] SIP.receive(exp_req) -> value g_rx_sip_req { + var template (value) PDU_SIP_Response tx_resp; + var Via via; + var charstring tx_sdp; + + via := g_rx_sip_req.msgHeader.via; + + /* Tx 200 OK + * TODO: Tx Unauthorized instead, with IMS params */ + tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id, + g_pars.cp.from_addr, + g_pars.cp.to_addr, + "REGISTER", 200, + g_pars.cp.sip_seq_nr, + "OK", + via); + SIP.send(tx_resp); + } + [fail_others] as_SIP_fail_resp(sip_expect_str); + [fail_others] as_SIP_fail_req(sip_expect_str); + +} + }