blob: f690dc704c0173e11f271a50d7e1e3f56ab5c19f [file] [log] [blame]
Harald Welteafec4712018-03-19 22:52:17 +01001module SIP_Tests {
2
3import from General_Types all;
4import from Osmocom_Types all;
5
6import from Osmocom_CTRL_Functions all;
7import from Osmocom_CTRL_Types all;
8import from Osmocom_CTRL_Adapter all;
9
10import from TELNETasp_PortType all;
11import from Osmocom_VTY_Functions all;
12
13import from MNCC_Emulation all;
14import from MNCC_Types all;
15
16import from SDP_Types all;
17
18import from SIP_Emulation all;
19import from SIPmsg_Types all;
Harald Welteb0d93602018-03-20 18:09:34 +010020import from SIP_Templates all;
Harald Welteafec4712018-03-19 22:52:17 +010021
22modulepar {
Harald Welteb0d93602018-03-20 18:09:34 +010023 charstring mp_local_host := "127.0.0.2";
Harald Welteafec4712018-03-19 22:52:17 +010024 charstring mp_osmosip_host := "127.0.0.1";
25 integer mp_osmosip_port_ctrl := -1; /* RFU */
26 charstring mp_mncc := "/tmp/mncc";
27}
28
29type component test_CT extends CTRL_Adapter_CT {
30 var MNCC_Emulation_CT vc_MNCC;
31 var SIP_Emulation_CT vc_SIP;
32
33 port TELNETasp_PT SIPVTY;
34}
35
36type component ConnHdlr extends SIP_ConnHdlr, MNCC_ConnHdlr {
37 var ConnHdlrPars g_pars;
38 timer g_Tguard;
39}
40
41type record ConnHdlrPars {
Harald Welteb0d93602018-03-20 18:09:34 +010042 float t_guard,
43 CallPars g_cp optional
44}
45
46type record CallPars {
47 boolean is_mo,
48 charstring calling,
49 charstring called,
50
51 uint32_t mncc_call_id optional,
52
53 CallParsComputed comp optional
54}
55
56type record CallParsComputed {
57 CallidString sip_call_id,
58 SipAddr sip_url_ext,
59 SipAddr sip_url_gsm,
60 charstring sip_body,
61 integer sip_seq_nr
62}
63
64private template (value) CallPars t_CallPars(boolean is_mo) := {
65 is_mo := is_mo,
66 calling := "12345",
67 called := "98766",
68 mncc_call_id := omit,
69 comp := omit
70}
71
72private function f_CallPars_compute(inout CallPars cp) {
73 if (cp.is_mo) {
74 cp.comp.sip_url_ext := valueof(ts_SipAddr(cp.called, mp_local_host, 5060));
75 cp.comp.sip_url_gsm := valueof(ts_SipAddr(cp.calling, mp_osmosip_host, 5060));
76 cp.mncc_call_id := f_rnd_int(429496725);
77 } else {
78 cp.comp.sip_url_ext := valueof(ts_SipAddr(cp.calling, mp_local_host, 5060));
79 cp.comp.sip_url_gsm := valueof(ts_SipAddr(cp.called, mp_osmosip_host, 5060));
80 cp.comp.sip_call_id := hex2str(f_rnd_hexstring(15));
81 }
82 cp.comp.sip_seq_nr := f_rnd_int(4294967295);
83 cp.comp.sip_body := "";
Harald Welteafec4712018-03-19 22:52:17 +010084}
85
86
87function f_init_mncc(charstring id) runs on test_CT {
88 id := id & "-MNCC";
89 var MnccOps ops := {
90 create_cb := refers(MNCC_Emulation.ExpectedCreateCallback),
91 unitdata_cb := refers(MNCC_Emulation.DummyUnitdataCallback)
92 };
93
94 vc_MNCC := MNCC_Emulation_CT.create(id);
95 map(vc_MNCC:MNCC, system:MNCC_CODEC_PT);
96 vc_MNCC.start(MNCC_Emulation.main(ops, id, mp_mncc, true));
97}
98
99function f_init() runs on test_CT {
100 //f_ipa_ctrl_start(mp_osmosip_host, mp_osmosip_port_ctrl);
101 f_init_mncc("SIP_Test");
102 log("end of f_init_mncc");
103 f_init_sip(vc_SIP, "SIP_Test");
104 log("end of f_init_sip");
105
106 map(self:SIPVTY, system:SIPVTY);
107 f_vty_set_prompts(SIPVTY);
108 f_vty_transceive(SIPVTY, "enable");
109 log("end of f_init");
110}
111
112type function void_fn(charstring id) runs on ConnHdlr;
113
114function f_start_handler(void_fn fn, ConnHdlrPars pars)
115runs on test_CT return ConnHdlr {
116 var ConnHdlr vc_conn;
117 var charstring id := testcasename();
118
119 vc_conn := ConnHdlr.create(id);
120
121 connect(vc_conn:SIP, vc_SIP:CLIENT);
122 connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
123
124 connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT);
125 connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC);
126
127 vc_conn.start(f_handler_init(fn, id, pars));
128 return vc_conn;
129}
130
131private altstep as_Tguard() runs on ConnHdlr {
132 [] g_Tguard.timeout {
133 setverdict(fail, "Tguard timeout");
134 self.stop;
135 }
136}
137
138private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
139runs on ConnHdlr {
140 g_pars := pars;
141 g_Tguard.start(pars.t_guard);
142 activate(as_Tguard());
143
144 /* call the user-supied test case function */
145 fn.apply(id);
146}
147
148
149template (value) ConnHdlrPars t_Pars := {
Harald Welteb0d93602018-03-20 18:09:34 +0100150 t_guard := 30.0,
151 g_cp := omit
Harald Welteafec4712018-03-19 22:52:17 +0100152}
153
Harald Welteb0d93602018-03-20 18:09:34 +0100154/* Establish a mobile terminated call described in 'cp' */
155function f_establish_mt(inout CallPars cp) runs on ConnHdlr {
156 var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
157 var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
Harald Welteafec4712018-03-19 22:52:17 +0100158 var PDU_SIP_Request sip_req;
Harald Welteb0d93602018-03-20 18:09:34 +0100159 var MNCC_PDU mncc;
Harald Welteafec4712018-03-19 22:52:17 +0100160
Harald Welteb0d93602018-03-20 18:09:34 +0100161 /* Ask MNCC_Emulation to "expect" a call to the given called number */
162 f_create_mncc_expect(cp.called);
Harald Welteafec4712018-03-19 22:52:17 +0100163
Harald Welteb0d93602018-03-20 18:09:34 +0100164 /* OSC <- SIP: A party sends SIP invite for a MT-call into OSC */
165 SIP.send(ts_SIP_INVITE(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
166 cp.comp.sip_seq_nr, cp.comp.sip_body));
167 /* MSC <- OSC: OSC generates MNCC_SETUP_REQ from INVITE */
168 MNCC.receive(tr_MNCC_SETUP_req) -> value mncc {
169 cp.mncc_call_id := mncc.u.signal.callref;
170 }
171 /* OSC -> SIP */
172 SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *,
173 "INVITE", 100, ?, "Trying", *));
Harald Welteafec4712018-03-19 22:52:17 +0100174
Harald Welteb0d93602018-03-20 18:09:34 +0100175 /* MSC -> OSC: After MS sends CALL CONF in response to SETUP */
176 MNCC.send(ts_MNCC_CALL_CONF_ind(cp.mncc_call_id));
177 /* MSC <- OSC: OSC asks MSC to create RTP socket */
178 MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id));
179 MNCC.send(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
Harald Welteafec4712018-03-19 22:52:17 +0100180
Harald Welteb0d93602018-03-20 18:09:34 +0100181 /* MSC -> OSC: After MS is ringing and sent CC ALERTING */
182 MNCC.send(ts_MNCC_ALERT_ind(cp.mncc_call_id));
183 SIP.clear;
184 SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *,
185 "INVITE", 180, ?, "Ringing", *));
Harald Welteafec4712018-03-19 22:52:17 +0100186
Harald Welteb0d93602018-03-20 18:09:34 +0100187 /* MSC -> OSC: After MT user has picked up and sent CC CONNECT */
188 MNCC.send(ts_MNCC_SETUP_CNF(cp.mncc_call_id));
189
190 SIP.clear;
191 interleave {
192 /* MSC <- OSC: OSC asks MSC to connect its RTP stream to remote end */
193 [] MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id)) {}
194 /* OSC -> SIP: OSC confirms call establishment to SIP side */
195 [] SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, ?,
196 "INVITE", 200, ?, "OK", ?)) {}
Harald Welteafec4712018-03-19 22:52:17 +0100197 }
Harald Welteb0d93602018-03-20 18:09:34 +0100198 /* OSC <- SIP: SIP world acknowledges "200 OK" */
199 SIP.send(ts_SIP_ACK(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
200 cp.comp.sip_seq_nr, omit));
201 /* MSC <- OSC: OSC sends SETUP COMPL to MNCC (which triggers CC CONNECT ACK */
202 MNCC.receive(tr_MNCC_SETUP_COMPL_req(cp.mncc_call_id));
Harald Welteafec4712018-03-19 22:52:17 +0100203}
204
Harald Welteb0d93602018-03-20 18:09:34 +0100205/* Establish a mobile originated call described in 'cp' */
206function f_establish_mo(inout CallPars cp) runs on ConnHdlr {
207 var MNCC_number dst := valueof(ts_MNCC_number(cp.called, GSM48_TON_UNKNOWN));
208 var MNCC_number src := valueof(ts_MNCC_number(cp.calling, GSM48_TON_UNKNOWN));
209 var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
210 var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
211 var PDU_SIP_Request sip_req;
212 var integer seq_nr;
213
214 f_create_sip_expect(cp.comp.sip_url_ext.addr.nameAddr.addrSpec);
215
216 /* MSC -> OSC: MSC sends SETUP.ind after CC SETUP was received from MS */
217 MNCC.send(ts_MNCC_SETUP_ind(cp.mncc_call_id, dst, src, "262420123456789"));
218 /* MSC <- OSC: Create GSM side RTP socket */
219 MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) {
220 var MNCC_PDU mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
221 mncc.u.rtp.payload_msg_type := oct2int('0300'O);
222 MNCC.send(mncc); /* FIXME: port/ip */
223 }
224 /* OSC -> SIP: Send INVITE with GSM side IP/Port in SDP */
225 SIP.receive(tr_SIP_INVITE(?, sip_addr_gsm, sip_addr_ext, ?, ?)) -> value sip_req {
226 cp.comp.sip_url_gsm.params := sip_req.msgHeader.fromField.fromParams;
227 cp.comp.sip_call_id := sip_req.msgHeader.callId.callid;
228 seq_nr := sip_req.msgHeader.cSeq.seqNumber;
229 }
230 /* OSC <- SIP: Notify call is proceeding */
231 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
232 "INVITE", 100, seq_nr, "Trying", sip_req.msgHeader.via));
233 /* MSC <- OSC: "100 Trying" translated to MNCC_CALL_PROC_REQ */
234 MNCC.receive(tr_MNCC_CALL_PROC_req(cp.mncc_call_id));
235
236 /* OSC <- SIP: SIP-terminated user is ringing now */
237 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
238 "INVITE", 180, seq_nr, "Ringing", sip_req.msgHeader.via));
239
240 /* MSC <- OSC: "180 Ringing" translated to MNCC_ALERT_REQ */
241 MNCC.receive(tr_MNCC_ALERT_req(cp.mncc_call_id)) {}
242
243 /* OSC <- SIP: SIP-terminated user has accepted the call */
244 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
245 "INVITE", 200, seq_nr, "OK", sip_req.msgHeader.via,
246 cp.comp.sip_body));
247 MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id));
248 /* MSC <- OSC: "200 OK" translated to MNCC_SETUP_RSP */
249 MNCC.receive(tr_MNCC_SETUP_rsp(cp.mncc_call_id));
250
251 /* MSC -> OSC: CC CONNECT ACK was received from MS */
252 MNCC.send(ts_MNCC_SETUP_COMPL_ind(cp.mncc_call_id));
253 /* OSC -> SIP: Acknowledge the call */
254 SIP.receive(tr_SIP_ACK(cp.comp.sip_call_id, sip_addr_gsm, sip_addr_ext, ?, omit));
255}
256
257/* Release call from the mobile side */
258function f_release_mobile(inout CallPars cp) runs on ConnHdlr {
259 var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
260 var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
261 var PDU_SIP_Request sip_req;
262 SIP.clear;
263 /* MSC -> OSC: Simulate a CC DISCONNET from the MT user */
264 MNCC.send(ts_MNCC_DISC_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
265 /* OSC -> SIP: Expect BYE from OSC to SIP side */
266 SIP.receive(tr_SIP_BYE(cp.comp.sip_call_id, sip_addr_gsm, sip_addr_ext, ?, *)) -> value sip_req {
267 cp.comp.sip_url_gsm.params := sip_req.msgHeader.fromField.fromParams;
268 }
269 /* OSC <- SIP: Acknowledge the BYE */
270 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext,
271 "BYE", 200, sip_req.msgHeader.cSeq.seqNumber, "OK",
272 sip_req.msgHeader.via));
273 /* MSC <- OSC: Send REL_REQ to MSC, triggers CC RELEASE REQ to MS */
274 MNCC.receive(tr_MNCC_REL_req(cp.mncc_call_id)); // CAUSE?
275 /* MSC -> OSC: MS has responded with CC CLEAR COMPL, triggers MNCC_REL_CNF */
276 MNCC.send(ts_MNCC_REL_cnf(cp.mncc_call_id, ts_MNCC_cause(0)));
277}
278
279/* Release call from the SIP side */
280function f_release_sip(inout CallPars cp) runs on ConnHdlr {
281 var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm);
282 var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext);
283 /* OSC <- SIP: SIP-side sends a BYE to OSC */
284 SIP.send(ts_SIP_BYE(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm,
285 cp.comp.sip_seq_nr, omit));
286 /* MSC <- OSC: Expect OSC to cause MNCC Disconnect Request */
287 MNCC.receive(tr_MNCC_DISC_req(cp.mncc_call_id));
288 /* MSC -> OSC: Indicate GSM side release */
289 MNCC.send(ts_MNCC_REL_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
290 /* OSC -> SIP: Confirmation to SIP side */
291 SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *,
292 "BYE", 200, cp.comp.sip_seq_nr, "OK", omit));
293}
294
295/* Successful MT Call, which is subsequently released by GSM side */
296private function f_TC_mt_success_rel_gsm(charstring id) runs on ConnHdlr {
297 var CallPars cp := valueof(t_CallPars(false));
298 f_CallPars_compute(cp);
299 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
300 f_sleep(3.0)
301
302 f_establish_mt(cp);
303 /* now call is fully established */
304 f_sleep(2.0);
305 f_release_mobile(cp);
306 setverdict(pass);
307}
308testcase TC_mt_success_rel_gsm() runs on test_CT {
Harald Welteafec4712018-03-19 22:52:17 +0100309 var ConnHdlrPars pars;
310 var ConnHdlr vc_conn;
Harald Welteafec4712018-03-19 22:52:17 +0100311 f_init();
Harald Welteafec4712018-03-19 22:52:17 +0100312 pars := valueof(t_Pars);
Harald Welteb0d93602018-03-20 18:09:34 +0100313 vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
314 vc_conn.done;
315}
316
317/* Successful MT Call, which is subsequently released by SIP side */
318private function f_TC_mt_success_rel_sip(charstring id) runs on ConnHdlr {
319 var CallPars cp := valueof(t_CallPars(false));
320 f_CallPars_compute(cp);
321 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
322 f_sleep(3.0)
323
324 f_establish_mt(cp);
325 /* now call is fully established */
326 f_sleep(2.0);
327 f_release_sip(cp);
328 setverdict(pass);
329}
330testcase TC_mt_success_rel_sip() runs on test_CT {
331 var ConnHdlrPars pars;
332 var ConnHdlr vc_conn;
333 f_init();
334 pars := valueof(t_Pars);
335 vc_conn := f_start_handler(refers(f_TC_mt_success_rel_sip), pars);
Harald Welteafec4712018-03-19 22:52:17 +0100336 vc_conn.done;
337}
338
339
Harald Welteb0d93602018-03-20 18:09:34 +0100340/* Successful MO Call, which is subsequently released by GSM side */
341private function f_TC_mo_success_rel_gsm(charstring id) runs on ConnHdlr {
342 var CallPars cp := valueof(t_CallPars(true));
343 f_CallPars_compute(cp);
344 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
345 f_sleep(3.0)
Harald Welteafec4712018-03-19 22:52:17 +0100346
Harald Welteb0d93602018-03-20 18:09:34 +0100347 f_establish_mo(cp);
348 /* now call is fully established */
349 f_sleep(2.0);
350 f_release_mobile(cp);
351 setverdict(pass);
352}
353testcase TC_mo_success_rel_gsm() runs on test_CT {
354 var ConnHdlrPars pars;
355 var ConnHdlr vc_conn;
356 f_init();
357 pars := valueof(t_Pars);
358 vc_conn := f_start_handler(refers(f_TC_mo_success_rel_gsm), pars);
359 vc_conn.done;
Harald Welteafec4712018-03-19 22:52:17 +0100360}
361
Harald Welteb0d93602018-03-20 18:09:34 +0100362/* Successful MO Call, which is subsequently released by SIP side */
363private function f_TC_mo_success_rel_sip(charstring id) runs on ConnHdlr {
364 var CallPars cp := valueof(t_CallPars(true));
365 f_CallPars_compute(cp);
366 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
367 f_sleep(3.0)
Harald Welteafec4712018-03-19 22:52:17 +0100368
Harald Welteb0d93602018-03-20 18:09:34 +0100369 f_establish_mo(cp);
370 /* now call is fully established */
371 f_sleep(2.0);
372 f_release_sip(cp);
373 setverdict(pass);
374}
375testcase TC_mo_success_rel_sip() runs on test_CT {
376 var ConnHdlrPars pars;
377 var ConnHdlr vc_conn;
378 f_init();
379 pars := valueof(t_Pars);
380 vc_conn := f_start_handler(refers(f_TC_mo_success_rel_sip), pars);
381 vc_conn.done;
382}
Harald Welteafec4712018-03-19 22:52:17 +0100383
384
385control {
Harald Welteb0d93602018-03-20 18:09:34 +0100386 execute( TC_mt_success_rel_gsm() );
387 execute( TC_mt_success_rel_sip() );
388 execute( TC_mo_success_rel_gsm() );
389 execute( TC_mo_success_rel_sip() );
Harald Welteafec4712018-03-19 22:52:17 +0100390}
391
392
393
394}