blob: 007775c188d5560087ef084b543c72fb9ab6e7d9 [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;
10 import from RTP_Endpoint all;
Harald Weltebb7523b2018-03-29 08:52:01 +020011 import from RTP_Emulation all;
Harald Welte3c6ebb92017-09-16 00:56:57 +080012 import from IPL4asp_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +020013
Philipp Maierbb7a01c2018-02-01 12:32:57 +010014 const charstring c_mgw_domain := "mgw";
15 const charstring c_mgw_ep_rtpbridge := "rtpbridge/";
16
Harald Welte21ba5572017-09-19 17:55:05 +080017 /* any variables declared in the component will be available to
18 * all functions that 'run on' the named component, similar to
19 * class members in C++ */
Harald Welte00a067f2017-09-13 23:27:17 +020020 type component dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080021 port MGCP_CODEC_PT MGCP;
Harald Weltef07c2862017-11-18 17:16:24 +010022 port RTP_CODEC_PT RTP;
Harald Welte3c6ebb92017-09-16 00:56:57 +080023 var boolean initialized := false;
Harald Welte55015362017-11-18 16:02:42 +010024 var ConnectionId g_mgcp_conn_id := -1;
Harald Weltee1e18c52017-09-17 16:23:07 +080025 var integer g_trans_id;
Harald Weltef07c2862017-11-18 17:16:24 +010026
27 var RtpEndpoint g_rtp_ep[2];
Harald Weltebb7523b2018-03-29 08:52:01 +020028
29 var RTP_Emulation_CT vc_RTPEM[2];
30 port RTPEM_CTRL_PT RTPEM[2];
Harald Welte00a067f2017-09-13 23:27:17 +020031 };
32
Harald Weltee1e18c52017-09-17 16:23:07 +080033 function get_next_trans_id() runs on dummy_CT return MgcpTransId {
34 var MgcpTransId tid := int2str(g_trans_id);
35 g_trans_id := g_trans_id + 1;
36 return tid;
37 }
38
Harald Welte21ba5572017-09-19 17:55:05 +080039 /* all parameters declared here can be modified / overridden by
40 * the config file in the [MODULE_PARAMETERS] section. If no
41 * config file is used or the file doesn't specify them, the
42 * default values assigned below are used */
Harald Welte3c6ebb92017-09-16 00:56:57 +080043 modulepar {
44 PortNumber mp_local_udp_port := 2727;
45 charstring mp_local_ip := "127.0.0.1";
46 PortNumber mp_remote_udp_port := 2427;
47 charstring mp_remote_ip := "127.0.0.1";
Harald Weltef07c2862017-11-18 17:16:24 +010048 PortNumber mp_local_rtp_port_base := 10000;
Harald Welte3c6ebb92017-09-16 00:56:57 +080049 }
50
Harald Weltebb7523b2018-03-29 08:52:01 +020051 private function f_rtpem_init(inout RTP_Emulation_CT comp_ref, integer i)
52 runs on dummy_CT {
53 comp_ref := RTP_Emulation_CT.create("RTPEM" & int2str(i));
54 map(comp_ref:RTP, system:RTP);
55 map(comp_ref:RTCP, system:RTCP);
56 comp_ref.start(RTP_Emulation.f_main());
57 }
58
Harald Welte21ba5572017-09-19 17:55:05 +080059 /* initialization function, called by each test case at the
60 * beginning, but 'initialized' variable ensures its body is
61 * only executed once */
Harald Welteedc45c12017-11-18 19:15:05 +010062 private function f_init(template MgcpEndpoint ep := omit) runs on dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080063 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010064 var uint32_t ssrc;
Harald Welteedc45c12017-11-18 19:15:05 +010065 if (initialized == false) {
66 initialized := true;
67
68 /* some random number for the initial transaction id */
69 g_trans_id := float2int(rnd()*65535.0);
70 map(self:MGCP, system:MGCP_CODEC_PT);
71 /* connect the MGCP test port using the given
72 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
73 * */
74 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
75 g_mgcp_conn_id := res.connId;
76
77 map(self:RTP, system:RTP_CODEC_PT);
78 ssrc := float2int(rnd()*4294967296.0);
79 rtp_endpoint_init(g_rtp_ep[0], mp_local_ip, mp_local_rtp_port_base, ssrc);
80 rtp_endpoint_bind(RTP, g_rtp_ep[0]);
81 rtp_endpoint_init(g_rtp_ep[1], mp_local_ip, mp_local_rtp_port_base+2, ssrc);
82 rtp_endpoint_bind(RTP, g_rtp_ep[1]);
Harald Weltebb7523b2018-03-29 08:52:01 +020083
84 for (var integer i := 0; i < sizeof(vc_RTPEM); i := i+1) {
85 f_rtpem_init(vc_RTPEM[i], i);
86 connect(vc_RTPEM[i]:CTRL, self:RTPEM[i]);
87 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080088 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080089
Harald Welteedc45c12017-11-18 19:15:05 +010090 if (isvalue(ep)) {
91 /* do a DLCX on all connections of the EP */
92 f_dlcx_ignore(valueof(ep));
93 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080094 }
95
Harald Welte00a067f2017-09-13 23:27:17 +020096 testcase TC_selftest() runs on dummy_CT {
97 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 +010098 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 +020099 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
100 "I: 1\n" &
101 "\n" &
102 "v=0\r\n" &
103 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
104 "s=-\r\n" &
105 "c=IN IP4 0.0.0.0\r\n" &
106 "t=0 0\r\n" &
107 "m=audio 0 RTP/AVP 126\r\n" &
108 "a=rtpmap:126 AMR/8000\r\n" &
109 "a=ptime:20\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100110 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 +0200111 "M: sendrecv\r" &
112 "C: 2\r\n" &
113 "I: 1\r\n" &
114 "L: p:20, a:AMR, nt:IN\r\n" &
115 "\n" &
116 "v=0\r\n" &
117 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800118 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200119 "c=IN IP4 0.0.0.0\r\n" &
120 "t=0 0\r\n" &
121 "m=audio 4441 RTP/AVP 99\r\n" &
122 "a=rtpmap:99 AMR/8000\r\n" &
123 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800124 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200125
126 log(c_auep);
127 log(dec_MgcpCommand(c_auep));
128
129 log(c_mdcx3);
130 log(dec_MgcpCommand(c_mdcx3));
131
132 log(c_mdcx3_ret);
133 log(dec_MgcpResponse(c_mdcx3_ret));
134
135 log(c_mdcx4);
136 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800137
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100138 log(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H));
139 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 +0800140
141 log(c_crcx510_ret);
142 log(dec_MgcpResponse(c_crcx510_ret));
143 log(dec_MgcpMessage(c_crcx510_ret));
144 }
145
Harald Weltee636afd2017-09-17 16:24:09 +0800146 /* CRCX test ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100147 * x without mandatory CallId
Harald Weltee636afd2017-09-17 16:24:09 +0800148 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
149 * - CRCX with remote session description and without
150 *
151 * general ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100152 * x packetization != 20ms
153 * x invalid mode
Harald Weltee636afd2017-09-17 16:24:09 +0800154 * x unsupported mode (517)
155 * x bidirectional mode before RemoteConnDesc: 527
156 * - invalid codec
Harald Weltee0b331f2017-11-18 20:34:33 +0100157 * x retransmission of same transaction
Harald Weltee636afd2017-09-17 16:24:09 +0800158 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
159 */
160
Harald Welte21ba5572017-09-19 17:55:05 +0800161 /* build a receive template for receiving a MGCP message. You
162 * pass the MGCP response template in, and it will generate an
163 * MGCP_RecvFrom template that can match the primitives arriving on the
164 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800165 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
166 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100167 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800168 remName := mp_remote_ip,
169 remPort := mp_remote_udp_port,
170 locName := mp_local_ip,
171 locPort := mp_local_udp_port,
172 msg := { response := resp }
173 }
174 return mrf;
175 }
176
177 /* Send a MGCP request + receive a (matching!) response */
178 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
179 var MgcpMessage msg := { command := valueof(cmd) };
180 resp.line.trans_id := cmd.line.trans_id;
181 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800182 var MGCP_RecvFrom mrf;
183 timer T := 5.0;
184
Harald Welte55015362017-11-18 16:02:42 +0100185 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800186 T.start;
187 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800188 [] MGCP.receive(mrt) -> value mrf { }
189 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800190 [] MGCP.receive { repeat; }
191 [] T.timeout { setverdict(fail); }
192 }
193 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800194
195 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
196 return mrf.msg.response;
197 } else {
198 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
199 return r;
200 }
Harald Welte00a067f2017-09-13 23:27:17 +0200201 }
202
Harald Welteba62c8c2017-11-18 18:26:49 +0100203 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
204 var integer i;
205 for (i := 0; i < lengthof(resp.params); i := i + 1) {
206 var MgcpParameter par := resp.params[i];
207 if (par.code == "I") {
208 return str2hex(par.val);
209 }
210 }
211 setverdict(fail);
212 return '00000000'H;
213 }
214
Harald Welte10889c12017-11-18 19:40:31 +0100215 function f_dlcx(MgcpEndpoint ep, template MgcpResponseCode ret_code, template charstring ret_val,
216 template MgcpCallId call_id := omit,
217 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welteba62c8c2017-11-18 18:26:49 +0100218 var template MgcpCommand cmd;
219 var MgcpResponse resp;
220 var template MgcpResponse rtmpl := {
221 line := {
Harald Welte10889c12017-11-18 19:40:31 +0100222 code := ret_code,
223 string := ret_val
Harald Welteba62c8c2017-11-18 18:26:49 +0100224 },
225 params := *,
226 sdp := *
227 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100228 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100229 resp := mgcp_transceive_mgw(cmd, rtmpl);
230 }
231
Harald Welte10889c12017-11-18 19:40:31 +0100232 /* Send DLCX and expect OK response */
233 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
234 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Weltef91edf32017-12-28 14:16:21 +0100235 f_dlcx(ep, ("200","250"), "OK", call_id, conn_id);
Harald Welte10889c12017-11-18 19:40:31 +0100236 }
237
Harald Welteba62c8c2017-11-18 18:26:49 +0100238 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100239 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100240 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welte10889c12017-11-18 19:40:31 +0100241 f_dlcx(ep, ?, *, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100242 }
243
Harald Weltebb7523b2018-03-29 08:52:01 +0200244 type record HostPort {
245 charstring hostname,
246 integer portnr optional
247 }
248 type record RtpFlowData {
249 HostPort em, /* emulation side */
250 HostPort mgw, /* mgw side */
251 uint7_t pt,
252 charstring codec,
253 MgcpConnectionId mgcp_conn_id optional
254 }
255
256 function f_flow_create(RTPEM_CTRL_PT pt, MgcpEndpoint ep, inout RtpFlowData flow,
257 boolean one_phase := true)
258 runs on dummy_CT {
259 var MgcpCallId call_id := '1226'H;
260 var template MgcpCommand cmd;
261 var MgcpResponse resp;
262
263 /* bind local RTP emulation socket */
264 f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
265
266 if (one_phase) {
267 /* Connect flow to MGW */
268 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
269 cmd.sdp := ts_SDP(flow.em.hostname, flow.mgw.hostname, "23", "42",
270 flow.em.portnr, { int2str(flow.pt) },
271 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
272 valueof(ts_SDP_ptime(20)) });
273 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
274 flow.mgcp_conn_id := extract_conn_id(resp);
275 /* extract port number from response */
276 flow.mgw.portnr :=
277 resp.sdp.media_list[0].media_field.ports.port_number;
278 } else {
279 /* first create the MGW side RTP socket */
280 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
281 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
282 flow.mgcp_conn_id := extract_conn_id(resp);
283 /* extract MGW-side port number from response */
284 flow.mgw.portnr :=
285 resp.sdp.media_list[0].media_field.ports.port_number;
286
287 /* then connect it to the emulation-side RTP socket using SDP */
288 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, flow.mgcp_conn_id);
289 cmd.sdp := ts_SDP(flow.em.hostname, flow.mgw.hostname, "23", "42",
290 flow.em.portnr, { int2str(flow.pt) },
291 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
292 valueof(ts_SDP_ptime(20)) });
293 resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
294
295 }
296 /* finally, connect the emulation-side RTP socket to the MGW */
297 f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);
298 }
299
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100300 function f_crcx(charstring ep_prefix) runs on dummy_CT {
301 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800302 var template MgcpCommand cmd;
303 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100304 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800305
Harald Welteedc45c12017-11-18 19:15:05 +0100306 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800307
Harald Welteba62c8c2017-11-18 18:26:49 +0100308 /* create the connection on the MGW */
309 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100310 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welteba62c8c2017-11-18 18:26:49 +0100311 extract_conn_id(resp);
312
313 /* clean-up */
314 f_dlcx_ok(ep, call_id);
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100315 }
Harald Welteba62c8c2017-11-18 18:26:49 +0100316
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100317 /* test valid CRCX without SDP */
318 testcase TC_crcx() runs on dummy_CT {
319 f_crcx(c_mgw_ep_rtpbridge);
320 setverdict(pass);
321 }
322
323 /* test valid CRCX without SDP (older method without endpoint prefix) */
324 testcase TC_crcx_noprefix() runs on dummy_CT {
325 f_crcx("");
Harald Weltee636afd2017-09-17 16:24:09 +0800326 setverdict(pass);
327 }
328
329 /* test CRCX with unsupported mode, expect 517 */
330 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
331 var template MgcpCommand cmd;
332 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100333 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100334 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800335 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
336
Harald Welteedc45c12017-11-18 19:15:05 +0100337 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800338
Harald Welteba62c8c2017-11-18 18:26:49 +0100339 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800340 resp := mgcp_transceive_mgw(cmd, rtmpl);
341 setverdict(pass);
342 }
343
Harald Welte21ba5572017-09-19 17:55:05 +0800344 /* test CRCX with early bi-directional mode, expect 527 as
345 * bi-diretional media can only be established once both local and
346 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800347 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
348 var template MgcpCommand cmd;
349 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100350 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100351 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800352 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
353
Harald Welteedc45c12017-11-18 19:15:05 +0100354 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800355
Harald Welteba62c8c2017-11-18 18:26:49 +0100356 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800357 resp := mgcp_transceive_mgw(cmd, rtmpl);
358 setverdict(pass);
359 }
360
361 /* test CRCX with unsupported Parameters */
362 testcase TC_crcx_unsupp_param() runs on dummy_CT {
363 var template MgcpCommand cmd;
364 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100365 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100366 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800367 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
368
Harald Welteedc45c12017-11-18 19:15:05 +0100369 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800370
Harald Welteba62c8c2017-11-18 18:26:49 +0100371 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100372 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
373 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
374
Harald Weltee636afd2017-09-17 16:24:09 +0800375 resp := mgcp_transceive_mgw(cmd, rtmpl);
376 setverdict(pass);
377 }
378
379 /* test CRCX with missing CallId */
380 testcase TC_crcx_missing_callid() runs on dummy_CT {
381 var template MgcpCommand cmd;
382 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100383 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Weltef91edf32017-12-28 14:16:21 +0100384 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","516"));
Harald Weltee636afd2017-09-17 16:24:09 +0800385
Harald Welteedc45c12017-11-18 19:15:05 +0100386 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800387
Harald Welteba62c8c2017-11-18 18:26:49 +0100388 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800389 cmd.params := {
390 t_MgcpParConnMode("recvonly"),
391 t_MgcpParLocConnOpt("p:20")
392 }
393 resp := mgcp_transceive_mgw(cmd, rtmpl);
394 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100395
Harald Weltee636afd2017-09-17 16:24:09 +0800396 }
397
398 /* test CRCX with missing Mode */
399 testcase TC_crcx_missing_mode() runs on dummy_CT {
400 var template MgcpCommand cmd;
401 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100402 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100403 var MgcpCallId call_id := '1229'H;
Harald Weltef91edf32017-12-28 14:16:21 +0100404 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","517"));
Harald Weltee636afd2017-09-17 16:24:09 +0800405
Harald Welteedc45c12017-11-18 19:15:05 +0100406 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800407
Harald Welteba62c8c2017-11-18 18:26:49 +0100408 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800409 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100410 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800411 t_MgcpParLocConnOpt("p:20")
412 }
413 resp := mgcp_transceive_mgw(cmd, rtmpl);
414 setverdict(pass);
415 }
416
417 /* test CRCX with unsupported packetization interval */
418 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
419 var template MgcpCommand cmd;
420 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100421 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100422 var MgcpCallId call_id := '1228'H;
Harald Welte0d198612017-11-18 19:58:31 +0100423 var template MgcpResponse rtmpl := tr_MgcpResp_Err("535");
Harald Weltee636afd2017-09-17 16:24:09 +0800424
Harald Welteedc45c12017-11-18 19:15:05 +0100425 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800426
Harald Welteba62c8c2017-11-18 18:26:49 +0100427 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100428 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800429 resp := mgcp_transceive_mgw(cmd, rtmpl);
430 setverdict(pass);
431 }
432
433 /* test CRCX with illegal double presence of local connection option */
434 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
435 var template MgcpCommand cmd;
436 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100437 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100438 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800439 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
440
Harald Welteedc45c12017-11-18 19:15:05 +0100441 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800442
Harald Welteba62c8c2017-11-18 18:26:49 +0100443 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100444 /* p:20 is permitted only once and not twice! */
445 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800446 resp := mgcp_transceive_mgw(cmd, rtmpl);
447 setverdict(pass);
448 }
449
450 /* test valid CRCX with valid SDP */
451 testcase TC_crcx_sdp() runs on dummy_CT {
452 var template MgcpCommand cmd;
453 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100454 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100455 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800456
Harald Welteedc45c12017-11-18 19:15:05 +0100457 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800458
Harald Welteba62c8c2017-11-18 18:26:49 +0100459 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800460 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
461 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
462 valueof(ts_SDP_ptime(20)) });
Harald Welte9988d282017-11-18 19:22:00 +0100463 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Philipp Maierdffa6a42018-02-02 11:55:44 +0100464
465 /* clean-up */
466 f_dlcx_ok(ep, call_id);
467
Harald Weltee636afd2017-09-17 16:24:09 +0800468 setverdict(pass);
469 }
470
Philipp Maier5e06cee2018-02-01 18:28:08 +0100471 /* test valid wildcarded CRCX */
472 testcase TC_crcx_wildcarded() runs on dummy_CT {
473 var template MgcpCommand cmd;
474 var MgcpResponse resp;
475 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
476 var MgcpCallId call_id := '1234'H;
477 var MgcpEndpoint ep_assigned;
478 f_init();
479
480 /* create the connection on the MGW */
481 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
482 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
483 extract_conn_id(resp);
484
485 /* extract endpoint name we got assigned by the MGW */
486 var MgcpMessage resp_msg := {
487 response := resp
488 }
489 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
490 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
491 }
492
493 /* clean-up */
494 f_dlcx_ok(ep_assigned, call_id);
495
496 setverdict(pass);
497 }
498
499 /* test valid wildcarded CRCX */
500 testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
501 const integer n_endpoints := 32;
502 var integer i;
503 var template MgcpCommand cmd;
504 var MgcpResponse resp;
505 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
506 var MgcpCallId call_id := '1234'H;
507 var MgcpEndpoint ep_assigned[n_endpoints];
508 f_init();
509
510 /* Exhaust all endpoint resources on the virtual trunk */
511 for (i := 0; i < n_endpoints; i := i+1) {
512 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
513 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
514
515 /* Make sure we got a connection id */
516 extract_conn_id(resp);
517
518 var MgcpMessage resp_msg := {
519 response := resp
520 }
521 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
522 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
523 }
524 }
525
526 /* Try to allocate one more endpoint, which should fail */
527 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
528 var template MgcpResponse rtmpl := tr_MgcpResp_Err("403");
529 resp := mgcp_transceive_mgw(cmd, rtmpl);
530 setverdict(pass);
531
532 /* clean-up */
533 for (i := 0; i < n_endpoints; i := i+1) {
534 f_dlcx_ok(ep_assigned[i], call_id);
535 }
536 setverdict(pass);
537 }
538
Harald Weltee636afd2017-09-17 16:24:09 +0800539 /* TODO: various SDP related bits */
540
541
542 /* TODO: CRCX with X-Osmux */
543 /* TODO: double CRCX without force_realloc */
544
545 /* TODO: MDCX (various) */
546
547 /* TODO: MDCX without CRCX first */
548 testcase TC_mdcx_without_crcx() runs on dummy_CT {
549 var template MgcpCommand cmd;
550 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100551 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "3@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100552 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800553 var template MgcpResponse rtmpl := {
554 line := {
555 /* TODO: accept/enforce better error? */
556 code := "400",
557 string := ?
558 },
559 params:= { },
560 sdp := omit
561 };
562
Harald Welteedc45c12017-11-18 19:15:05 +0100563 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800564
Harald Welte2bcfd3a2017-11-18 22:14:35 +0100565 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800566 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
567 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
568 valueof(ts_SDP_ptime(20)) });
569 resp := mgcp_transceive_mgw(cmd, rtmpl);
570 setverdict(pass);
571 }
572
573 /* DLCX without CRCX first */
574 testcase TC_dlcx_without_crcx() runs on dummy_CT {
575 var template MgcpCommand cmd;
576 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100577 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800578 var template MgcpResponse rtmpl := {
579 line := {
Harald Weltef91edf32017-12-28 14:16:21 +0100580 code := ("400", "515"),
Harald Weltee636afd2017-09-17 16:24:09 +0800581 string := ?
582 },
583 params:= { },
584 sdp := omit
585 };
586
Harald Welteedc45c12017-11-18 19:15:05 +0100587 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800588
Harald Welteedc45c12017-11-18 19:15:05 +0100589 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800590 resp := mgcp_transceive_mgw(cmd, rtmpl);
591 setverdict(pass);
592 }
593
Philipp Maier8a3dc922018-02-02 14:55:12 +0100594 /* test valid wildcarded MDCX */
595 testcase TC_mdcx_wildcarded() runs on dummy_CT {
596 /* Note: A wildcarded MDCX is not allowed, so we expect the
597 * MGW to reject this request */
598 var template MgcpCommand cmd;
599 var MgcpResponse resp;
600 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
601 var MgcpCallId call_id := '1225'H;
602 var template MgcpResponse rtmpl := {
603 line := {
604 /* TODO: accept/enforce better error? */
605 code := "507",
606 string := ?
607 },
608 params:= { },
609 sdp := omit
610 };
611
612 f_init(ep);
613
614 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
615 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
616 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
617 valueof(ts_SDP_ptime(20)) });
618 resp := mgcp_transceive_mgw(cmd, rtmpl);
619 setverdict(pass);
620 }
621
622 /* test valid wildcarded DLCX */
623 testcase TC_dlcx_wildcarded() runs on dummy_CT {
624 /* Note: A wildcarded DLCX is specified, but our MGW does not
625 * support this feature so we expect the MGW to reject the
626 * request */
627 var template MgcpCommand cmd;
628 var MgcpResponse resp;
629 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
630 var template MgcpResponse rtmpl := {
631 line := {
632 code := "507",
633 string := ?
634 },
635 params:= { },
636 sdp := omit
637 };
638
639 f_init(ep);
640
641 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
642 resp := mgcp_transceive_mgw(cmd, rtmpl);
643 setverdict(pass);
644 }
645
Harald Welte79181ff2017-11-18 19:26:11 +0100646 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
647 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
648 var template MgcpCommand cmd;
649 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100650 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte79181ff2017-11-18 19:26:11 +0100651 var MgcpCallId call_id := '51234'H;
652
653 f_init(ep);
654
655 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
656 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
657
658 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
659
660 setverdict(pass);
661 }
662
Harald Welte646ecdb2017-12-28 03:21:57 +0100663 function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
664 var template MgcpCommand cmd;
665 var MgcpResponse resp;
666
667 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
668 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
669
670 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
671
672 setverdict(pass);
673 }
674
675 testcase TC_crcx_dlcx_30ep() runs on dummy_CT {
676 var MgcpEndpoint ep;
677 var MgcpCallId call_id;
678 var integer ep_nr;
679
680 f_init();
681
682 for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100683 ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
Harald Welte646ecdb2017-12-28 03:21:57 +0100684 call_id := int2hex(ep_nr, 2) & '1234'H;
685 f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
686 }
687 }
688
Harald Welte79181ff2017-11-18 19:26:11 +0100689 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
690 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800691 var template MgcpCommand cmd;
692 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100693 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100694 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800695
Harald Welteedc45c12017-11-18 19:15:05 +0100696 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800697
Harald Welteba62c8c2017-11-18 18:26:49 +0100698 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100699 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800700
Harald Welteba62c8c2017-11-18 18:26:49 +0100701 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800702
703 setverdict(pass);
704 }
705
Harald Welte79181ff2017-11-18 19:26:11 +0100706 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
707 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
708 var template MgcpCommand cmd;
709 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100710 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100711 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100712
713 f_init(ep);
714
715 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
716 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
717
718 f_dlcx_ok(ep);
719
720 setverdict(pass);
721 }
722
723
Harald Welte6d167f82017-11-18 19:41:35 +0100724 /* CRCX + DLCX of valid endpoint but invalid call-id */
725 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
726 var template MgcpCommand cmd;
727 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100728 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100729 var MgcpCallId call_id := '51231'H;
730
731 f_init(ep);
732
733 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
734 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
735
736 f_dlcx(ep, "516", *, 'ffff'H);
737
738 setverdict(pass);
739 }
740
741
742 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
743 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
744 var template MgcpCommand cmd;
745 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100746 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100747 var MgcpCallId call_id := '51230'H;
748
749 f_init(ep);
750
751 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
752 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
753
754 f_dlcx(ep, "515", *, call_id, 'ffff'H);
755
756 setverdict(pass);
757 }
758
759
Harald Weltee636afd2017-09-17 16:24:09 +0800760 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100761 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
762 var template MgcpCommand cmd;
763 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100764 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Weltef53f1642017-11-18 19:57:11 +0100765 var MgcpCallId call_id := '51229'H;
766 var template MgcpResponse rtmpl := {
767 line := {
768 code := "200",
769 string := "OK"
770 },
771 params:= { },
772 sdp := omit
773 };
774
775 f_init(ep);
776
777 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
778 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
779
780 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
781 resp := mgcp_transceive_mgw(cmd, rtmpl);
782 resp := mgcp_transceive_mgw(cmd, rtmpl);
783
784 setverdict(pass);
785 }
786
Harald Weltebb7523b2018-03-29 08:52:01 +0200787 template (value) RtpFlowData t_RtpFlow(charstring host_a, charstring host_b, uint7_t pt,
788 charstring codec) := {
789 em := {
790 hostname := host_a,
791 portnr := omit
792 },
793 mgw := {
794 hostname := host_b,
795 portnr := omit
796 },
797 pt := pt,
798 codec := codec
799 }
Harald Weltef53f1642017-11-18 19:57:11 +0100800
Harald Weltebb7523b2018-03-29 08:52:01 +0200801 /* transmit RTP streams between two RTP Emulations back-to-back; expect no loss */
802 testcase TC_rtpem_selftest() runs on dummy_CT {
803 var RtpemStats stats[2];
804 var integer local_port := 10000;
805 var integer local_port2 := 20000;
806
807 f_init();
808
809 f_rtpem_bind(RTPEM[0], "127.0.0.1", local_port);
810 f_rtpem_bind(RTPEM[1], "127.0.0.2", local_port2);
811
812 f_rtpem_connect(RTPEM[0], "127.0.0.2", local_port2);
813 f_rtpem_connect(RTPEM[1], "127.0.0.1", local_port);
814
815 log("=== starting");
816 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
817 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
818
819 f_sleep(5.0);
820
821 log("=== stopping");
822 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
823 f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
824 f_sleep(0.5);
825 f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
826 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
827
828 stats[0] := f_rtpem_stats_get(RTPEM[0]);
829 stats[1] := f_rtpem_stats_get(RTPEM[1]);
830 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
831 setverdict(fail, "RTP endpoint statistics don't match");
832 }
833 setverdict(pass);
834 }
835
836 /* create two local RTP emulations; create two connections on MGW EP, exchange some data */
837 testcase TC_two_crcx_and_rtp() runs on dummy_CT {
838 var RtpFlowData flow[2];
839 var RtpemStats stats[2];
840 var template MgcpCommand cmd;
841 var MgcpResponse resp;
842 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
843 var MgcpCallId call_id := '1226'H;
844
845 f_init(ep);
846
847 /* from us to MGW */
848 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
849 /* bind local RTP emulation sockets */
850 flow[0].em.portnr := 10000;
851 f_flow_create(RTPEM[0], ep, flow[0]);
852
853 /* from MGW back to us */
854 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
855 flow[1].em.portnr := 20000;
856 f_flow_create(RTPEM[1], ep, flow[1]);
857
858 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
859 f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
860
861 f_sleep(1.0);
862
863 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
864 f_sleep(0.1);
865
866 stats[0] := f_rtpem_stats_get(RTPEM[0]);
867 stats[1] := f_rtpem_stats_get(RTPEM[1]);
868 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
869 setverdict(fail, "RTP endpoint statistics don't match");
870 }
871
872 f_dlcx_ok(ep, call_id);
873 setverdict(pass);
874
875 }
Harald Weltef53f1642017-11-18 19:57:11 +0100876
Harald Weltee636afd2017-09-17 16:24:09 +0800877 /* TODO: Double-DLCX (no retransmission) */
878
879
880
881 /* TODO: AUEP (various) */
882 /* TODO: RSIP (various) */
883 /* TODO: RQNT (various) */
884 /* TODO: EPCF (various) */
885 /* TODO: AUCX (various) */
886 /* TODO: invalid verb (various) */
887
Harald Welte00a067f2017-09-13 23:27:17 +0200888 control {
889 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800890 execute(TC_crcx());
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100891 execute(TC_crcx_noprefix());
Harald Weltee636afd2017-09-17 16:24:09 +0800892 execute(TC_crcx_unsupp_mode());
893 execute(TC_crcx_early_bidir_mode());
894 execute(TC_crcx_unsupp_param());
895 execute(TC_crcx_missing_callid());
896 execute(TC_crcx_missing_mode());
897 execute(TC_crcx_unsupp_packet_intv());
898 execute(TC_crcx_illegal_double_lco());
899 execute(TC_crcx_sdp());
Philipp Maier5e06cee2018-02-01 18:28:08 +0100900 execute(TC_crcx_wildcarded());
901 execute(TC_crcx_wildcarded_exhaust());
Harald Weltee636afd2017-09-17 16:24:09 +0800902 execute(TC_mdcx_without_crcx());
903 execute(TC_dlcx_without_crcx());
Philipp Maier8a3dc922018-02-02 14:55:12 +0100904 execute(TC_mdcx_wildcarded());
905 execute(TC_dlcx_wildcarded());
Harald Welte79181ff2017-11-18 19:26:11 +0100906 execute(TC_crcx_and_dlcx_ep_callid_connid());
907 execute(TC_crcx_and_dlcx_ep_callid());
908 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +0100909 execute(TC_crcx_and_dlcx_ep_callid_inval());
910 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +0100911 execute(TC_crcx_and_dlcx_retrans());
Harald Welte33d82162017-12-28 03:21:57 +0100912
913 execute(TC_crcx_dlcx_30ep());
Harald Weltebb7523b2018-03-29 08:52:01 +0200914
915 execute(TC_rtpem_selftest());
916 execute(TC_two_crcx_and_rtp());
Harald Welte00a067f2017-09-13 23:27:17 +0200917 }
918}