blob: c883bac5a88402bec0eb5dd201ee23f531171152 [file] [log] [blame]
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +01001module Asterisk_Tests {
2
3/* Asterisk test suite in TTCN-3
4 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
5 * All rights reserved.
6 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
7 *
8 * Released under the terms of GNU General Public License, Version 2 or
9 * (at your option) any later version.
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020014import from TCCOpenSecurity_Functions all;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010015import from General_Types all;
16import from Osmocom_Types all;
17import from Native_Functions all;
18import from Misc_Helpers all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020019import from TELNETasp_PortType all;
20import from AMI_Functions all;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010021
22import from SDP_Types all;
23import from SDP_Templates all;
24
25import from SIP_Emulation all;
26import from SIPmsg_Types all;
27import from SIP_Templates all;
28
29modulepar {
30 charstring mp_local_sip_host := "127.0.0.2";
31 integer mp_local_sip_port := 5060;
32 charstring mp_remote_sip_host := "127.0.0.1";
33 integer mp_remote_sip_port := 5060;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020034
35 /* Asterisk AMI: */
36 charstring mp_ami_user := "test_user";
37 charstring mp_ami_secret := "1234";
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010038}
39
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020040type port Coord_PT message
41{
42 inout charstring;
43} with { extension "internal" };
44private const charstring COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
45private const charstring COORD_CMD_START := "COORD_CMD_START";
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020046private const charstring COORD_CMD_PICKUP := "COORD_CMD_PICKUP";
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020047private const charstring COORD_CMD_CALL_ESTABLISHED := "COORD_CMD_CALL_ESTABLISHED";
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020048private const charstring COORD_CMD_CALL_CANCELLED := "COORD_CMD_CALL_CANCELLED";
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020049private const charstring COORD_CMD_HANGUP := "COORD_CMD_HANGUP";
50
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010051type component test_CT {
52 var SIP_Emulation_CT vc_SIP;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020053 port TELNETasp_PT AMI;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020054 port Coord_PT COORD;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010055}
56
57type component ConnHdlr extends SIP_ConnHdlr {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020058 var charstring g_name;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010059 var ConnHdlrPars g_pars;
60 timer g_Tguard;
61 var PDU_SIP_Request g_rx_sip_req;
62 var PDU_SIP_Response g_rx_sip_resp;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020063
64 port Coord_PT COORD;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010065}
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020066type record of ConnHdlr ConnHdlrList;
67
68const charstring broadcast_sip_extension := "0500";
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010069
70type record ConnHdlrPars {
71 float t_guard,
72 charstring user,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020073 charstring display_name,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020074 charstring password,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020075 SipUrl registrar_sip_req_uri,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010076 SipAddr registrar_sip_record,
77 CallidString registrar_sip_call_id,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010078 integer registrar_sip_seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020079 Via local_via,
80 SipUrl local_sip_url_ext,
81 SipAddr local_sip_record,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010082 Contact local_contact,
83 CallPars cp optional
84}
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020085type record of ConnHdlrPars ConnHdlrParsList;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010086
87template (value) ConnHdlrPars t_Pars(charstring user,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020088 charstring display_name := "Anonymous",
89 charstring password := "secret",
90 template (value) CallPars cp := t_CallPars()) := {
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010091 t_guard := 30.0,
92 user := user,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020093 display_name := f_sip_str_quote(display_name),
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020094 password := password,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020095 registrar_sip_req_uri := valueof(ts_SipUrlHost(mp_remote_sip_host)),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010096 registrar_sip_record := ts_SipAddr(ts_HostPort(mp_remote_sip_host),
97 ts_UserInfo(user),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020098 f_sip_str_quote(display_name)),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010099 registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & mp_local_sip_host,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100100 registrar_sip_seq_nr := f_sip_rand_seq_nr(),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200101 local_via := ts_Via_from(ts_HostPort(mp_local_sip_host, mp_local_sip_port)),
102 local_sip_url_ext := ts_SipUrl(ts_HostPort(mp_local_sip_host, mp_local_sip_port),
103 ts_UserInfo(user)),
104 local_sip_record := ts_SipAddr(ts_HostPort(mp_local_sip_host),
105 ts_UserInfo(user)),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100106 local_contact := valueof(ts_Contact({
107 ts_ContactAddress(
108 ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
109 mp_local_sip_host,
110 mp_local_sip_port),
111 ts_UserInfo(user))),
112 omit)
113 })),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200114 cp := cp
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100115}
116
117function f_init_ConnHdlrPars(integer idx := 1) runs on test_CT return ConnHdlrPars {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200118 var template (value) CallPars cp := t_CallPars(idx := idx);
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200119 var template (value) ConnHdlrPars pars := t_Pars("0" & int2str(str2int(broadcast_sip_extension) + idx),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200120 cp := cp);
121 return valueof(pars);
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100122}
123
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200124type record CallParsMT {
125 /* Whether to wait for COORD.receive(COORD_CMD_PICKUP) before accepting the call. */
126 boolean wait_coord_cmd_pickup,
127 /* Whether to expect CANCEL instead of ACK as answer to our OK */
128 boolean exp_cancel
129}
130private template (value) CallParsMT t_CallParsMT := {
131 wait_coord_cmd_pickup := false,
132 exp_cancel := false
133}
134
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100135type record CallPars {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200136 SipAddr calling optional,
137 SipAddr called optional,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100138
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200139 SipAddr from_addr optional,
140 SipAddr to_addr optional,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100141
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100142 CallidString sip_call_id,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200143 integer sip_seq_nr,
144 charstring sip_body optional,
145
146 charstring local_rtp_addr,
147 uint16_t local_rtp_port,
148
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200149 SDP_Message peer_sdp optional,
150 CallParsMT mt
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100151}
152
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200153private template (value) CallPars t_CallPars(integer idx := 1,
154 template (omit) SipAddr calling := omit,
155 template (omit) SipAddr called := omit) := {
156 calling := calling,
157 called := called,
158 from_addr := omit,
159 to_addr := omit,
160 sip_call_id := hex2str(f_rnd_hexstring(15)),
161 sip_seq_nr := f_sip_rand_seq_nr(),
162 sip_body := omit,
163 local_rtp_addr := mp_local_sip_host,
164 local_rtp_port := 1234 + 2*idx,
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200165 peer_sdp := omit,
166 mt := t_CallParsMT
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100167}
168
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200169/* Initialize connection towards Asterisk AMI */
170private function f_init_ami() runs on test_CT {
171 map(self:AMI, system:AMI);
172 f_ami_action_login(AMI, mp_ami_user, mp_ami_secret);
173}
174
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100175function f_init() runs on test_CT {
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200176 f_init_ami();
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100177 f_init_sip(vc_SIP, "Asterisk_Test");
178 log("end of f_init");
179}
180
181type function void_fn(charstring id) runs on ConnHdlr;
182
183function f_start_handler(void_fn fn, ConnHdlrPars pars)
184runs on test_CT return ConnHdlr {
185 var ConnHdlr vc_conn;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200186 var charstring id := testcasename() & "-ConnHdlr-" & pars.user;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100187
Pau Espin Pedrole94a6482024-04-10 13:37:55 +0200188 vc_conn := ConnHdlr.create(id) alive;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100189
190 connect(vc_conn:SIP, vc_SIP:CLIENT);
191 connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
192
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200193 connect(vc_conn:COORD, self:COORD);
194
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100195 vc_conn.start(f_handler_init(fn, id, pars));
196 return vc_conn;
197}
198
199private altstep as_Tguard() runs on ConnHdlr {
200 [] g_Tguard.timeout {
201 setverdict(fail, "Tguard timeout");
202 mtc.stop;
203 }
204}
205
206private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
207runs on ConnHdlr {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200208 g_name := id;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100209 g_pars := pars;
210 g_Tguard.start(pars.t_guard);
211 activate(as_Tguard());
212
213 // Make sure the UA is deregistered before starting the test:
214 // sends REGISTER with Contact = "*" and Expires = 0
215 //f_SIP_deregister();
216
217 /* call the user-supied test case function */
218 fn.apply(id);
219}
220
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200221private altstep as_SIP_fail_req(charstring exp_msg_str := "") runs on ConnHdlr
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100222{
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200223 var PDU_SIP_Request sip_req;
224 [] SIP.receive(PDU_SIP_Request:?) -> value sip_req {
225 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
226 log2str(g_name & ": Received unexpected SIP Req message := ", sip_req, "\nvs exp := ", exp_msg_str));
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100227 }
228}
229
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200230private altstep as_SIP_fail_resp(charstring exp_msg_str := "") runs on ConnHdlr
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100231{
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200232 var PDU_SIP_Response sip_resp;
233 [] SIP.receive(PDU_SIP_Response:?) -> value sip_resp {
234 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
235 log2str(g_name & ": Received unexpected SIP Resp message := ", sip_resp, "\nvs exp := ", exp_msg_str));
236 }
237}
238
239altstep as_SIP_expect_req(template (present) PDU_SIP_Request sip_expect, boolean fail_others := true) runs on ConnHdlr
240{
241 var charstring sip_expect_str := log2str(sip_expect);
242 [] SIP.receive(sip_expect) -> value g_rx_sip_req;
243 [fail_others] as_SIP_fail_req(sip_expect_str);
244 [fail_others] as_SIP_fail_resp(sip_expect_str);
245}
246
247altstep as_SIP_expect_resp(template (present) PDU_SIP_Response sip_expect, boolean fail_others := true) runs on ConnHdlr
248{
249 var charstring sip_expect_str := log2str(sip_expect);
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100250 [] SIP.receive(sip_expect) -> value g_rx_sip_resp;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200251 [fail_others] as_SIP_fail_resp(sip_expect_str);
252 [fail_others] as_SIP_fail_req(sip_expect_str);
253}
254
255altstep as_SIP_ignore_resp(template PDU_SIP_Response sip_expect := ?) runs on ConnHdlr
256{
257 [] SIP.receive(sip_expect) -> value g_rx_sip_resp {
258 log("Ignoring ", g_rx_sip_resp);
259 repeat;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100260 }
261}
262
263private function f_tr_Via_response(Via via_req) return template (present) Via {
264 template (present) SemicolonParam_List via_resp_params := ?;
265
266 /*via_resp_params := {
267 { id := "rport", paramValue := int2str(mp_remote_sip_port) },
268 { id := "received", paramValue := mp_remote_sip_host }
269 }; */
270 return tr_Via_from(via_req.viaBody[0].sentBy,
271 via_resp_params);
272}
273
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200274private function f_tr_To_response(template (value) SipAddr to_req) return template (present) SipAddr {
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200275 return tr_SipAddr_from_val(to_req);
276}
277
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200278private function f_tr_From(template (value) SipAddr from_req) return template (present) SipAddr {
279 return tr_SipAddr_from_val(from_req);
280}
281
282private function f_gen_sdp() runs on ConnHdlr return charstring {
283 var charstring sdp :=
284 "v=0\r\n" &
285 "o=0502 2390 1824 IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
286 "s=Talk\r\n" &
287 "c=IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
288 "t=0 0\r\n" &
289 "a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
290 "a=record:off\r\n" &
291 "m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 96 97 98 0 8 18 99 100 101\r\n" &
292 "a=rtpmap:96 opus/48000/2\r\n" &
293 "a=fmtp:96 useinbandfec=1\r\n" &
294 "a=rtpmap:97 speex/16000\r\n" &
295 "a=fmtp:97 vbr=on\r\n" &
296 "a=rtpmap:98 speex/8000\r\n" &
297 "a=fmtp:98 vbr=on\r\n" &
298 "a=fmtp:18 annexb=yes\r\n" &
299 "a=rtpmap:99 telephone-event/48000\r\n" &
300 "a=rtpmap:100 telephone-event/16000\r\n" &
301 "a=rtpmap:101 telephone-event/8000\r\n" &
302 "a=rtcp:" & int2str(g_pars.cp.local_rtp_port + 1) & "\r\n" &
303 "a=rtcp-fb:* trr-int 1000\r\n" &
304 "a=rtcp-fb:* ccm tmmbr\r\n";
305 return sdp;
306}
307
308private function f_SIP_register() runs on ConnHdlr return PDU_SIP_Response
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100309{
310 var template (present) PDU_SIP_Response exp;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200311 var Authorization authorization;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200312 var Via via := g_pars.local_via;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200313 var SipAddr from_sipaddr := g_pars.registrar_sip_record;
314 var charstring branch_value;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100315
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200316 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
317 f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
318 g_pars.registrar_sip_call_id,
319 g_pars.registrar_sip_seq_nr);
320
321 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
322 from_sipaddr.params := f_sip_param_set(from_sipaddr.params, "tag", f_sip_rand_tag());
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200323 SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_req_uri,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100324 g_pars.registrar_sip_call_id,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200325 from_sipaddr,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100326 g_pars.registrar_sip_record,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200327 via,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100328 g_pars.registrar_sip_seq_nr,
329 g_pars.local_contact,
330 ts_Expires("7200")));
331
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200332 exp := tr_SIP_Response_Unauthorized(
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100333 g_pars.registrar_sip_call_id,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200334 from_sipaddr,
335 f_tr_To_response(g_pars.registrar_sip_record),
336 f_tr_Via_response(via),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100337 *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200338 tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100339 g_pars.registrar_sip_seq_nr);
340 as_SIP_expect_resp(exp);
341
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200342 /* Digest Auth: RFC 2617 */
343 authorization := f_sip_digest_gen_Authorization(g_rx_sip_resp.msgHeader.wwwAuthenticate,
344 g_pars.user, g_pars.password,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200345 "REGISTER",
346 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200347
348 /* New transaction: */
349 g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
350 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
351 f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
352 g_pars.registrar_sip_call_id,
353 g_pars.registrar_sip_seq_nr);
354 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
355
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200356 SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_req_uri,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200357 g_pars.registrar_sip_call_id,
358 from_sipaddr,
359 g_pars.registrar_sip_record,
360 via,
361 g_pars.registrar_sip_seq_nr,
362 g_pars.local_contact,
363 ts_Expires("7200"),
364 authorization := authorization));
365
366 /* Wait for OK answer */
367 exp := tr_SIP_Response(
368 g_pars.registrar_sip_call_id,
369 from_sipaddr,
370 f_tr_To_response(g_pars.registrar_sip_record),
371 f_tr_Via_response(via),
372 *,
373 "REGISTER", 200,
374 g_pars.registrar_sip_seq_nr, "OK");
375 as_SIP_expect_resp(exp);
376
377 /* Prepare for next use: */
378 g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100379 return g_rx_sip_resp;
380}
381
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200382private function f_SIP_mo_call_setup() runs on ConnHdlr
383{
384 var template (value) PDU_SIP_Request req;
385 var template (present) PDU_SIP_Response exp;
386 var Via via;
387 var charstring tx_sdp := f_gen_sdp();
388 var default d_trying, d_ringing;
389 var charstring branch_value;
390
391 /* RFC 3261 8.1.1.3 From */
392 g_pars.cp.from_addr := g_pars.cp.calling;
393 g_pars.cp.from_addr.params := f_sip_param_set(g_pars.cp.from_addr.params, "tag", f_sip_rand_tag());
394 g_pars.cp.to_addr := g_pars.cp.called;
395 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.cp.from_addr),
396 f_sip_SipAddr_to_str(valueof(g_pars.cp.to_addr)),
397 g_pars.cp.sip_call_id,
398 g_pars.cp.sip_seq_nr);
399 via := g_pars.local_via;
400 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
401
402 req := ts_SIP_INVITE(g_pars.cp.sip_call_id,
403 g_pars.cp.from_addr,
404 g_pars.cp.to_addr,
405 via,
406 g_pars.local_contact,
407 g_pars.cp.sip_seq_nr,
408 body := tx_sdp);
409
410 SIP.send(req);
411
412 /* RFC 3261 22.2: */
413 exp := tr_SIP_Response_Unauthorized(
414 g_pars.cp.sip_call_id,
415 f_tr_From(g_pars.cp.from_addr),
416 f_tr_To_response(g_pars.cp.to_addr),
417 f_tr_Via_response(via),
418 *,
419 tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
420 g_pars.cp.sip_seq_nr, "INVITE");
421 as_SIP_expect_resp(exp);
422
423 /* Digest Auth: RFC 2617 */
424 req.msgHeader.authorization := f_sip_digest_gen_Authorization(
425 g_rx_sip_resp.msgHeader.wwwAuthenticate,
426 g_pars.user, g_pars.password,
427 "INVITE",
428 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
429 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
430 f_sip_Request_inc_seq_nr(req);
431 SIP.send(req);
432
433 /* Conditionally match and accept 100 Trying. */
434 exp := tr_SIP_Response_Trying(g_pars.cp.sip_call_id,
435 g_pars.cp.from_addr,
436 f_tr_To_response(g_pars.cp.to_addr),
437 f_tr_Via_response(via),
438 g_pars.cp.sip_seq_nr, "INVITE");
439 d_trying := activate(as_SIP_ignore_resp(exp));
440
441 /* Conditionally match and accept 180 Ringing */
442 exp := tr_SIP_Response_Ringing(g_pars.cp.sip_call_id,
443 g_pars.cp.from_addr,
444 f_tr_To_response(g_pars.cp.to_addr),
445 f_tr_Via_response(via),
446 g_pars.cp.sip_seq_nr, "INVITE");
447 d_ringing := activate(as_SIP_ignore_resp(exp));
448
449 /* Wait for OK answer */
450 exp := tr_SIP_Response(
451 g_pars.cp.sip_call_id,
452 g_pars.cp.from_addr,
453 f_tr_To_response(g_pars.cp.to_addr),
454 f_tr_Via_response(via),
455 *,
456 "INVITE", 200,
457 g_pars.cp.sip_seq_nr, "OK",
458 body := ?);
459 as_SIP_expect_resp(exp, fail_others := false);
460
461 deactivate(d_trying);
462 deactivate(d_ringing);
463
464 /* Update To with the tags received from peer: */
465 g_pars.cp.to_addr := valueof(ts_SipAddr_from_Addr_Union(g_rx_sip_resp.msgHeader.toField.addressField,
466 g_rx_sip_resp.msgHeader.toField.toParams));
467
468 /* Transmit ACK */
469 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
470 req := ts_SIP_ACK(g_pars.cp.sip_call_id,
471 g_pars.cp.from_addr,
472 g_pars.cp.to_addr,
473 via,
474 g_pars.cp.sip_seq_nr,
475 omit);
476 SIP.send(req);
477 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
478}
479
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200480private function f_ConnHdlr_parse_initial_SIP_INVITE(PDU_SIP_Request rx_sip_req) runs on ConnHdlr
481{
482 f_SDP_decodeMessage(rx_sip_req.messageBody, g_pars.cp.peer_sdp);
483 log("Rx Initial MT INVITE decoded SDP: ", g_pars.cp.peer_sdp);
484
485 /* Obtain params: */
486 g_pars.cp.sip_call_id := rx_sip_req.msgHeader.callId.callid;
487 g_pars.cp.from_addr := valueof(ts_SipAddr_from_Addr_Union(rx_sip_req.msgHeader.fromField.addressField,
488 rx_sip_req.msgHeader.fromField.fromParams));
489 g_pars.cp.to_addr := valueof(ts_SipAddr_from_Addr_Union(rx_sip_req.msgHeader.toField.addressField,
490 rx_sip_req.msgHeader.toField.toParams));
491 g_pars.cp.to_addr.params := f_sip_param_set(g_pars.cp.to_addr.params, "tag", f_sip_rand_tag());
492 g_pars.cp.sip_seq_nr := rx_sip_req.msgHeader.cSeq.seqNumber;
493}
494
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200495/* Peer is calling us, accept it: */
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200496private altstep as_SIP_mt_call_accept(boolean exp_update_to_direct_rtp := true,
497 boolean fail_others := true) runs on ConnHdlr
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200498{
499 var template (present) PDU_SIP_Request exp_req :=
500 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
501 ?,
502 f_tr_From(g_pars.cp.calling),
503 g_pars.cp.called,
504 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
505 ?, ?);
506 var charstring sip_expect_str := log2str(exp_req);
507
508 [] SIP.receive(exp_req) -> value g_rx_sip_req {
509 var template (value) PDU_SIP_Response tx_resp;
510 var Via via;
511 var charstring tx_sdp;
512
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200513 /* Obtain params: */
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200514 f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200515 via := g_rx_sip_req.msgHeader.via;
516
517
518 /* Tx 180 Ringing */
519 tx_resp := ts_SIP_Response_Ringing(g_pars.cp.sip_call_id,
520 g_pars.cp.from_addr,
521 g_pars.cp.to_addr,
522 via,
523 g_pars.cp.sip_seq_nr);
524 SIP.send(tx_resp);
525
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200526 if (g_pars.cp.mt.wait_coord_cmd_pickup) {
527 COORD.receive(COORD_CMD_PICKUP);
528 }
529
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200530 /* Tx 200 OK */
531 tx_sdp := f_gen_sdp();
532 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
533 g_pars.cp.from_addr,
534 g_pars.cp.to_addr,
535 "INVITE", 200,
536 g_pars.cp.sip_seq_nr,
537 "OK",
538 via,
539 body := tx_sdp);
540 SIP.send(tx_resp);
541
542 /* Wait for ACK */
543 exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
544 g_pars.cp.sip_call_id,
545 g_pars.cp.from_addr,
546 g_pars.cp.to_addr,
547 f_tr_Via_response(via),
548 g_pars.cp.sip_seq_nr, *);
549 as_SIP_expect_req(exp_req);
550
551 if (exp_update_to_direct_rtp) {
552 /* Asterisk will now update the session to connect us to MO directly: */
553 /* Via is not kept since anyway "branch" will change upon following INVITE. */
554 as_SIP_exp_call_update(g_pars.cp.sip_seq_nr + 1);
555 }
556 }
557 [fail_others] as_SIP_fail_resp(sip_expect_str);
558 [fail_others] as_SIP_fail_req(sip_expect_str);
559
560}
561
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200562/* Peer is calling us, but cancells it during ringing: */
563private altstep as_SIP_mt_call_cancelled(boolean fail_others := true) runs on ConnHdlr
564{
565 var template (present) PDU_SIP_Request exp_req :=
566 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
567 ?,
568 f_tr_From(g_pars.cp.calling),
569 g_pars.cp.called,
570 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
571 ?, ?);
572 var charstring sip_expect_str := log2str(exp_req);
573
574 [] SIP.receive(exp_req) -> value g_rx_sip_req {
575 var template (value) PDU_SIP_Response tx_resp;
576 var Via via;
577 var template (present) SipAddr exp_to_addr;
578 var charstring tx_sdp;
579
580 /* Obtain params: */
581 f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
582 via := g_rx_sip_req.msgHeader.via;
583
584
585 /* Tx 180 Ringing */
586 tx_resp := ts_SIP_Response_Ringing(g_pars.cp.sip_call_id,
587 g_pars.cp.from_addr,
588 g_pars.cp.to_addr,
589 via,
590 g_pars.cp.sip_seq_nr);
591 SIP.send(tx_resp);
592
593 if (g_pars.cp.mt.wait_coord_cmd_pickup) {
594 COORD.receive(COORD_CMD_PICKUP);
595 }
596
597 /* Wait for CANCEL */
598 /* Cancel may come even before we send Ringing, hence To's "tag"
599 * may not be known by peer, so g_pars.to_addr can't be used here: */
600 exp_to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
601 g_rx_sip_req.msgHeader.toField.toParams);
602 exp_req := tr_SIP_CANCEL(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
603 g_pars.cp.sip_call_id,
604 g_pars.cp.from_addr,
605 exp_to_addr,
606 f_tr_Via_response(via),
607 g_pars.cp.sip_seq_nr, *);
608 as_SIP_expect_req(exp_req);
609
610 /* Tx 200 OK */
611 tx_sdp := f_gen_sdp();
612 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
613 g_pars.cp.from_addr,
614 g_pars.cp.to_addr,
615 "CANCEL", 200,
616 g_pars.cp.sip_seq_nr,
617 "OK",
618 via,
619 body := omit);
620 SIP.send(tx_resp);
621 }
622 [fail_others] as_SIP_fail_resp(sip_expect_str);
623 [fail_others] as_SIP_fail_req(sip_expect_str);
624
625}
626
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200627/* New INVITE arrives after MT call is established. Accept it: */
628private altstep as_SIP_exp_call_update(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on ConnHdlr
629{
630 var template (present) PDU_SIP_Request exp_req :=
631 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
632 g_pars.cp.sip_call_id,
633 g_pars.cp.from_addr,
634 g_pars.cp.to_addr,
635 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
636 exp_seq_nr,
637 ?);
638 var charstring sip_expect_str := log2str(exp_req);
639
640 [] SIP.receive(exp_req) -> value g_rx_sip_req {
641 var template (value) PDU_SIP_Response tx_resp;
642 var charstring tx_sdp;
643 var Via via;
644
645 f_SDP_decodeMessage(g_rx_sip_req.messageBody, g_pars.cp.peer_sdp);
646 log("Rx Update MT INVITE decoded SDP: ", g_pars.cp.peer_sdp);
647
648 /* Update parameters: */
649 g_pars.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
650 /* "branch" has changed: */
651 via := g_rx_sip_req.msgHeader.via;
652
653 /* Tx 200 OK */
654 tx_sdp := f_gen_sdp();
655 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
656 g_pars.cp.from_addr,
657 g_pars.cp.to_addr,
658 "INVITE", 200,
659 g_pars.cp.sip_seq_nr,
660 "OK",
661 via,
662 body := tx_sdp);
663 SIP.send(tx_resp);
664
665 /* Wait for ACK */
666 exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
667 g_pars.cp.sip_call_id,
668 g_pars.cp.from_addr,
669 g_pars.cp.to_addr,
670 f_tr_Via_response(via),
671 g_pars.cp.sip_seq_nr, *);
672 as_SIP_expect_req(exp_req);
673 }
674 [fail_others] as_SIP_fail_resp(sip_expect_str);
675 [fail_others] as_SIP_fail_req(sip_expect_str);
676}
677
678/* Tx BYE: */
679private function f_SIP_do_call_hangup() runs on ConnHdlr
680{
681 var template (value) PDU_SIP_Request req;
682 var template (present) PDU_SIP_Response exp_resp;
683 var Via via;
684 var charstring branch_value;
685
686 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.cp.from_addr),
687 f_sip_SipAddr_to_str(valueof(g_pars.cp.to_addr)),
688 g_pars.cp.sip_call_id,
689 g_pars.cp.sip_seq_nr);
690
691 via := g_pars.local_via;
692 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
693
694 /* Transmit ACK */
695 req := ts_SIP_BYE(g_pars.cp.sip_call_id,
696 g_pars.cp.from_addr,
697 g_pars.cp.to_addr,
698 via,
699 g_pars.cp.sip_seq_nr,
700 omit);
701 SIP.send(req);
702
703 /* Wait for OK answer */
704 exp_resp := tr_SIP_Response(
705 g_pars.cp.sip_call_id,
706 g_pars.cp.from_addr,
707 f_tr_To_response(g_pars.cp.to_addr),
708 f_tr_Via_response(via),
709 *,
710 "BYE", 200,
711 g_pars.cp.sip_seq_nr, "OK");
712 as_SIP_expect_resp(exp_resp);
713
714 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
715}
716
717/* Call is terminated by peer: */
718private altstep as_SIP_exp_call_hangup(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on ConnHdlr
719{
720 var template (present) PDU_SIP_Request exp_req :=
721 tr_SIP_BYE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
722 g_pars.cp.sip_call_id,
723 g_pars.cp.from_addr,
724 g_pars.cp.to_addr,
725 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
726 exp_seq_nr);
727 var charstring sip_expect_str := log2str(exp_req);
728
729 [] SIP.receive(exp_req) -> value g_rx_sip_req {
730 var template (value) PDU_SIP_Response tx_resp;
731 var charstring tx_sdp;
732 var Via via;
733
734 /* Update parameters: */
735 g_pars.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
736 /* "branch" has changed: */
737 via := g_rx_sip_req.msgHeader.via;
738
739 /* Tx 200 OK */
740 tx_sdp := f_gen_sdp();
741 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
742 g_pars.cp.from_addr,
743 g_pars.cp.to_addr,
744 "BYE", 200,
745 g_pars.cp.sip_seq_nr,
746 "OK",
747 via,
748 body := tx_sdp);
749 SIP.send(tx_resp);
750 }
751 [fail_others] as_SIP_fail_resp(sip_expect_str);
752 [fail_others] as_SIP_fail_req(sip_expect_str);
753}
754
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200755/* Test SIP registration of local clients */
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100756private function f_TC_internal_registration(charstring id) runs on ConnHdlr {
757
758 f_SIP_register();
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100759 // f_SIP_deregister();
760 setverdict(pass);
761}
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100762testcase TC_internal_registration() runs on test_CT {
763 var ConnHdlrPars pars;
764 var ConnHdlr vc_conn;
765 f_init();
766 pars := f_init_ConnHdlrPars();
767 vc_conn := f_start_handler(refers(f_TC_internal_registration), pars);
768 vc_conn.done;
769}
770
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200771/* Successful SIP MO-MT Call between local clients: */
772private function f_TC_internal_call_mo(charstring id) runs on ConnHdlr {
773
774 f_SIP_register();
775 COORD.send(COORD_CMD_REGISTERED);
776
777 COORD.receive(COORD_CMD_START);
778 f_SIP_mo_call_setup();
779 COORD.send(COORD_CMD_CALL_ESTABLISHED);
780
781 COORD.receive(COORD_CMD_HANGUP);
782 f_SIP_do_call_hangup();
783
784 setverdict(pass);
785}
786private function f_TC_internal_call_mt(charstring id) runs on ConnHdlr {
787
788 f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.cp.called.addr)));
789
790 f_SIP_register();
791 COORD.send(COORD_CMD_REGISTERED);
792
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200793 if (g_pars.cp.mt.exp_cancel) {
794 as_SIP_mt_call_cancelled();
795 COORD.send(COORD_CMD_CALL_CANCELLED);
796 setverdict(pass);
797 return;
798 }
799
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200800 as_SIP_mt_call_accept();
801 COORD.send(COORD_CMD_CALL_ESTABLISHED);
802
803 /* Once MO hangs up, Asterisk updates us to point RTP to it: */
804 as_SIP_exp_call_update(g_pars.cp.sip_seq_nr + 1);
805 as_SIP_exp_call_hangup(g_pars.cp.sip_seq_nr + 1);
806
807 setverdict(pass);
808}
809testcase TC_internal_call_momt() runs on test_CT {
810 var ConnHdlrPars pars[2];
811 var ConnHdlr vc_conn[2];
812
813 f_init();
814
815 pars[0] := f_init_ConnHdlrPars(idx := 1);
816 pars[1] := f_init_ConnHdlrPars(idx := 2);
817
818 pars[0].cp.calling := pars[0].registrar_sip_record;
819 pars[0].cp.called := pars[1].registrar_sip_record;
820
821 pars[1].cp.calling := pars[0].registrar_sip_record;
822 pars[1].cp.called := pars[1].local_sip_record;
823
824 vc_conn[0] := f_start_handler(refers(f_TC_internal_call_mo), pars[0]);
825 vc_conn[1] := f_start_handler(refers(f_TC_internal_call_mt), pars[1]);
826
827 interleave {
828 [] COORD.receive(COORD_CMD_REGISTERED) from vc_conn[0];
829 [] COORD.receive(COORD_CMD_REGISTERED) from vc_conn[1];
830 }
831
832 COORD.send(COORD_CMD_START) to vc_conn[0];
833
834 interleave {
835 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn[0];
836 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn[1];
837 }
838
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200839 /* Call on-going */
840 f_sleep(1.0);
841
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200842 COORD.send(COORD_CMD_HANGUP) to vc_conn[0];
843
844
845 vc_conn[0].done;
846 vc_conn[1].done;
847}
848
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200849/* One of the users calls (INVITE) shared extension, which makes all other user
850 * equipments ring (INVITE). The first one to pick up the call (OK 200) gets the
851 * call established (ACK), others get a CANCEL event. */
852private function TC_internal_call_all_Nregistered(integer num_conns := 2) runs on test_CT {
853 var ConnHdlrList vc_conn_list := {};
854 const integer vc_conn_mo_idx := 0; /* Index of MO leg in vc_conn_list */
855 const integer vc_conn_mt_idx := 1; /* Index of MT leg in vc_conn_list, peer picking up first the call */
856 var SipAddr broadcast_sip_record;
857 var ConnHdlrPars pars_mo;
858
859 f_init();
860
861 broadcast_sip_record := valueof(ts_SipAddr(ts_HostPort(mp_local_sip_host),
862 ts_UserInfo(broadcast_sip_extension)));
863
864 for (var integer i := 0; i < num_conns; i := i + 1) {
865 var ConnHdlrPars pars;
866 var ConnHdlr vc_conn;
867 pars := f_init_ConnHdlrPars(idx := i + 1);
868 if (i == vc_conn_mo_idx) { /* MO */
869 pars.cp.calling := pars.registrar_sip_record;
870 pars.cp.called := broadcast_sip_record;
871 vc_conn := f_start_handler(refers(f_TC_internal_call_mo), pars);
872 pars_mo := pars;
873 } else { /* MT */
874 pars.cp.calling := pars_mo.registrar_sip_record;
875 pars.cp.called := pars.local_sip_record;
876 pars.cp.mt.wait_coord_cmd_pickup := true;
877 if (i != vc_conn_mt_idx) {
878 /* Only first MT picking up (OK 200 INVITE) will be ACKed, others CANCELed: */
879 pars.cp.mt.exp_cancel := true;
880 }
881 vc_conn := f_start_handler(refers(f_TC_internal_call_mt), pars);
882 }
883 vc_conn_list := vc_conn_list & { vc_conn };
884 }
885
886 /* Wait all users are registered: */
887 for (var integer i := 0; i < num_conns; i := i + 1) {
888 /* Note: "from vc_conn_list[i]" can't be used since they may arrive from components in any order: */
889 COORD.receive(COORD_CMD_REGISTERED);
890 }
891
892 /* Ask MO user to start the call: */
893 COORD.send(COORD_CMD_START) to vc_conn_list[vc_conn_mo_idx];
894
895 /* Make sure the desired MT is the one picking up first the call: */
896 COORD.send(COORD_CMD_PICKUP) to vc_conn_list[vc_conn_mt_idx];
897 interleave {
898 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn_list[vc_conn_mo_idx];
899 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn_list[vc_conn_mt_idx];
900 }
901
902 /* Pick up from other phone calls and expect CANCEL: */
903 for (var integer i := 0; i < num_conns; i := i + 1) {
904 if (i != vc_conn_mo_idx and i != vc_conn_mt_idx) {
905 COORD.send(COORD_CMD_PICKUP) to vc_conn_list[i];
906 COORD.receive(COORD_CMD_CALL_CANCELLED) from vc_conn_list[i];
907 }
908 }
909
910 /* Call on-going */
911 f_sleep(1.0);
912
913 COORD.send(COORD_CMD_HANGUP) to vc_conn_list[vc_conn_mo_idx];
914
915 for (var integer i := 0; i < num_conns; i := i + 1) {
916 vc_conn_list[i].done;
917 }
918}
919testcase TC_internal_call_all_2registered() runs on test_CT {
920 TC_internal_call_all_Nregistered(2);
921}
922testcase TC_internal_call_all_3registered() runs on test_CT {
923 TC_internal_call_all_Nregistered(3);
924}
925testcase TC_internal_call_all_4registered() runs on test_CT {
926 TC_internal_call_all_Nregistered(4);
927}
928
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200929testcase TC_selftest() runs on test_CT {
930 f_sip_digest_selftest();
931 setverdict(pass);
932}
933
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100934control {
935 execute( TC_internal_registration() );
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200936 execute( TC_internal_call_momt() );
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200937 execute( TC_internal_call_all_2registered() );
938 execute( TC_internal_call_all_3registered() );
939 execute( TC_internal_call_all_4registered() );
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100940}
941
942}