blob: 26a0701232e080e409159b5cac7315fa6da076d0 [file] [log] [blame]
Harald Welte00a067f2017-09-13 23:27:17 +02001module MGCP_Test {
Harald Weltef07c2862017-11-18 17:16:24 +01002 import from Osmocom_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +02003 import from MGCP_Types all;
Harald Welte4029e8c2017-11-23 22:00:42 +01004 import from MGCP_Templates all;
Harald Welte3c6ebb92017-09-16 00:56:57 +08005 import from SDP_Types all;
6 import from MGCP_CodecPort all;
7 import from MGCP_CodecPort_CtrlFunct all;
Harald Weltef07c2862017-11-18 17:16:24 +01008 import from RTP_CodecPort all;
9 import from RTP_CodecPort_CtrlFunct all;
Harald Weltebb7523b2018-03-29 08:52:01 +020010 import from RTP_Emulation all;
Harald Welte3c6ebb92017-09-16 00:56:57 +080011 import from IPL4asp_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +020012
Philipp Maierbb7a01c2018-02-01 12:32:57 +010013 const charstring c_mgw_domain := "mgw";
14 const charstring c_mgw_ep_rtpbridge := "rtpbridge/";
15
Harald Welte21ba5572017-09-19 17:55:05 +080016 /* any variables declared in the component will be available to
17 * all functions that 'run on' the named component, similar to
18 * class members in C++ */
Harald Welte00a067f2017-09-13 23:27:17 +020019 type component dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080020 port MGCP_CODEC_PT MGCP;
21 var boolean initialized := false;
Harald Welte55015362017-11-18 16:02:42 +010022 var ConnectionId g_mgcp_conn_id := -1;
Harald Weltee1e18c52017-09-17 16:23:07 +080023 var integer g_trans_id;
Harald Weltef07c2862017-11-18 17:16:24 +010024
Harald Weltebb7523b2018-03-29 08:52:01 +020025 var RTP_Emulation_CT vc_RTPEM[2];
26 port RTPEM_CTRL_PT RTPEM[2];
Harald Welte00a067f2017-09-13 23:27:17 +020027 };
28
Harald Weltee1e18c52017-09-17 16:23:07 +080029 function get_next_trans_id() runs on dummy_CT return MgcpTransId {
30 var MgcpTransId tid := int2str(g_trans_id);
31 g_trans_id := g_trans_id + 1;
32 return tid;
33 }
34
Harald Welte21ba5572017-09-19 17:55:05 +080035 /* all parameters declared here can be modified / overridden by
36 * the config file in the [MODULE_PARAMETERS] section. If no
37 * config file is used or the file doesn't specify them, the
38 * default values assigned below are used */
Harald Welte3c6ebb92017-09-16 00:56:57 +080039 modulepar {
40 PortNumber mp_local_udp_port := 2727;
41 charstring mp_local_ip := "127.0.0.1";
42 PortNumber mp_remote_udp_port := 2427;
43 charstring mp_remote_ip := "127.0.0.1";
Harald Weltef07c2862017-11-18 17:16:24 +010044 PortNumber mp_local_rtp_port_base := 10000;
Harald Welte3c6ebb92017-09-16 00:56:57 +080045 }
46
Harald Weltebb7523b2018-03-29 08:52:01 +020047 private function f_rtpem_init(inout RTP_Emulation_CT comp_ref, integer i)
48 runs on dummy_CT {
49 comp_ref := RTP_Emulation_CT.create("RTPEM" & int2str(i));
50 map(comp_ref:RTP, system:RTP);
51 map(comp_ref:RTCP, system:RTCP);
52 comp_ref.start(RTP_Emulation.f_main());
53 }
54
Harald Welte21ba5572017-09-19 17:55:05 +080055 /* initialization function, called by each test case at the
56 * beginning, but 'initialized' variable ensures its body is
57 * only executed once */
Harald Welteedc45c12017-11-18 19:15:05 +010058 private function f_init(template MgcpEndpoint ep := omit) runs on dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080059 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010060 var uint32_t ssrc;
Harald Welteedc45c12017-11-18 19:15:05 +010061 if (initialized == false) {
62 initialized := true;
63
64 /* some random number for the initial transaction id */
65 g_trans_id := float2int(rnd()*65535.0);
66 map(self:MGCP, system:MGCP_CODEC_PT);
67 /* connect the MGCP test port using the given
68 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
69 * */
70 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
Harald Welte9220f632018-05-23 20:27:02 +020071 if (not ispresent(res.connId)) {
72 setverdict(fail, "Could not connect MGCP, check your configuration");
73 self.stop;
74 }
Harald Welteedc45c12017-11-18 19:15:05 +010075 g_mgcp_conn_id := res.connId;
76
Harald Weltebb7523b2018-03-29 08:52:01 +020077 for (var integer i := 0; i < sizeof(vc_RTPEM); i := i+1) {
78 f_rtpem_init(vc_RTPEM[i], i);
79 connect(vc_RTPEM[i]:CTRL, self:RTPEM[i]);
80 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080081 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080082
Harald Welteedc45c12017-11-18 19:15:05 +010083 if (isvalue(ep)) {
84 /* do a DLCX on all connections of the EP */
85 f_dlcx_ignore(valueof(ep));
86 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080087 }
88
Harald Welte00a067f2017-09-13 23:27:17 +020089 testcase TC_selftest() runs on dummy_CT {
90 const charstring c_auep := "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +010091 const charstring c_mdcx3 := "MDCX 18983215 " & c_mgw_ep_rtpbridge & "1@" & c_mgw_domain & " MGCP 1.0\r\n";
Harald Welte00a067f2017-09-13 23:27:17 +020092 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
93 "I: 1\n" &
94 "\n" &
95 "v=0\r\n" &
96 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
97 "s=-\r\n" &
98 "c=IN IP4 0.0.0.0\r\n" &
99 "t=0 0\r\n" &
100 "m=audio 0 RTP/AVP 126\r\n" &
101 "a=rtpmap:126 AMR/8000\r\n" &
102 "a=ptime:20\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100103 const charstring c_mdcx4 := "MDCX 18983216 " & c_mgw_ep_rtpbridge & "1@" & c_mgw_domain & " MGCP 1.0\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200104 "M: sendrecv\r" &
105 "C: 2\r\n" &
106 "I: 1\r\n" &
107 "L: p:20, a:AMR, nt:IN\r\n" &
108 "\n" &
109 "v=0\r\n" &
110 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800111 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200112 "c=IN IP4 0.0.0.0\r\n" &
113 "t=0 0\r\n" &
114 "m=audio 4441 RTP/AVP 99\r\n" &
115 "a=rtpmap:99 AMR/8000\r\n" &
116 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800117 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200118
119 log(c_auep);
120 log(dec_MgcpCommand(c_auep));
121
122 log(c_mdcx3);
123 log(dec_MgcpCommand(c_mdcx3));
124
125 log(c_mdcx3_ret);
126 log(dec_MgcpResponse(c_mdcx3_ret));
127
128 log(c_mdcx4);
129 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800130
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100131 log(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H));
132 log(enc_MgcpCommand(valueof(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H))));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800133
134 log(c_crcx510_ret);
135 log(dec_MgcpResponse(c_crcx510_ret));
136 log(dec_MgcpMessage(c_crcx510_ret));
137 }
138
Harald Weltee636afd2017-09-17 16:24:09 +0800139 /* CRCX test ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100140 * x without mandatory CallId
Harald Weltee636afd2017-09-17 16:24:09 +0800141 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
142 * - CRCX with remote session description and without
143 *
144 * general ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100145 * x packetization != 20ms
146 * x invalid mode
Harald Weltee636afd2017-09-17 16:24:09 +0800147 * x unsupported mode (517)
148 * x bidirectional mode before RemoteConnDesc: 527
149 * - invalid codec
Harald Weltee0b331f2017-11-18 20:34:33 +0100150 * x retransmission of same transaction
Harald Weltee636afd2017-09-17 16:24:09 +0800151 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
152 */
153
Harald Welte21ba5572017-09-19 17:55:05 +0800154 /* build a receive template for receiving a MGCP message. You
155 * pass the MGCP response template in, and it will generate an
156 * MGCP_RecvFrom template that can match the primitives arriving on the
157 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800158 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
159 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100160 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800161 remName := mp_remote_ip,
162 remPort := mp_remote_udp_port,
163 locName := mp_local_ip,
164 locPort := mp_local_udp_port,
165 msg := { response := resp }
166 }
167 return mrf;
168 }
169
170 /* Send a MGCP request + receive a (matching!) response */
171 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
172 var MgcpMessage msg := { command := valueof(cmd) };
173 resp.line.trans_id := cmd.line.trans_id;
174 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800175 var MGCP_RecvFrom mrf;
176 timer T := 5.0;
177
Harald Welte55015362017-11-18 16:02:42 +0100178 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800179 T.start;
180 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800181 [] MGCP.receive(mrt) -> value mrf { }
182 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800183 [] MGCP.receive { repeat; }
184 [] T.timeout { setverdict(fail); }
185 }
186 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800187
188 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
189 return mrf.msg.response;
190 } else {
191 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
192 return r;
193 }
Harald Welte00a067f2017-09-13 23:27:17 +0200194 }
195
Harald Welteba62c8c2017-11-18 18:26:49 +0100196 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
197 var integer i;
198 for (i := 0; i < lengthof(resp.params); i := i + 1) {
199 var MgcpParameter par := resp.params[i];
200 if (par.code == "I") {
201 return str2hex(par.val);
202 }
203 }
204 setverdict(fail);
205 return '00000000'H;
206 }
207
Harald Welte10889c12017-11-18 19:40:31 +0100208 function f_dlcx(MgcpEndpoint ep, template MgcpResponseCode ret_code, template charstring ret_val,
209 template MgcpCallId call_id := omit,
210 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welteba62c8c2017-11-18 18:26:49 +0100211 var template MgcpCommand cmd;
212 var MgcpResponse resp;
213 var template MgcpResponse rtmpl := {
214 line := {
Harald Welte10889c12017-11-18 19:40:31 +0100215 code := ret_code,
216 string := ret_val
Harald Welteba62c8c2017-11-18 18:26:49 +0100217 },
218 params := *,
219 sdp := *
220 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100221 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100222 resp := mgcp_transceive_mgw(cmd, rtmpl);
223 }
224
Harald Welte10889c12017-11-18 19:40:31 +0100225 /* Send DLCX and expect OK response */
226 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
227 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Weltef91edf32017-12-28 14:16:21 +0100228 f_dlcx(ep, ("200","250"), "OK", call_id, conn_id);
Harald Welte10889c12017-11-18 19:40:31 +0100229 }
230
Harald Welteba62c8c2017-11-18 18:26:49 +0100231 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100232 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100233 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welte10889c12017-11-18 19:40:31 +0100234 f_dlcx(ep, ?, *, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100235 }
236
Harald Weltebb7523b2018-03-29 08:52:01 +0200237 type record HostPort {
238 charstring hostname,
239 integer portnr optional
240 }
241 type record RtpFlowData {
242 HostPort em, /* emulation side */
243 HostPort mgw, /* mgw side */
244 uint7_t pt,
245 charstring codec,
246 MgcpConnectionId mgcp_conn_id optional
247 }
248
249 function f_flow_create(RTPEM_CTRL_PT pt, MgcpEndpoint ep, inout RtpFlowData flow,
250 boolean one_phase := true)
251 runs on dummy_CT {
252 var MgcpCallId call_id := '1226'H;
253 var template MgcpCommand cmd;
254 var MgcpResponse resp;
255
256 /* bind local RTP emulation socket */
257 f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
258
259 if (one_phase) {
260 /* Connect flow to MGW */
261 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Welteedc88742018-03-29 18:01:16 +0200262 cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
Harald Weltebb7523b2018-03-29 08:52:01 +0200263 flow.em.portnr, { int2str(flow.pt) },
264 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
265 valueof(ts_SDP_ptime(20)) });
266 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
267 flow.mgcp_conn_id := extract_conn_id(resp);
268 /* extract port number from response */
269 flow.mgw.portnr :=
270 resp.sdp.media_list[0].media_field.ports.port_number;
271 } else {
272 /* first create the MGW side RTP socket */
273 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
274 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
275 flow.mgcp_conn_id := extract_conn_id(resp);
276 /* extract MGW-side port number from response */
277 flow.mgw.portnr :=
278 resp.sdp.media_list[0].media_field.ports.port_number;
279
280 /* then connect it to the emulation-side RTP socket using SDP */
281 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, flow.mgcp_conn_id);
Harald Welteedc88742018-03-29 18:01:16 +0200282 cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
Harald Weltebb7523b2018-03-29 08:52:01 +0200283 flow.em.portnr, { int2str(flow.pt) },
284 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
285 valueof(ts_SDP_ptime(20)) });
286 resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
287
288 }
289 /* finally, connect the emulation-side RTP socket to the MGW */
290 f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);
291 }
292
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100293 function f_crcx(charstring ep_prefix) runs on dummy_CT {
294 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800295 var template MgcpCommand cmd;
296 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100297 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800298
Harald Welteedc45c12017-11-18 19:15:05 +0100299 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800300
Harald Welteba62c8c2017-11-18 18:26:49 +0100301 /* create the connection on the MGW */
302 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100303 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welteba62c8c2017-11-18 18:26:49 +0100304 extract_conn_id(resp);
305
306 /* clean-up */
307 f_dlcx_ok(ep, call_id);
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100308 }
Harald Welteba62c8c2017-11-18 18:26:49 +0100309
Philipp Maier45635f42018-06-05 17:28:02 +0200310 function f_crcx_no_lco(charstring ep_prefix) runs on dummy_CT {
311 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
312 var template MgcpCommand cmd;
313 var MgcpResponse resp;
314 var MgcpCallId call_id := '1234'H;
315
316 f_init(ep);
317
318 /* create the connection on the MGW */
319 cmd := ts_CRCX_no_lco(get_next_trans_id(), ep, "recvonly", call_id);
320 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
321 extract_conn_id(resp);
322
323 /* clean-up */
324 f_dlcx_ok(ep, call_id);
325
326 /* See also OS#2658: Even when we omit the LCO information, we
327 expect the MGW to pick a sane payload type for us. This
328 payload type should be visible in the SDP of the response. */
329 if (resp.sdp.media_list[0].attributes[0].rtpmap.attr_value != "0 PCMU/8000/1") {
330 setverdict(fail, "SDP contains unexpected codec");
331 }
332
333 /* See also OS#2658: We also expect the MGW to assign a port
334 number to us. */
335 if (isbound(resp.sdp.media_list[0].media_field.ports.port_number) == false) {
336 setverdict(fail, "SDP does not contain a port number");
337 }
338 }
339
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100340 /* test valid CRCX without SDP */
341 testcase TC_crcx() runs on dummy_CT {
342 f_crcx(c_mgw_ep_rtpbridge);
343 setverdict(pass);
344 }
345
Philipp Maier45635f42018-06-05 17:28:02 +0200346 /* test valid CRCX without SDP and LCO */
347 testcase TC_crcx_no_lco() runs on dummy_CT {
348 f_crcx_no_lco(c_mgw_ep_rtpbridge);
349 setverdict(pass);
350 }
351
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100352 /* test valid CRCX without SDP (older method without endpoint prefix) */
353 testcase TC_crcx_noprefix() runs on dummy_CT {
354 f_crcx("");
Harald Weltee636afd2017-09-17 16:24:09 +0800355 setverdict(pass);
356 }
357
358 /* test CRCX with unsupported mode, expect 517 */
359 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
360 var template MgcpCommand cmd;
361 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100362 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100363 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800364 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
365
Harald Welteedc45c12017-11-18 19:15:05 +0100366 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800367
Harald Welteba62c8c2017-11-18 18:26:49 +0100368 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800369 resp := mgcp_transceive_mgw(cmd, rtmpl);
370 setverdict(pass);
371 }
372
Harald Welte21ba5572017-09-19 17:55:05 +0800373 /* test CRCX with early bi-directional mode, expect 527 as
374 * bi-diretional media can only be established once both local and
375 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800376 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
377 var template MgcpCommand cmd;
378 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100379 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100380 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800381 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
382
Harald Welteedc45c12017-11-18 19:15:05 +0100383 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800384
Harald Welteba62c8c2017-11-18 18:26:49 +0100385 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800386 resp := mgcp_transceive_mgw(cmd, rtmpl);
387 setverdict(pass);
388 }
389
390 /* test CRCX with unsupported Parameters */
391 testcase TC_crcx_unsupp_param() runs on dummy_CT {
392 var template MgcpCommand cmd;
393 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100394 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100395 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800396 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
397
Harald Welteedc45c12017-11-18 19:15:05 +0100398 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800399
Harald Welteba62c8c2017-11-18 18:26:49 +0100400 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100401 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
402 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
403
Harald Weltee636afd2017-09-17 16:24:09 +0800404 resp := mgcp_transceive_mgw(cmd, rtmpl);
405 setverdict(pass);
406 }
407
408 /* test CRCX with missing CallId */
409 testcase TC_crcx_missing_callid() runs on dummy_CT {
410 var template MgcpCommand cmd;
411 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100412 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Weltef91edf32017-12-28 14:16:21 +0100413 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","516"));
Harald Weltee636afd2017-09-17 16:24:09 +0800414
Harald Welteedc45c12017-11-18 19:15:05 +0100415 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800416
Harald Welteba62c8c2017-11-18 18:26:49 +0100417 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800418 cmd.params := {
419 t_MgcpParConnMode("recvonly"),
420 t_MgcpParLocConnOpt("p:20")
421 }
422 resp := mgcp_transceive_mgw(cmd, rtmpl);
423 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100424
Harald Weltee636afd2017-09-17 16:24:09 +0800425 }
426
427 /* test CRCX with missing Mode */
428 testcase TC_crcx_missing_mode() runs on dummy_CT {
429 var template MgcpCommand cmd;
430 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100431 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100432 var MgcpCallId call_id := '1229'H;
Harald Weltef91edf32017-12-28 14:16:21 +0100433 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","517"));
Harald Weltee636afd2017-09-17 16:24:09 +0800434
Harald Welteedc45c12017-11-18 19:15:05 +0100435 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800436
Harald Welteba62c8c2017-11-18 18:26:49 +0100437 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800438 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100439 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800440 t_MgcpParLocConnOpt("p:20")
441 }
442 resp := mgcp_transceive_mgw(cmd, rtmpl);
443 setverdict(pass);
444 }
445
446 /* test CRCX with unsupported packetization interval */
447 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
448 var template MgcpCommand cmd;
449 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100450 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100451 var MgcpCallId call_id := '1228'H;
Harald Welte0d198612017-11-18 19:58:31 +0100452 var template MgcpResponse rtmpl := tr_MgcpResp_Err("535");
Harald Weltee636afd2017-09-17 16:24:09 +0800453
Harald Welteedc45c12017-11-18 19:15:05 +0100454 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800455
Harald Welteba62c8c2017-11-18 18:26:49 +0100456 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100457 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800458 resp := mgcp_transceive_mgw(cmd, rtmpl);
459 setverdict(pass);
460 }
461
462 /* test CRCX with illegal double presence of local connection option */
463 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
464 var template MgcpCommand cmd;
465 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100466 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100467 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800468 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
469
Harald Welteedc45c12017-11-18 19:15:05 +0100470 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800471
Harald Welteba62c8c2017-11-18 18:26:49 +0100472 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100473 /* p:20 is permitted only once and not twice! */
474 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800475 resp := mgcp_transceive_mgw(cmd, rtmpl);
476 setverdict(pass);
477 }
478
479 /* test valid CRCX with valid SDP */
480 testcase TC_crcx_sdp() runs on dummy_CT {
481 var template MgcpCommand cmd;
482 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100483 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100484 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800485
Harald Welteedc45c12017-11-18 19:15:05 +0100486 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800487
Harald Welteba62c8c2017-11-18 18:26:49 +0100488 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800489 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
490 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
491 valueof(ts_SDP_ptime(20)) });
Harald Welte9988d282017-11-18 19:22:00 +0100492 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Philipp Maierdffa6a42018-02-02 11:55:44 +0100493
494 /* clean-up */
495 f_dlcx_ok(ep, call_id);
496
Harald Weltee636afd2017-09-17 16:24:09 +0800497 setverdict(pass);
498 }
499
Philipp Maier5e06cee2018-02-01 18:28:08 +0100500 /* test valid wildcarded CRCX */
501 testcase TC_crcx_wildcarded() runs on dummy_CT {
502 var template MgcpCommand cmd;
503 var MgcpResponse resp;
504 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
505 var MgcpCallId call_id := '1234'H;
506 var MgcpEndpoint ep_assigned;
507 f_init();
508
509 /* create the connection on the MGW */
510 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
511 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
512 extract_conn_id(resp);
513
514 /* extract endpoint name we got assigned by the MGW */
515 var MgcpMessage resp_msg := {
516 response := resp
517 }
518 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
519 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
520 }
521
522 /* clean-up */
523 f_dlcx_ok(ep_assigned, call_id);
524
525 setverdict(pass);
526 }
527
528 /* test valid wildcarded CRCX */
529 testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
530 const integer n_endpoints := 32;
531 var integer i;
532 var template MgcpCommand cmd;
533 var MgcpResponse resp;
534 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
535 var MgcpCallId call_id := '1234'H;
536 var MgcpEndpoint ep_assigned[n_endpoints];
537 f_init();
538
539 /* Exhaust all endpoint resources on the virtual trunk */
540 for (i := 0; i < n_endpoints; i := i+1) {
541 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
542 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
543
544 /* Make sure we got a connection id */
545 extract_conn_id(resp);
546
547 var MgcpMessage resp_msg := {
548 response := resp
549 }
550 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
551 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
552 }
553 }
554
555 /* Try to allocate one more endpoint, which should fail */
556 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
557 var template MgcpResponse rtmpl := tr_MgcpResp_Err("403");
558 resp := mgcp_transceive_mgw(cmd, rtmpl);
559 setverdict(pass);
560
561 /* clean-up */
562 for (i := 0; i < n_endpoints; i := i+1) {
563 f_dlcx_ok(ep_assigned[i], call_id);
564 }
565 setverdict(pass);
566 }
567
Harald Weltee636afd2017-09-17 16:24:09 +0800568 /* TODO: various SDP related bits */
569
570
571 /* TODO: CRCX with X-Osmux */
572 /* TODO: double CRCX without force_realloc */
573
574 /* TODO: MDCX (various) */
575
576 /* TODO: MDCX without CRCX first */
577 testcase TC_mdcx_without_crcx() runs on dummy_CT {
578 var template MgcpCommand cmd;
579 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100580 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "3@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100581 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800582 var template MgcpResponse rtmpl := {
583 line := {
584 /* TODO: accept/enforce better error? */
585 code := "400",
586 string := ?
587 },
588 params:= { },
589 sdp := omit
590 };
591
Harald Welteedc45c12017-11-18 19:15:05 +0100592 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800593
Harald Welte2bcfd3a2017-11-18 22:14:35 +0100594 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800595 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
596 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
597 valueof(ts_SDP_ptime(20)) });
598 resp := mgcp_transceive_mgw(cmd, rtmpl);
599 setverdict(pass);
600 }
601
602 /* DLCX without CRCX first */
603 testcase TC_dlcx_without_crcx() runs on dummy_CT {
604 var template MgcpCommand cmd;
605 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100606 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800607 var template MgcpResponse rtmpl := {
608 line := {
Harald Weltef91edf32017-12-28 14:16:21 +0100609 code := ("400", "515"),
Harald Weltee636afd2017-09-17 16:24:09 +0800610 string := ?
611 },
612 params:= { },
613 sdp := omit
614 };
615
Harald Welteedc45c12017-11-18 19:15:05 +0100616 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800617
Harald Welteedc45c12017-11-18 19:15:05 +0100618 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800619 resp := mgcp_transceive_mgw(cmd, rtmpl);
620 setverdict(pass);
621 }
622
Philipp Maier8a3dc922018-02-02 14:55:12 +0100623 /* test valid wildcarded MDCX */
624 testcase TC_mdcx_wildcarded() runs on dummy_CT {
625 /* Note: A wildcarded MDCX is not allowed, so we expect the
626 * MGW to reject this request */
627 var template MgcpCommand cmd;
628 var MgcpResponse resp;
629 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
630 var MgcpCallId call_id := '1225'H;
631 var template MgcpResponse rtmpl := {
632 line := {
633 /* TODO: accept/enforce better error? */
634 code := "507",
635 string := ?
636 },
637 params:= { },
638 sdp := omit
639 };
640
641 f_init(ep);
642
643 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
644 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
645 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
646 valueof(ts_SDP_ptime(20)) });
647 resp := mgcp_transceive_mgw(cmd, rtmpl);
648 setverdict(pass);
649 }
650
651 /* test valid wildcarded DLCX */
652 testcase TC_dlcx_wildcarded() runs on dummy_CT {
653 /* Note: A wildcarded DLCX is specified, but our MGW does not
654 * support this feature so we expect the MGW to reject the
655 * request */
656 var template MgcpCommand cmd;
657 var MgcpResponse resp;
658 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
659 var template MgcpResponse rtmpl := {
660 line := {
661 code := "507",
662 string := ?
663 },
664 params:= { },
665 sdp := omit
666 };
667
668 f_init(ep);
669
670 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
671 resp := mgcp_transceive_mgw(cmd, rtmpl);
672 setverdict(pass);
673 }
674
Harald Welte79181ff2017-11-18 19:26:11 +0100675 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
676 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
677 var template MgcpCommand cmd;
678 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100679 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte79181ff2017-11-18 19:26:11 +0100680 var MgcpCallId call_id := '51234'H;
681
682 f_init(ep);
683
684 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
685 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
686
687 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
688
689 setverdict(pass);
690 }
691
Harald Welte646ecdb2017-12-28 03:21:57 +0100692 function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
693 var template MgcpCommand cmd;
694 var MgcpResponse resp;
695
696 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
697 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
698
699 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
700
701 setverdict(pass);
702 }
703
704 testcase TC_crcx_dlcx_30ep() runs on dummy_CT {
705 var MgcpEndpoint ep;
706 var MgcpCallId call_id;
707 var integer ep_nr;
708
709 f_init();
710
711 for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100712 ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
Harald Welte646ecdb2017-12-28 03:21:57 +0100713 call_id := int2hex(ep_nr, 2) & '1234'H;
714 f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
715 }
716 }
717
Harald Welte79181ff2017-11-18 19:26:11 +0100718 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
719 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800720 var template MgcpCommand cmd;
721 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100722 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100723 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800724
Harald Welteedc45c12017-11-18 19:15:05 +0100725 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800726
Harald Welteba62c8c2017-11-18 18:26:49 +0100727 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100728 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800729
Harald Welteba62c8c2017-11-18 18:26:49 +0100730 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800731
732 setverdict(pass);
733 }
734
Harald Welte79181ff2017-11-18 19:26:11 +0100735 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
736 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
737 var template MgcpCommand cmd;
738 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100739 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100740 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100741
742 f_init(ep);
743
744 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
745 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
746
747 f_dlcx_ok(ep);
748
749 setverdict(pass);
750 }
751
752
Harald Welte6d167f82017-11-18 19:41:35 +0100753 /* CRCX + DLCX of valid endpoint but invalid call-id */
754 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
755 var template MgcpCommand cmd;
756 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100757 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100758 var MgcpCallId call_id := '51231'H;
759
760 f_init(ep);
761
762 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
763 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
764
765 f_dlcx(ep, "516", *, 'ffff'H);
766
767 setverdict(pass);
768 }
769
770
771 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
772 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
773 var template MgcpCommand cmd;
774 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100775 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100776 var MgcpCallId call_id := '51230'H;
777
778 f_init(ep);
779
780 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
781 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
782
783 f_dlcx(ep, "515", *, call_id, 'ffff'H);
784
785 setverdict(pass);
786 }
787
788
Harald Weltee636afd2017-09-17 16:24:09 +0800789 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100790 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
791 var template MgcpCommand cmd;
792 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100793 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Weltef53f1642017-11-18 19:57:11 +0100794 var MgcpCallId call_id := '51229'H;
795 var template MgcpResponse rtmpl := {
796 line := {
797 code := "200",
798 string := "OK"
799 },
800 params:= { },
801 sdp := omit
802 };
803
804 f_init(ep);
805
806 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
807 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
808
809 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
810 resp := mgcp_transceive_mgw(cmd, rtmpl);
811 resp := mgcp_transceive_mgw(cmd, rtmpl);
812
813 setverdict(pass);
814 }
815
Harald Weltebb7523b2018-03-29 08:52:01 +0200816 template (value) RtpFlowData t_RtpFlow(charstring host_a, charstring host_b, uint7_t pt,
817 charstring codec) := {
818 em := {
819 hostname := host_a,
820 portnr := omit
821 },
822 mgw := {
823 hostname := host_b,
824 portnr := omit
825 },
826 pt := pt,
827 codec := codec
828 }
Harald Weltef53f1642017-11-18 19:57:11 +0100829
Harald Weltebb7523b2018-03-29 08:52:01 +0200830 /* transmit RTP streams between two RTP Emulations back-to-back; expect no loss */
831 testcase TC_rtpem_selftest() runs on dummy_CT {
832 var RtpemStats stats[2];
833 var integer local_port := 10000;
834 var integer local_port2 := 20000;
835
836 f_init();
837
838 f_rtpem_bind(RTPEM[0], "127.0.0.1", local_port);
839 f_rtpem_bind(RTPEM[1], "127.0.0.2", local_port2);
840
841 f_rtpem_connect(RTPEM[0], "127.0.0.2", local_port2);
842 f_rtpem_connect(RTPEM[1], "127.0.0.1", local_port);
843
844 log("=== starting");
845 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
846 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
847
848 f_sleep(5.0);
849
850 log("=== stopping");
851 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
852 f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
853 f_sleep(0.5);
854 f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
855 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
856
857 stats[0] := f_rtpem_stats_get(RTPEM[0]);
858 stats[1] := f_rtpem_stats_get(RTPEM[1]);
859 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
860 setverdict(fail, "RTP endpoint statistics don't match");
861 }
862 setverdict(pass);
863 }
864
865 /* create two local RTP emulations; create two connections on MGW EP, exchange some data */
866 testcase TC_two_crcx_and_rtp() runs on dummy_CT {
867 var RtpFlowData flow[2];
868 var RtpemStats stats[2];
869 var template MgcpCommand cmd;
870 var MgcpResponse resp;
871 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
872 var MgcpCallId call_id := '1226'H;
873
874 f_init(ep);
875
876 /* from us to MGW */
877 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
878 /* bind local RTP emulation sockets */
879 flow[0].em.portnr := 10000;
880 f_flow_create(RTPEM[0], ep, flow[0]);
881
882 /* from MGW back to us */
883 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
884 flow[1].em.portnr := 20000;
885 f_flow_create(RTPEM[1], ep, flow[1]);
886
887 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
888 f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
889
890 f_sleep(1.0);
891
892 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
893 f_sleep(0.1);
894
895 stats[0] := f_rtpem_stats_get(RTPEM[0]);
896 stats[1] := f_rtpem_stats_get(RTPEM[1]);
897 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
898 setverdict(fail, "RTP endpoint statistics don't match");
899 }
900
901 f_dlcx_ok(ep, call_id);
902 setverdict(pass);
903
904 }
Harald Weltef53f1642017-11-18 19:57:11 +0100905
Harald Weltee636afd2017-09-17 16:24:09 +0800906 /* TODO: Double-DLCX (no retransmission) */
907
908
909
910 /* TODO: AUEP (various) */
911 /* TODO: RSIP (various) */
912 /* TODO: RQNT (various) */
913 /* TODO: EPCF (various) */
914 /* TODO: AUCX (various) */
915 /* TODO: invalid verb (various) */
916
Harald Welte00a067f2017-09-13 23:27:17 +0200917 control {
918 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800919 execute(TC_crcx());
Philipp Maier45635f42018-06-05 17:28:02 +0200920 execute(TC_crcx_no_lco());
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100921 execute(TC_crcx_noprefix());
Harald Weltee636afd2017-09-17 16:24:09 +0800922 execute(TC_crcx_unsupp_mode());
923 execute(TC_crcx_early_bidir_mode());
924 execute(TC_crcx_unsupp_param());
925 execute(TC_crcx_missing_callid());
926 execute(TC_crcx_missing_mode());
927 execute(TC_crcx_unsupp_packet_intv());
928 execute(TC_crcx_illegal_double_lco());
929 execute(TC_crcx_sdp());
Philipp Maier5e06cee2018-02-01 18:28:08 +0100930 execute(TC_crcx_wildcarded());
931 execute(TC_crcx_wildcarded_exhaust());
Harald Weltee636afd2017-09-17 16:24:09 +0800932 execute(TC_mdcx_without_crcx());
933 execute(TC_dlcx_without_crcx());
Philipp Maier8a3dc922018-02-02 14:55:12 +0100934 execute(TC_mdcx_wildcarded());
935 execute(TC_dlcx_wildcarded());
Harald Welte79181ff2017-11-18 19:26:11 +0100936 execute(TC_crcx_and_dlcx_ep_callid_connid());
937 execute(TC_crcx_and_dlcx_ep_callid());
938 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +0100939 execute(TC_crcx_and_dlcx_ep_callid_inval());
940 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +0100941 execute(TC_crcx_and_dlcx_retrans());
Harald Welte33d82162017-12-28 03:21:57 +0100942
943 execute(TC_crcx_dlcx_30ep());
Harald Weltebb7523b2018-03-29 08:52:01 +0200944
945 execute(TC_rtpem_selftest());
946 execute(TC_two_crcx_and_rtp());
Harald Welte00a067f2017-09-13 23:27:17 +0200947 }
948}