blob: 151041ddb939ede2127628e7d136235590b25538 [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;
19
20import from SDP_Types all;
21import from SDP_Templates all;
22
23import from SIP_Emulation all;
24import from SIPmsg_Types all;
25import from SIP_Templates all;
26
27modulepar {
28 charstring mp_local_sip_host := "127.0.0.2";
29 integer mp_local_sip_port := 5060;
30 charstring mp_remote_sip_host := "127.0.0.1";
31 integer mp_remote_sip_port := 5060;
32}
33
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020034type port Coord_PT message
35{
36 inout charstring;
37} with { extension "internal" };
38private const charstring COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
39private const charstring COORD_CMD_START := "COORD_CMD_START";
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020040private const charstring COORD_CMD_PICKUP := "COORD_CMD_PICKUP";
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020041private const charstring COORD_CMD_CALL_ESTABLISHED := "COORD_CMD_CALL_ESTABLISHED";
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020042private const charstring COORD_CMD_CALL_CANCELLED := "COORD_CMD_CALL_CANCELLED";
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020043private const charstring COORD_CMD_HANGUP := "COORD_CMD_HANGUP";
44
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010045type component test_CT {
46 var SIP_Emulation_CT vc_SIP;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020047 port Coord_PT COORD;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010048}
49
50type component ConnHdlr extends SIP_ConnHdlr {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020051 var charstring g_name;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010052 var ConnHdlrPars g_pars;
53 timer g_Tguard;
54 var PDU_SIP_Request g_rx_sip_req;
55 var PDU_SIP_Response g_rx_sip_resp;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020056
57 port Coord_PT COORD;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010058}
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020059type record of ConnHdlr ConnHdlrList;
60
61const charstring broadcast_sip_extension := "0500";
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010062
63type record ConnHdlrPars {
64 float t_guard,
65 charstring user,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020066 charstring display_name,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020067 charstring password,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020068 SipUrl registrar_sip_req_uri,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010069 SipAddr registrar_sip_record,
70 CallidString registrar_sip_call_id,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010071 integer registrar_sip_seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020072 Via local_via,
73 SipUrl local_sip_url_ext,
74 SipAddr local_sip_record,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010075 Contact local_contact,
76 CallPars cp optional
77}
Pau Espin Pedrol32167d82024-04-10 13:14:51 +020078type record of ConnHdlrPars ConnHdlrParsList;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010079
80template (value) ConnHdlrPars t_Pars(charstring user,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020081 charstring display_name := "Anonymous",
82 charstring password := "secret",
83 template (value) CallPars cp := t_CallPars()) := {
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010084 t_guard := 30.0,
85 user := user,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020086 display_name := f_sip_str_quote(display_name),
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020087 password := password,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020088 registrar_sip_req_uri := valueof(ts_SipUrlHost(mp_remote_sip_host)),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010089 registrar_sip_record := ts_SipAddr(ts_HostPort(mp_remote_sip_host),
90 ts_UserInfo(user),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020091 f_sip_str_quote(display_name)),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010092 registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & mp_local_sip_host,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010093 registrar_sip_seq_nr := f_sip_rand_seq_nr(),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020094 local_via := ts_Via_from(ts_HostPort(mp_local_sip_host, mp_local_sip_port)),
95 local_sip_url_ext := ts_SipUrl(ts_HostPort(mp_local_sip_host, mp_local_sip_port),
96 ts_UserInfo(user)),
97 local_sip_record := ts_SipAddr(ts_HostPort(mp_local_sip_host),
98 ts_UserInfo(user)),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +010099 local_contact := valueof(ts_Contact({
100 ts_ContactAddress(
101 ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
102 mp_local_sip_host,
103 mp_local_sip_port),
104 ts_UserInfo(user))),
105 omit)
106 })),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200107 cp := cp
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100108}
109
110function f_init_ConnHdlrPars(integer idx := 1) runs on test_CT return ConnHdlrPars {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200111 var template (value) CallPars cp := t_CallPars(idx := idx);
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200112 var template (value) ConnHdlrPars pars := t_Pars("0" & int2str(str2int(broadcast_sip_extension) + idx),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200113 cp := cp);
114 return valueof(pars);
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100115}
116
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200117type record CallParsMT {
118 /* Whether to wait for COORD.receive(COORD_CMD_PICKUP) before accepting the call. */
119 boolean wait_coord_cmd_pickup,
120 /* Whether to expect CANCEL instead of ACK as answer to our OK */
121 boolean exp_cancel
122}
123private template (value) CallParsMT t_CallParsMT := {
124 wait_coord_cmd_pickup := false,
125 exp_cancel := false
126}
127
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100128type record CallPars {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200129 SipAddr calling optional,
130 SipAddr called optional,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100131
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200132 SipAddr from_addr optional,
133 SipAddr to_addr optional,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100134
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100135 CallidString sip_call_id,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200136 integer sip_seq_nr,
137 charstring sip_body optional,
138
139 charstring local_rtp_addr,
140 uint16_t local_rtp_port,
141
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200142 SDP_Message peer_sdp optional,
143 CallParsMT mt
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100144}
145
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200146private template (value) CallPars t_CallPars(integer idx := 1,
147 template (omit) SipAddr calling := omit,
148 template (omit) SipAddr called := omit) := {
149 calling := calling,
150 called := called,
151 from_addr := omit,
152 to_addr := omit,
153 sip_call_id := hex2str(f_rnd_hexstring(15)),
154 sip_seq_nr := f_sip_rand_seq_nr(),
155 sip_body := omit,
156 local_rtp_addr := mp_local_sip_host,
157 local_rtp_port := 1234 + 2*idx,
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200158 peer_sdp := omit,
159 mt := t_CallParsMT
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100160}
161
162function f_init() runs on test_CT {
163 f_init_sip(vc_SIP, "Asterisk_Test");
164 log("end of f_init");
165}
166
167type function void_fn(charstring id) runs on ConnHdlr;
168
169function f_start_handler(void_fn fn, ConnHdlrPars pars)
170runs on test_CT return ConnHdlr {
171 var ConnHdlr vc_conn;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200172 var charstring id := testcasename() & "-ConnHdlr-" & pars.user;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100173
Pau Espin Pedrole94a6482024-04-10 13:37:55 +0200174 vc_conn := ConnHdlr.create(id) alive;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100175
176 connect(vc_conn:SIP, vc_SIP:CLIENT);
177 connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
178
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200179 connect(vc_conn:COORD, self:COORD);
180
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100181 vc_conn.start(f_handler_init(fn, id, pars));
182 return vc_conn;
183}
184
185private altstep as_Tguard() runs on ConnHdlr {
186 [] g_Tguard.timeout {
187 setverdict(fail, "Tguard timeout");
188 mtc.stop;
189 }
190}
191
192private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
193runs on ConnHdlr {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200194 g_name := id;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100195 g_pars := pars;
196 g_Tguard.start(pars.t_guard);
197 activate(as_Tguard());
198
199 // Make sure the UA is deregistered before starting the test:
200 // sends REGISTER with Contact = "*" and Expires = 0
201 //f_SIP_deregister();
202
203 /* call the user-supied test case function */
204 fn.apply(id);
205}
206
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200207private altstep as_SIP_fail_req(charstring exp_msg_str := "") runs on ConnHdlr
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100208{
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200209 var PDU_SIP_Request sip_req;
210 [] SIP.receive(PDU_SIP_Request:?) -> value sip_req {
211 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
212 log2str(g_name & ": Received unexpected SIP Req message := ", sip_req, "\nvs exp := ", exp_msg_str));
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100213 }
214}
215
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200216private altstep as_SIP_fail_resp(charstring exp_msg_str := "") runs on ConnHdlr
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100217{
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200218 var PDU_SIP_Response sip_resp;
219 [] SIP.receive(PDU_SIP_Response:?) -> value sip_resp {
220 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
221 log2str(g_name & ": Received unexpected SIP Resp message := ", sip_resp, "\nvs exp := ", exp_msg_str));
222 }
223}
224
225altstep as_SIP_expect_req(template (present) PDU_SIP_Request sip_expect, boolean fail_others := true) runs on ConnHdlr
226{
227 var charstring sip_expect_str := log2str(sip_expect);
228 [] SIP.receive(sip_expect) -> value g_rx_sip_req;
229 [fail_others] as_SIP_fail_req(sip_expect_str);
230 [fail_others] as_SIP_fail_resp(sip_expect_str);
231}
232
233altstep as_SIP_expect_resp(template (present) PDU_SIP_Response sip_expect, boolean fail_others := true) runs on ConnHdlr
234{
235 var charstring sip_expect_str := log2str(sip_expect);
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100236 [] SIP.receive(sip_expect) -> value g_rx_sip_resp;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200237 [fail_others] as_SIP_fail_resp(sip_expect_str);
238 [fail_others] as_SIP_fail_req(sip_expect_str);
239}
240
241altstep as_SIP_ignore_resp(template PDU_SIP_Response sip_expect := ?) runs on ConnHdlr
242{
243 [] SIP.receive(sip_expect) -> value g_rx_sip_resp {
244 log("Ignoring ", g_rx_sip_resp);
245 repeat;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100246 }
247}
248
249private function f_tr_Via_response(Via via_req) return template (present) Via {
250 template (present) SemicolonParam_List via_resp_params := ?;
251
252 /*via_resp_params := {
253 { id := "rport", paramValue := int2str(mp_remote_sip_port) },
254 { id := "received", paramValue := mp_remote_sip_host }
255 }; */
256 return tr_Via_from(via_req.viaBody[0].sentBy,
257 via_resp_params);
258}
259
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200260private function f_tr_To_response(template (value) SipAddr to_req) return template (present) SipAddr {
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200261 return tr_SipAddr_from_val(to_req);
262}
263
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200264private function f_tr_From(template (value) SipAddr from_req) return template (present) SipAddr {
265 return tr_SipAddr_from_val(from_req);
266}
267
268private function f_gen_sdp() runs on ConnHdlr return charstring {
269 var charstring sdp :=
270 "v=0\r\n" &
271 "o=0502 2390 1824 IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
272 "s=Talk\r\n" &
273 "c=IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
274 "t=0 0\r\n" &
275 "a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
276 "a=record:off\r\n" &
277 "m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 96 97 98 0 8 18 99 100 101\r\n" &
278 "a=rtpmap:96 opus/48000/2\r\n" &
279 "a=fmtp:96 useinbandfec=1\r\n" &
280 "a=rtpmap:97 speex/16000\r\n" &
281 "a=fmtp:97 vbr=on\r\n" &
282 "a=rtpmap:98 speex/8000\r\n" &
283 "a=fmtp:98 vbr=on\r\n" &
284 "a=fmtp:18 annexb=yes\r\n" &
285 "a=rtpmap:99 telephone-event/48000\r\n" &
286 "a=rtpmap:100 telephone-event/16000\r\n" &
287 "a=rtpmap:101 telephone-event/8000\r\n" &
288 "a=rtcp:" & int2str(g_pars.cp.local_rtp_port + 1) & "\r\n" &
289 "a=rtcp-fb:* trr-int 1000\r\n" &
290 "a=rtcp-fb:* ccm tmmbr\r\n";
291 return sdp;
292}
293
294private function f_SIP_register() runs on ConnHdlr return PDU_SIP_Response
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100295{
296 var template (present) PDU_SIP_Response exp;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200297 var Authorization authorization;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200298 var Via via := g_pars.local_via;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200299 var SipAddr from_sipaddr := g_pars.registrar_sip_record;
300 var charstring branch_value;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100301
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200302 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
303 f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
304 g_pars.registrar_sip_call_id,
305 g_pars.registrar_sip_seq_nr);
306
307 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
308 from_sipaddr.params := f_sip_param_set(from_sipaddr.params, "tag", f_sip_rand_tag());
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200309 SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_req_uri,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100310 g_pars.registrar_sip_call_id,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200311 from_sipaddr,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100312 g_pars.registrar_sip_record,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200313 via,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100314 g_pars.registrar_sip_seq_nr,
315 g_pars.local_contact,
316 ts_Expires("7200")));
317
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200318 exp := tr_SIP_Response_Unauthorized(
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100319 g_pars.registrar_sip_call_id,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200320 from_sipaddr,
321 f_tr_To_response(g_pars.registrar_sip_record),
322 f_tr_Via_response(via),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100323 *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200324 tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100325 g_pars.registrar_sip_seq_nr);
326 as_SIP_expect_resp(exp);
327
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200328 /* Digest Auth: RFC 2617 */
329 authorization := f_sip_digest_gen_Authorization(g_rx_sip_resp.msgHeader.wwwAuthenticate,
330 g_pars.user, g_pars.password,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200331 "REGISTER",
332 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200333
334 /* New transaction: */
335 g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
336 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
337 f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
338 g_pars.registrar_sip_call_id,
339 g_pars.registrar_sip_seq_nr);
340 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
341
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200342 SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_req_uri,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200343 g_pars.registrar_sip_call_id,
344 from_sipaddr,
345 g_pars.registrar_sip_record,
346 via,
347 g_pars.registrar_sip_seq_nr,
348 g_pars.local_contact,
349 ts_Expires("7200"),
350 authorization := authorization));
351
352 /* Wait for OK answer */
353 exp := tr_SIP_Response(
354 g_pars.registrar_sip_call_id,
355 from_sipaddr,
356 f_tr_To_response(g_pars.registrar_sip_record),
357 f_tr_Via_response(via),
358 *,
359 "REGISTER", 200,
360 g_pars.registrar_sip_seq_nr, "OK");
361 as_SIP_expect_resp(exp);
362
363 /* Prepare for next use: */
364 g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100365 return g_rx_sip_resp;
366}
367
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200368private function f_SIP_mo_call_setup() runs on ConnHdlr
369{
370 var template (value) PDU_SIP_Request req;
371 var template (present) PDU_SIP_Response exp;
372 var Via via;
373 var charstring tx_sdp := f_gen_sdp();
374 var default d_trying, d_ringing;
375 var charstring branch_value;
376
377 /* RFC 3261 8.1.1.3 From */
378 g_pars.cp.from_addr := g_pars.cp.calling;
379 g_pars.cp.from_addr.params := f_sip_param_set(g_pars.cp.from_addr.params, "tag", f_sip_rand_tag());
380 g_pars.cp.to_addr := g_pars.cp.called;
381 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.cp.from_addr),
382 f_sip_SipAddr_to_str(valueof(g_pars.cp.to_addr)),
383 g_pars.cp.sip_call_id,
384 g_pars.cp.sip_seq_nr);
385 via := g_pars.local_via;
386 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
387
388 req := ts_SIP_INVITE(g_pars.cp.sip_call_id,
389 g_pars.cp.from_addr,
390 g_pars.cp.to_addr,
391 via,
392 g_pars.local_contact,
393 g_pars.cp.sip_seq_nr,
394 body := tx_sdp);
395
396 SIP.send(req);
397
398 /* RFC 3261 22.2: */
399 exp := tr_SIP_Response_Unauthorized(
400 g_pars.cp.sip_call_id,
401 f_tr_From(g_pars.cp.from_addr),
402 f_tr_To_response(g_pars.cp.to_addr),
403 f_tr_Via_response(via),
404 *,
405 tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
406 g_pars.cp.sip_seq_nr, "INVITE");
407 as_SIP_expect_resp(exp);
408
409 /* Digest Auth: RFC 2617 */
410 req.msgHeader.authorization := f_sip_digest_gen_Authorization(
411 g_rx_sip_resp.msgHeader.wwwAuthenticate,
412 g_pars.user, g_pars.password,
413 "INVITE",
414 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
415 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
416 f_sip_Request_inc_seq_nr(req);
417 SIP.send(req);
418
419 /* Conditionally match and accept 100 Trying. */
420 exp := tr_SIP_Response_Trying(g_pars.cp.sip_call_id,
421 g_pars.cp.from_addr,
422 f_tr_To_response(g_pars.cp.to_addr),
423 f_tr_Via_response(via),
424 g_pars.cp.sip_seq_nr, "INVITE");
425 d_trying := activate(as_SIP_ignore_resp(exp));
426
427 /* Conditionally match and accept 180 Ringing */
428 exp := tr_SIP_Response_Ringing(g_pars.cp.sip_call_id,
429 g_pars.cp.from_addr,
430 f_tr_To_response(g_pars.cp.to_addr),
431 f_tr_Via_response(via),
432 g_pars.cp.sip_seq_nr, "INVITE");
433 d_ringing := activate(as_SIP_ignore_resp(exp));
434
435 /* Wait for OK answer */
436 exp := tr_SIP_Response(
437 g_pars.cp.sip_call_id,
438 g_pars.cp.from_addr,
439 f_tr_To_response(g_pars.cp.to_addr),
440 f_tr_Via_response(via),
441 *,
442 "INVITE", 200,
443 g_pars.cp.sip_seq_nr, "OK",
444 body := ?);
445 as_SIP_expect_resp(exp, fail_others := false);
446
447 deactivate(d_trying);
448 deactivate(d_ringing);
449
450 /* Update To with the tags received from peer: */
451 g_pars.cp.to_addr := valueof(ts_SipAddr_from_Addr_Union(g_rx_sip_resp.msgHeader.toField.addressField,
452 g_rx_sip_resp.msgHeader.toField.toParams));
453
454 /* Transmit ACK */
455 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
456 req := ts_SIP_ACK(g_pars.cp.sip_call_id,
457 g_pars.cp.from_addr,
458 g_pars.cp.to_addr,
459 via,
460 g_pars.cp.sip_seq_nr,
461 omit);
462 SIP.send(req);
463 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
464}
465
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200466private function f_ConnHdlr_parse_initial_SIP_INVITE(PDU_SIP_Request rx_sip_req) runs on ConnHdlr
467{
468 f_SDP_decodeMessage(rx_sip_req.messageBody, g_pars.cp.peer_sdp);
469 log("Rx Initial MT INVITE decoded SDP: ", g_pars.cp.peer_sdp);
470
471 /* Obtain params: */
472 g_pars.cp.sip_call_id := rx_sip_req.msgHeader.callId.callid;
473 g_pars.cp.from_addr := valueof(ts_SipAddr_from_Addr_Union(rx_sip_req.msgHeader.fromField.addressField,
474 rx_sip_req.msgHeader.fromField.fromParams));
475 g_pars.cp.to_addr := valueof(ts_SipAddr_from_Addr_Union(rx_sip_req.msgHeader.toField.addressField,
476 rx_sip_req.msgHeader.toField.toParams));
477 g_pars.cp.to_addr.params := f_sip_param_set(g_pars.cp.to_addr.params, "tag", f_sip_rand_tag());
478 g_pars.cp.sip_seq_nr := rx_sip_req.msgHeader.cSeq.seqNumber;
479}
480
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200481/* Peer is calling us, accept it: */
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200482private altstep as_SIP_mt_call_accept(boolean exp_update_to_direct_rtp := true,
483 boolean fail_others := true) runs on ConnHdlr
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200484{
485 var template (present) PDU_SIP_Request exp_req :=
486 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
487 ?,
488 f_tr_From(g_pars.cp.calling),
489 g_pars.cp.called,
490 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
491 ?, ?);
492 var charstring sip_expect_str := log2str(exp_req);
493
494 [] SIP.receive(exp_req) -> value g_rx_sip_req {
495 var template (value) PDU_SIP_Response tx_resp;
496 var Via via;
497 var charstring tx_sdp;
498
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200499 /* Obtain params: */
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200500 f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200501 via := g_rx_sip_req.msgHeader.via;
502
503
504 /* Tx 180 Ringing */
505 tx_resp := ts_SIP_Response_Ringing(g_pars.cp.sip_call_id,
506 g_pars.cp.from_addr,
507 g_pars.cp.to_addr,
508 via,
509 g_pars.cp.sip_seq_nr);
510 SIP.send(tx_resp);
511
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200512 if (g_pars.cp.mt.wait_coord_cmd_pickup) {
513 COORD.receive(COORD_CMD_PICKUP);
514 }
515
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200516 /* Tx 200 OK */
517 tx_sdp := f_gen_sdp();
518 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
519 g_pars.cp.from_addr,
520 g_pars.cp.to_addr,
521 "INVITE", 200,
522 g_pars.cp.sip_seq_nr,
523 "OK",
524 via,
525 body := tx_sdp);
526 SIP.send(tx_resp);
527
528 /* Wait for ACK */
529 exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
530 g_pars.cp.sip_call_id,
531 g_pars.cp.from_addr,
532 g_pars.cp.to_addr,
533 f_tr_Via_response(via),
534 g_pars.cp.sip_seq_nr, *);
535 as_SIP_expect_req(exp_req);
536
537 if (exp_update_to_direct_rtp) {
538 /* Asterisk will now update the session to connect us to MO directly: */
539 /* Via is not kept since anyway "branch" will change upon following INVITE. */
540 as_SIP_exp_call_update(g_pars.cp.sip_seq_nr + 1);
541 }
542 }
543 [fail_others] as_SIP_fail_resp(sip_expect_str);
544 [fail_others] as_SIP_fail_req(sip_expect_str);
545
546}
547
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200548/* Peer is calling us, but cancells it during ringing: */
549private altstep as_SIP_mt_call_cancelled(boolean fail_others := true) runs on ConnHdlr
550{
551 var template (present) PDU_SIP_Request exp_req :=
552 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
553 ?,
554 f_tr_From(g_pars.cp.calling),
555 g_pars.cp.called,
556 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
557 ?, ?);
558 var charstring sip_expect_str := log2str(exp_req);
559
560 [] SIP.receive(exp_req) -> value g_rx_sip_req {
561 var template (value) PDU_SIP_Response tx_resp;
562 var Via via;
563 var template (present) SipAddr exp_to_addr;
564 var charstring tx_sdp;
565
566 /* Obtain params: */
567 f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
568 via := g_rx_sip_req.msgHeader.via;
569
570
571 /* Tx 180 Ringing */
572 tx_resp := ts_SIP_Response_Ringing(g_pars.cp.sip_call_id,
573 g_pars.cp.from_addr,
574 g_pars.cp.to_addr,
575 via,
576 g_pars.cp.sip_seq_nr);
577 SIP.send(tx_resp);
578
579 if (g_pars.cp.mt.wait_coord_cmd_pickup) {
580 COORD.receive(COORD_CMD_PICKUP);
581 }
582
583 /* Wait for CANCEL */
584 /* Cancel may come even before we send Ringing, hence To's "tag"
585 * may not be known by peer, so g_pars.to_addr can't be used here: */
586 exp_to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
587 g_rx_sip_req.msgHeader.toField.toParams);
588 exp_req := tr_SIP_CANCEL(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
589 g_pars.cp.sip_call_id,
590 g_pars.cp.from_addr,
591 exp_to_addr,
592 f_tr_Via_response(via),
593 g_pars.cp.sip_seq_nr, *);
594 as_SIP_expect_req(exp_req);
595
596 /* Tx 200 OK */
597 tx_sdp := f_gen_sdp();
598 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
599 g_pars.cp.from_addr,
600 g_pars.cp.to_addr,
601 "CANCEL", 200,
602 g_pars.cp.sip_seq_nr,
603 "OK",
604 via,
605 body := omit);
606 SIP.send(tx_resp);
607 }
608 [fail_others] as_SIP_fail_resp(sip_expect_str);
609 [fail_others] as_SIP_fail_req(sip_expect_str);
610
611}
612
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200613/* New INVITE arrives after MT call is established. Accept it: */
614private altstep as_SIP_exp_call_update(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on ConnHdlr
615{
616 var template (present) PDU_SIP_Request exp_req :=
617 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
618 g_pars.cp.sip_call_id,
619 g_pars.cp.from_addr,
620 g_pars.cp.to_addr,
621 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
622 exp_seq_nr,
623 ?);
624 var charstring sip_expect_str := log2str(exp_req);
625
626 [] SIP.receive(exp_req) -> value g_rx_sip_req {
627 var template (value) PDU_SIP_Response tx_resp;
628 var charstring tx_sdp;
629 var Via via;
630
631 f_SDP_decodeMessage(g_rx_sip_req.messageBody, g_pars.cp.peer_sdp);
632 log("Rx Update MT INVITE decoded SDP: ", g_pars.cp.peer_sdp);
633
634 /* Update parameters: */
635 g_pars.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
636 /* "branch" has changed: */
637 via := g_rx_sip_req.msgHeader.via;
638
639 /* Tx 200 OK */
640 tx_sdp := f_gen_sdp();
641 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
642 g_pars.cp.from_addr,
643 g_pars.cp.to_addr,
644 "INVITE", 200,
645 g_pars.cp.sip_seq_nr,
646 "OK",
647 via,
648 body := tx_sdp);
649 SIP.send(tx_resp);
650
651 /* Wait for ACK */
652 exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
653 g_pars.cp.sip_call_id,
654 g_pars.cp.from_addr,
655 g_pars.cp.to_addr,
656 f_tr_Via_response(via),
657 g_pars.cp.sip_seq_nr, *);
658 as_SIP_expect_req(exp_req);
659 }
660 [fail_others] as_SIP_fail_resp(sip_expect_str);
661 [fail_others] as_SIP_fail_req(sip_expect_str);
662}
663
664/* Tx BYE: */
665private function f_SIP_do_call_hangup() runs on ConnHdlr
666{
667 var template (value) PDU_SIP_Request req;
668 var template (present) PDU_SIP_Response exp_resp;
669 var Via via;
670 var charstring branch_value;
671
672 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.cp.from_addr),
673 f_sip_SipAddr_to_str(valueof(g_pars.cp.to_addr)),
674 g_pars.cp.sip_call_id,
675 g_pars.cp.sip_seq_nr);
676
677 via := g_pars.local_via;
678 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
679
680 /* Transmit ACK */
681 req := ts_SIP_BYE(g_pars.cp.sip_call_id,
682 g_pars.cp.from_addr,
683 g_pars.cp.to_addr,
684 via,
685 g_pars.cp.sip_seq_nr,
686 omit);
687 SIP.send(req);
688
689 /* Wait for OK answer */
690 exp_resp := tr_SIP_Response(
691 g_pars.cp.sip_call_id,
692 g_pars.cp.from_addr,
693 f_tr_To_response(g_pars.cp.to_addr),
694 f_tr_Via_response(via),
695 *,
696 "BYE", 200,
697 g_pars.cp.sip_seq_nr, "OK");
698 as_SIP_expect_resp(exp_resp);
699
700 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
701}
702
703/* Call is terminated by peer: */
704private altstep as_SIP_exp_call_hangup(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on ConnHdlr
705{
706 var template (present) PDU_SIP_Request exp_req :=
707 tr_SIP_BYE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
708 g_pars.cp.sip_call_id,
709 g_pars.cp.from_addr,
710 g_pars.cp.to_addr,
711 tr_Via_from(f_tr_HostPort(mp_remote_sip_host, mp_remote_sip_port)),
712 exp_seq_nr);
713 var charstring sip_expect_str := log2str(exp_req);
714
715 [] SIP.receive(exp_req) -> value g_rx_sip_req {
716 var template (value) PDU_SIP_Response tx_resp;
717 var charstring tx_sdp;
718 var Via via;
719
720 /* Update parameters: */
721 g_pars.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
722 /* "branch" has changed: */
723 via := g_rx_sip_req.msgHeader.via;
724
725 /* Tx 200 OK */
726 tx_sdp := f_gen_sdp();
727 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
728 g_pars.cp.from_addr,
729 g_pars.cp.to_addr,
730 "BYE", 200,
731 g_pars.cp.sip_seq_nr,
732 "OK",
733 via,
734 body := tx_sdp);
735 SIP.send(tx_resp);
736 }
737 [fail_others] as_SIP_fail_resp(sip_expect_str);
738 [fail_others] as_SIP_fail_req(sip_expect_str);
739}
740
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200741/* Test SIP registration of local clients */
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100742private function f_TC_internal_registration(charstring id) runs on ConnHdlr {
743
744 f_SIP_register();
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100745 // f_SIP_deregister();
746 setverdict(pass);
747}
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100748testcase TC_internal_registration() runs on test_CT {
749 var ConnHdlrPars pars;
750 var ConnHdlr vc_conn;
751 f_init();
752 pars := f_init_ConnHdlrPars();
753 vc_conn := f_start_handler(refers(f_TC_internal_registration), pars);
754 vc_conn.done;
755}
756
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200757/* Successful SIP MO-MT Call between local clients: */
758private function f_TC_internal_call_mo(charstring id) runs on ConnHdlr {
759
760 f_SIP_register();
761 COORD.send(COORD_CMD_REGISTERED);
762
763 COORD.receive(COORD_CMD_START);
764 f_SIP_mo_call_setup();
765 COORD.send(COORD_CMD_CALL_ESTABLISHED);
766
767 COORD.receive(COORD_CMD_HANGUP);
768 f_SIP_do_call_hangup();
769
770 setverdict(pass);
771}
772private function f_TC_internal_call_mt(charstring id) runs on ConnHdlr {
773
774 f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.cp.called.addr)));
775
776 f_SIP_register();
777 COORD.send(COORD_CMD_REGISTERED);
778
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200779 if (g_pars.cp.mt.exp_cancel) {
780 as_SIP_mt_call_cancelled();
781 COORD.send(COORD_CMD_CALL_CANCELLED);
782 setverdict(pass);
783 return;
784 }
785
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200786 as_SIP_mt_call_accept();
787 COORD.send(COORD_CMD_CALL_ESTABLISHED);
788
789 /* Once MO hangs up, Asterisk updates us to point RTP to it: */
790 as_SIP_exp_call_update(g_pars.cp.sip_seq_nr + 1);
791 as_SIP_exp_call_hangup(g_pars.cp.sip_seq_nr + 1);
792
793 setverdict(pass);
794}
795testcase TC_internal_call_momt() runs on test_CT {
796 var ConnHdlrPars pars[2];
797 var ConnHdlr vc_conn[2];
798
799 f_init();
800
801 pars[0] := f_init_ConnHdlrPars(idx := 1);
802 pars[1] := f_init_ConnHdlrPars(idx := 2);
803
804 pars[0].cp.calling := pars[0].registrar_sip_record;
805 pars[0].cp.called := pars[1].registrar_sip_record;
806
807 pars[1].cp.calling := pars[0].registrar_sip_record;
808 pars[1].cp.called := pars[1].local_sip_record;
809
810 vc_conn[0] := f_start_handler(refers(f_TC_internal_call_mo), pars[0]);
811 vc_conn[1] := f_start_handler(refers(f_TC_internal_call_mt), pars[1]);
812
813 interleave {
814 [] COORD.receive(COORD_CMD_REGISTERED) from vc_conn[0];
815 [] COORD.receive(COORD_CMD_REGISTERED) from vc_conn[1];
816 }
817
818 COORD.send(COORD_CMD_START) to vc_conn[0];
819
820 interleave {
821 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn[0];
822 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn[1];
823 }
824
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200825 /* Call on-going */
826 f_sleep(1.0);
827
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200828 COORD.send(COORD_CMD_HANGUP) to vc_conn[0];
829
830
831 vc_conn[0].done;
832 vc_conn[1].done;
833}
834
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200835/* One of the users calls (INVITE) shared extension, which makes all other user
836 * equipments ring (INVITE). The first one to pick up the call (OK 200) gets the
837 * call established (ACK), others get a CANCEL event. */
838private function TC_internal_call_all_Nregistered(integer num_conns := 2) runs on test_CT {
839 var ConnHdlrList vc_conn_list := {};
840 const integer vc_conn_mo_idx := 0; /* Index of MO leg in vc_conn_list */
841 const integer vc_conn_mt_idx := 1; /* Index of MT leg in vc_conn_list, peer picking up first the call */
842 var SipAddr broadcast_sip_record;
843 var ConnHdlrPars pars_mo;
844
845 f_init();
846
847 broadcast_sip_record := valueof(ts_SipAddr(ts_HostPort(mp_local_sip_host),
848 ts_UserInfo(broadcast_sip_extension)));
849
850 for (var integer i := 0; i < num_conns; i := i + 1) {
851 var ConnHdlrPars pars;
852 var ConnHdlr vc_conn;
853 pars := f_init_ConnHdlrPars(idx := i + 1);
854 if (i == vc_conn_mo_idx) { /* MO */
855 pars.cp.calling := pars.registrar_sip_record;
856 pars.cp.called := broadcast_sip_record;
857 vc_conn := f_start_handler(refers(f_TC_internal_call_mo), pars);
858 pars_mo := pars;
859 } else { /* MT */
860 pars.cp.calling := pars_mo.registrar_sip_record;
861 pars.cp.called := pars.local_sip_record;
862 pars.cp.mt.wait_coord_cmd_pickup := true;
863 if (i != vc_conn_mt_idx) {
864 /* Only first MT picking up (OK 200 INVITE) will be ACKed, others CANCELed: */
865 pars.cp.mt.exp_cancel := true;
866 }
867 vc_conn := f_start_handler(refers(f_TC_internal_call_mt), pars);
868 }
869 vc_conn_list := vc_conn_list & { vc_conn };
870 }
871
872 /* Wait all users are registered: */
873 for (var integer i := 0; i < num_conns; i := i + 1) {
874 /* Note: "from vc_conn_list[i]" can't be used since they may arrive from components in any order: */
875 COORD.receive(COORD_CMD_REGISTERED);
876 }
877
878 /* Ask MO user to start the call: */
879 COORD.send(COORD_CMD_START) to vc_conn_list[vc_conn_mo_idx];
880
881 /* Make sure the desired MT is the one picking up first the call: */
882 COORD.send(COORD_CMD_PICKUP) to vc_conn_list[vc_conn_mt_idx];
883 interleave {
884 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn_list[vc_conn_mo_idx];
885 [] COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn_list[vc_conn_mt_idx];
886 }
887
888 /* Pick up from other phone calls and expect CANCEL: */
889 for (var integer i := 0; i < num_conns; i := i + 1) {
890 if (i != vc_conn_mo_idx and i != vc_conn_mt_idx) {
891 COORD.send(COORD_CMD_PICKUP) to vc_conn_list[i];
892 COORD.receive(COORD_CMD_CALL_CANCELLED) from vc_conn_list[i];
893 }
894 }
895
896 /* Call on-going */
897 f_sleep(1.0);
898
899 COORD.send(COORD_CMD_HANGUP) to vc_conn_list[vc_conn_mo_idx];
900
901 for (var integer i := 0; i < num_conns; i := i + 1) {
902 vc_conn_list[i].done;
903 }
904}
905testcase TC_internal_call_all_2registered() runs on test_CT {
906 TC_internal_call_all_Nregistered(2);
907}
908testcase TC_internal_call_all_3registered() runs on test_CT {
909 TC_internal_call_all_Nregistered(3);
910}
911testcase TC_internal_call_all_4registered() runs on test_CT {
912 TC_internal_call_all_Nregistered(4);
913}
914
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200915testcase TC_selftest() runs on test_CT {
916 f_sip_digest_selftest();
917 setverdict(pass);
918}
919
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100920control {
921 execute( TC_internal_registration() );
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200922 execute( TC_internal_call_momt() );
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200923 execute( TC_internal_call_all_2registered() );
924 execute( TC_internal_call_all_3registered() );
925 execute( TC_internal_call_all_4registered() );
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100926}
927
928}