blob: c1ff3fc92676b69fa48c46072878a9eb171fb5a0 [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 := {} });
71 g_mgcp_conn_id := res.connId;
72
Harald Weltebb7523b2018-03-29 08:52:01 +020073 for (var integer i := 0; i < sizeof(vc_RTPEM); i := i+1) {
74 f_rtpem_init(vc_RTPEM[i], i);
75 connect(vc_RTPEM[i]:CTRL, self:RTPEM[i]);
76 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080077 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080078
Harald Welteedc45c12017-11-18 19:15:05 +010079 if (isvalue(ep)) {
80 /* do a DLCX on all connections of the EP */
81 f_dlcx_ignore(valueof(ep));
82 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080083 }
84
Harald Welte00a067f2017-09-13 23:27:17 +020085 testcase TC_selftest() runs on dummy_CT {
86 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 +010087 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 +020088 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
89 "I: 1\n" &
90 "\n" &
91 "v=0\r\n" &
92 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
93 "s=-\r\n" &
94 "c=IN IP4 0.0.0.0\r\n" &
95 "t=0 0\r\n" &
96 "m=audio 0 RTP/AVP 126\r\n" &
97 "a=rtpmap:126 AMR/8000\r\n" &
98 "a=ptime:20\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +010099 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 +0200100 "M: sendrecv\r" &
101 "C: 2\r\n" &
102 "I: 1\r\n" &
103 "L: p:20, a:AMR, nt:IN\r\n" &
104 "\n" &
105 "v=0\r\n" &
106 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800107 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200108 "c=IN IP4 0.0.0.0\r\n" &
109 "t=0 0\r\n" &
110 "m=audio 4441 RTP/AVP 99\r\n" &
111 "a=rtpmap:99 AMR/8000\r\n" &
112 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800113 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200114
115 log(c_auep);
116 log(dec_MgcpCommand(c_auep));
117
118 log(c_mdcx3);
119 log(dec_MgcpCommand(c_mdcx3));
120
121 log(c_mdcx3_ret);
122 log(dec_MgcpResponse(c_mdcx3_ret));
123
124 log(c_mdcx4);
125 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800126
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100127 log(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H));
128 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 +0800129
130 log(c_crcx510_ret);
131 log(dec_MgcpResponse(c_crcx510_ret));
132 log(dec_MgcpMessage(c_crcx510_ret));
133 }
134
Harald Weltee636afd2017-09-17 16:24:09 +0800135 /* CRCX test ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100136 * x without mandatory CallId
Harald Weltee636afd2017-09-17 16:24:09 +0800137 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
138 * - CRCX with remote session description and without
139 *
140 * general ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100141 * x packetization != 20ms
142 * x invalid mode
Harald Weltee636afd2017-09-17 16:24:09 +0800143 * x unsupported mode (517)
144 * x bidirectional mode before RemoteConnDesc: 527
145 * - invalid codec
Harald Weltee0b331f2017-11-18 20:34:33 +0100146 * x retransmission of same transaction
Harald Weltee636afd2017-09-17 16:24:09 +0800147 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
148 */
149
Harald Welte21ba5572017-09-19 17:55:05 +0800150 /* build a receive template for receiving a MGCP message. You
151 * pass the MGCP response template in, and it will generate an
152 * MGCP_RecvFrom template that can match the primitives arriving on the
153 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800154 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
155 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100156 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800157 remName := mp_remote_ip,
158 remPort := mp_remote_udp_port,
159 locName := mp_local_ip,
160 locPort := mp_local_udp_port,
161 msg := { response := resp }
162 }
163 return mrf;
164 }
165
166 /* Send a MGCP request + receive a (matching!) response */
167 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
168 var MgcpMessage msg := { command := valueof(cmd) };
169 resp.line.trans_id := cmd.line.trans_id;
170 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800171 var MGCP_RecvFrom mrf;
172 timer T := 5.0;
173
Harald Welte55015362017-11-18 16:02:42 +0100174 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800175 T.start;
176 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800177 [] MGCP.receive(mrt) -> value mrf { }
178 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800179 [] MGCP.receive { repeat; }
180 [] T.timeout { setverdict(fail); }
181 }
182 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800183
184 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
185 return mrf.msg.response;
186 } else {
187 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
188 return r;
189 }
Harald Welte00a067f2017-09-13 23:27:17 +0200190 }
191
Harald Welteba62c8c2017-11-18 18:26:49 +0100192 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
193 var integer i;
194 for (i := 0; i < lengthof(resp.params); i := i + 1) {
195 var MgcpParameter par := resp.params[i];
196 if (par.code == "I") {
197 return str2hex(par.val);
198 }
199 }
200 setverdict(fail);
201 return '00000000'H;
202 }
203
Harald Welte10889c12017-11-18 19:40:31 +0100204 function f_dlcx(MgcpEndpoint ep, template MgcpResponseCode ret_code, template charstring ret_val,
205 template MgcpCallId call_id := omit,
206 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welteba62c8c2017-11-18 18:26:49 +0100207 var template MgcpCommand cmd;
208 var MgcpResponse resp;
209 var template MgcpResponse rtmpl := {
210 line := {
Harald Welte10889c12017-11-18 19:40:31 +0100211 code := ret_code,
212 string := ret_val
Harald Welteba62c8c2017-11-18 18:26:49 +0100213 },
214 params := *,
215 sdp := *
216 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100217 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100218 resp := mgcp_transceive_mgw(cmd, rtmpl);
219 }
220
Harald Welte10889c12017-11-18 19:40:31 +0100221 /* Send DLCX and expect OK response */
222 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
223 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Weltef91edf32017-12-28 14:16:21 +0100224 f_dlcx(ep, ("200","250"), "OK", call_id, conn_id);
Harald Welte10889c12017-11-18 19:40:31 +0100225 }
226
Harald Welteba62c8c2017-11-18 18:26:49 +0100227 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100228 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100229 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welte10889c12017-11-18 19:40:31 +0100230 f_dlcx(ep, ?, *, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100231 }
232
Harald Weltebb7523b2018-03-29 08:52:01 +0200233 type record HostPort {
234 charstring hostname,
235 integer portnr optional
236 }
237 type record RtpFlowData {
238 HostPort em, /* emulation side */
239 HostPort mgw, /* mgw side */
240 uint7_t pt,
241 charstring codec,
242 MgcpConnectionId mgcp_conn_id optional
243 }
244
245 function f_flow_create(RTPEM_CTRL_PT pt, MgcpEndpoint ep, inout RtpFlowData flow,
246 boolean one_phase := true)
247 runs on dummy_CT {
248 var MgcpCallId call_id := '1226'H;
249 var template MgcpCommand cmd;
250 var MgcpResponse resp;
251
252 /* bind local RTP emulation socket */
253 f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
254
255 if (one_phase) {
256 /* Connect flow to MGW */
257 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Welteedc88742018-03-29 18:01:16 +0200258 cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
Harald Weltebb7523b2018-03-29 08:52:01 +0200259 flow.em.portnr, { int2str(flow.pt) },
260 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
261 valueof(ts_SDP_ptime(20)) });
262 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
263 flow.mgcp_conn_id := extract_conn_id(resp);
264 /* extract port number from response */
265 flow.mgw.portnr :=
266 resp.sdp.media_list[0].media_field.ports.port_number;
267 } else {
268 /* first create the MGW side RTP socket */
269 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
270 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
271 flow.mgcp_conn_id := extract_conn_id(resp);
272 /* extract MGW-side port number from response */
273 flow.mgw.portnr :=
274 resp.sdp.media_list[0].media_field.ports.port_number;
275
276 /* then connect it to the emulation-side RTP socket using SDP */
277 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, flow.mgcp_conn_id);
Harald Welteedc88742018-03-29 18:01:16 +0200278 cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
Harald Weltebb7523b2018-03-29 08:52:01 +0200279 flow.em.portnr, { int2str(flow.pt) },
280 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
281 valueof(ts_SDP_ptime(20)) });
282 resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
283
284 }
285 /* finally, connect the emulation-side RTP socket to the MGW */
286 f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);
287 }
288
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100289 function f_crcx(charstring ep_prefix) runs on dummy_CT {
290 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800291 var template MgcpCommand cmd;
292 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100293 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800294
Harald Welteedc45c12017-11-18 19:15:05 +0100295 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800296
Harald Welteba62c8c2017-11-18 18:26:49 +0100297 /* create the connection on the MGW */
298 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100299 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welteba62c8c2017-11-18 18:26:49 +0100300 extract_conn_id(resp);
301
302 /* clean-up */
303 f_dlcx_ok(ep, call_id);
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100304 }
Harald Welteba62c8c2017-11-18 18:26:49 +0100305
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100306 /* test valid CRCX without SDP */
307 testcase TC_crcx() runs on dummy_CT {
308 f_crcx(c_mgw_ep_rtpbridge);
309 setverdict(pass);
310 }
311
312 /* test valid CRCX without SDP (older method without endpoint prefix) */
313 testcase TC_crcx_noprefix() runs on dummy_CT {
314 f_crcx("");
Harald Weltee636afd2017-09-17 16:24:09 +0800315 setverdict(pass);
316 }
317
318 /* test CRCX with unsupported mode, expect 517 */
319 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
320 var template MgcpCommand cmd;
321 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100322 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100323 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800324 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
325
Harald Welteedc45c12017-11-18 19:15:05 +0100326 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800327
Harald Welteba62c8c2017-11-18 18:26:49 +0100328 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800329 resp := mgcp_transceive_mgw(cmd, rtmpl);
330 setverdict(pass);
331 }
332
Harald Welte21ba5572017-09-19 17:55:05 +0800333 /* test CRCX with early bi-directional mode, expect 527 as
334 * bi-diretional media can only be established once both local and
335 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800336 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
337 var template MgcpCommand cmd;
338 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100339 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100340 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800341 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
342
Harald Welteedc45c12017-11-18 19:15:05 +0100343 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800344
Harald Welteba62c8c2017-11-18 18:26:49 +0100345 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800346 resp := mgcp_transceive_mgw(cmd, rtmpl);
347 setverdict(pass);
348 }
349
350 /* test CRCX with unsupported Parameters */
351 testcase TC_crcx_unsupp_param() runs on dummy_CT {
352 var template MgcpCommand cmd;
353 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100354 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100355 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800356 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
357
Harald Welteedc45c12017-11-18 19:15:05 +0100358 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800359
Harald Welteba62c8c2017-11-18 18:26:49 +0100360 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100361 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
362 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
363
Harald Weltee636afd2017-09-17 16:24:09 +0800364 resp := mgcp_transceive_mgw(cmd, rtmpl);
365 setverdict(pass);
366 }
367
368 /* test CRCX with missing CallId */
369 testcase TC_crcx_missing_callid() runs on dummy_CT {
370 var template MgcpCommand cmd;
371 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100372 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Weltef91edf32017-12-28 14:16:21 +0100373 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","516"));
Harald Weltee636afd2017-09-17 16:24:09 +0800374
Harald Welteedc45c12017-11-18 19:15:05 +0100375 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800376
Harald Welteba62c8c2017-11-18 18:26:49 +0100377 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800378 cmd.params := {
379 t_MgcpParConnMode("recvonly"),
380 t_MgcpParLocConnOpt("p:20")
381 }
382 resp := mgcp_transceive_mgw(cmd, rtmpl);
383 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100384
Harald Weltee636afd2017-09-17 16:24:09 +0800385 }
386
387 /* test CRCX with missing Mode */
388 testcase TC_crcx_missing_mode() runs on dummy_CT {
389 var template MgcpCommand cmd;
390 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100391 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100392 var MgcpCallId call_id := '1229'H;
Harald Weltef91edf32017-12-28 14:16:21 +0100393 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","517"));
Harald Weltee636afd2017-09-17 16:24:09 +0800394
Harald Welteedc45c12017-11-18 19:15:05 +0100395 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800396
Harald Welteba62c8c2017-11-18 18:26:49 +0100397 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800398 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100399 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800400 t_MgcpParLocConnOpt("p:20")
401 }
402 resp := mgcp_transceive_mgw(cmd, rtmpl);
403 setverdict(pass);
404 }
405
406 /* test CRCX with unsupported packetization interval */
407 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
408 var template MgcpCommand cmd;
409 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100410 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100411 var MgcpCallId call_id := '1228'H;
Harald Welte0d198612017-11-18 19:58:31 +0100412 var template MgcpResponse rtmpl := tr_MgcpResp_Err("535");
Harald Weltee636afd2017-09-17 16:24:09 +0800413
Harald Welteedc45c12017-11-18 19:15:05 +0100414 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800415
Harald Welteba62c8c2017-11-18 18:26:49 +0100416 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100417 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800418 resp := mgcp_transceive_mgw(cmd, rtmpl);
419 setverdict(pass);
420 }
421
422 /* test CRCX with illegal double presence of local connection option */
423 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
424 var template MgcpCommand cmd;
425 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100426 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100427 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800428 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
429
Harald Welteedc45c12017-11-18 19:15:05 +0100430 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800431
Harald Welteba62c8c2017-11-18 18:26:49 +0100432 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100433 /* p:20 is permitted only once and not twice! */
434 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800435 resp := mgcp_transceive_mgw(cmd, rtmpl);
436 setverdict(pass);
437 }
438
439 /* test valid CRCX with valid SDP */
440 testcase TC_crcx_sdp() runs on dummy_CT {
441 var template MgcpCommand cmd;
442 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100443 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100444 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800445
Harald Welteedc45c12017-11-18 19:15:05 +0100446 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800447
Harald Welteba62c8c2017-11-18 18:26:49 +0100448 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800449 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
450 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
451 valueof(ts_SDP_ptime(20)) });
Harald Welte9988d282017-11-18 19:22:00 +0100452 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Philipp Maierdffa6a42018-02-02 11:55:44 +0100453
454 /* clean-up */
455 f_dlcx_ok(ep, call_id);
456
Harald Weltee636afd2017-09-17 16:24:09 +0800457 setverdict(pass);
458 }
459
Philipp Maier5e06cee2018-02-01 18:28:08 +0100460 /* test valid wildcarded CRCX */
461 testcase TC_crcx_wildcarded() runs on dummy_CT {
462 var template MgcpCommand cmd;
463 var MgcpResponse resp;
464 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
465 var MgcpCallId call_id := '1234'H;
466 var MgcpEndpoint ep_assigned;
467 f_init();
468
469 /* create the connection on the MGW */
470 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
471 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
472 extract_conn_id(resp);
473
474 /* extract endpoint name we got assigned by the MGW */
475 var MgcpMessage resp_msg := {
476 response := resp
477 }
478 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
479 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
480 }
481
482 /* clean-up */
483 f_dlcx_ok(ep_assigned, call_id);
484
485 setverdict(pass);
486 }
487
488 /* test valid wildcarded CRCX */
489 testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
490 const integer n_endpoints := 32;
491 var integer i;
492 var template MgcpCommand cmd;
493 var MgcpResponse resp;
494 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
495 var MgcpCallId call_id := '1234'H;
496 var MgcpEndpoint ep_assigned[n_endpoints];
497 f_init();
498
499 /* Exhaust all endpoint resources on the virtual trunk */
500 for (i := 0; i < n_endpoints; i := i+1) {
501 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
502 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
503
504 /* Make sure we got a connection id */
505 extract_conn_id(resp);
506
507 var MgcpMessage resp_msg := {
508 response := resp
509 }
510 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
511 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
512 }
513 }
514
515 /* Try to allocate one more endpoint, which should fail */
516 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
517 var template MgcpResponse rtmpl := tr_MgcpResp_Err("403");
518 resp := mgcp_transceive_mgw(cmd, rtmpl);
519 setverdict(pass);
520
521 /* clean-up */
522 for (i := 0; i < n_endpoints; i := i+1) {
523 f_dlcx_ok(ep_assigned[i], call_id);
524 }
525 setverdict(pass);
526 }
527
Harald Weltee636afd2017-09-17 16:24:09 +0800528 /* TODO: various SDP related bits */
529
530
531 /* TODO: CRCX with X-Osmux */
532 /* TODO: double CRCX without force_realloc */
533
534 /* TODO: MDCX (various) */
535
536 /* TODO: MDCX without CRCX first */
537 testcase TC_mdcx_without_crcx() runs on dummy_CT {
538 var template MgcpCommand cmd;
539 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100540 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "3@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100541 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800542 var template MgcpResponse rtmpl := {
543 line := {
544 /* TODO: accept/enforce better error? */
545 code := "400",
546 string := ?
547 },
548 params:= { },
549 sdp := omit
550 };
551
Harald Welteedc45c12017-11-18 19:15:05 +0100552 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800553
Harald Welte2bcfd3a2017-11-18 22:14:35 +0100554 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800555 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
556 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
557 valueof(ts_SDP_ptime(20)) });
558 resp := mgcp_transceive_mgw(cmd, rtmpl);
559 setverdict(pass);
560 }
561
562 /* DLCX without CRCX first */
563 testcase TC_dlcx_without_crcx() runs on dummy_CT {
564 var template MgcpCommand cmd;
565 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100566 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800567 var template MgcpResponse rtmpl := {
568 line := {
Harald Weltef91edf32017-12-28 14:16:21 +0100569 code := ("400", "515"),
Harald Weltee636afd2017-09-17 16:24:09 +0800570 string := ?
571 },
572 params:= { },
573 sdp := omit
574 };
575
Harald Welteedc45c12017-11-18 19:15:05 +0100576 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800577
Harald Welteedc45c12017-11-18 19:15:05 +0100578 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800579 resp := mgcp_transceive_mgw(cmd, rtmpl);
580 setverdict(pass);
581 }
582
Philipp Maier8a3dc922018-02-02 14:55:12 +0100583 /* test valid wildcarded MDCX */
584 testcase TC_mdcx_wildcarded() runs on dummy_CT {
585 /* Note: A wildcarded MDCX is not allowed, so we expect the
586 * MGW to reject this request */
587 var template MgcpCommand cmd;
588 var MgcpResponse resp;
589 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
590 var MgcpCallId call_id := '1225'H;
591 var template MgcpResponse rtmpl := {
592 line := {
593 /* TODO: accept/enforce better error? */
594 code := "507",
595 string := ?
596 },
597 params:= { },
598 sdp := omit
599 };
600
601 f_init(ep);
602
603 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
604 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
605 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
606 valueof(ts_SDP_ptime(20)) });
607 resp := mgcp_transceive_mgw(cmd, rtmpl);
608 setverdict(pass);
609 }
610
611 /* test valid wildcarded DLCX */
612 testcase TC_dlcx_wildcarded() runs on dummy_CT {
613 /* Note: A wildcarded DLCX is specified, but our MGW does not
614 * support this feature so we expect the MGW to reject the
615 * request */
616 var template MgcpCommand cmd;
617 var MgcpResponse resp;
618 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
619 var template MgcpResponse rtmpl := {
620 line := {
621 code := "507",
622 string := ?
623 },
624 params:= { },
625 sdp := omit
626 };
627
628 f_init(ep);
629
630 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
631 resp := mgcp_transceive_mgw(cmd, rtmpl);
632 setverdict(pass);
633 }
634
Harald Welte79181ff2017-11-18 19:26:11 +0100635 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
636 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
637 var template MgcpCommand cmd;
638 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100639 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte79181ff2017-11-18 19:26:11 +0100640 var MgcpCallId call_id := '51234'H;
641
642 f_init(ep);
643
644 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
645 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
646
647 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
648
649 setverdict(pass);
650 }
651
Harald Welte646ecdb2017-12-28 03:21:57 +0100652 function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
653 var template MgcpCommand cmd;
654 var MgcpResponse resp;
655
656 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
657 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
658
659 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
660
661 setverdict(pass);
662 }
663
664 testcase TC_crcx_dlcx_30ep() runs on dummy_CT {
665 var MgcpEndpoint ep;
666 var MgcpCallId call_id;
667 var integer ep_nr;
668
669 f_init();
670
671 for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100672 ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
Harald Welte646ecdb2017-12-28 03:21:57 +0100673 call_id := int2hex(ep_nr, 2) & '1234'H;
674 f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
675 }
676 }
677
Harald Welte79181ff2017-11-18 19:26:11 +0100678 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
679 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800680 var template MgcpCommand cmd;
681 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100682 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100683 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800684
Harald Welteedc45c12017-11-18 19:15:05 +0100685 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800686
Harald Welteba62c8c2017-11-18 18:26:49 +0100687 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100688 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800689
Harald Welteba62c8c2017-11-18 18:26:49 +0100690 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800691
692 setverdict(pass);
693 }
694
Harald Welte79181ff2017-11-18 19:26:11 +0100695 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
696 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
697 var template MgcpCommand cmd;
698 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100699 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100700 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100701
702 f_init(ep);
703
704 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
705 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
706
707 f_dlcx_ok(ep);
708
709 setverdict(pass);
710 }
711
712
Harald Welte6d167f82017-11-18 19:41:35 +0100713 /* CRCX + DLCX of valid endpoint but invalid call-id */
714 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
715 var template MgcpCommand cmd;
716 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100717 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100718 var MgcpCallId call_id := '51231'H;
719
720 f_init(ep);
721
722 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
723 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
724
725 f_dlcx(ep, "516", *, 'ffff'H);
726
727 setverdict(pass);
728 }
729
730
731 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
732 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
733 var template MgcpCommand cmd;
734 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100735 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100736 var MgcpCallId call_id := '51230'H;
737
738 f_init(ep);
739
740 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
741 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
742
743 f_dlcx(ep, "515", *, call_id, 'ffff'H);
744
745 setverdict(pass);
746 }
747
748
Harald Weltee636afd2017-09-17 16:24:09 +0800749 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100750 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
751 var template MgcpCommand cmd;
752 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100753 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Weltef53f1642017-11-18 19:57:11 +0100754 var MgcpCallId call_id := '51229'H;
755 var template MgcpResponse rtmpl := {
756 line := {
757 code := "200",
758 string := "OK"
759 },
760 params:= { },
761 sdp := omit
762 };
763
764 f_init(ep);
765
766 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
767 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
768
769 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
770 resp := mgcp_transceive_mgw(cmd, rtmpl);
771 resp := mgcp_transceive_mgw(cmd, rtmpl);
772
773 setverdict(pass);
774 }
775
Harald Weltebb7523b2018-03-29 08:52:01 +0200776 template (value) RtpFlowData t_RtpFlow(charstring host_a, charstring host_b, uint7_t pt,
777 charstring codec) := {
778 em := {
779 hostname := host_a,
780 portnr := omit
781 },
782 mgw := {
783 hostname := host_b,
784 portnr := omit
785 },
786 pt := pt,
787 codec := codec
788 }
Harald Weltef53f1642017-11-18 19:57:11 +0100789
Harald Weltebb7523b2018-03-29 08:52:01 +0200790 /* transmit RTP streams between two RTP Emulations back-to-back; expect no loss */
791 testcase TC_rtpem_selftest() runs on dummy_CT {
792 var RtpemStats stats[2];
793 var integer local_port := 10000;
794 var integer local_port2 := 20000;
795
796 f_init();
797
798 f_rtpem_bind(RTPEM[0], "127.0.0.1", local_port);
799 f_rtpem_bind(RTPEM[1], "127.0.0.2", local_port2);
800
801 f_rtpem_connect(RTPEM[0], "127.0.0.2", local_port2);
802 f_rtpem_connect(RTPEM[1], "127.0.0.1", local_port);
803
804 log("=== starting");
805 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
806 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
807
808 f_sleep(5.0);
809
810 log("=== stopping");
811 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
812 f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
813 f_sleep(0.5);
814 f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
815 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
816
817 stats[0] := f_rtpem_stats_get(RTPEM[0]);
818 stats[1] := f_rtpem_stats_get(RTPEM[1]);
819 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
820 setverdict(fail, "RTP endpoint statistics don't match");
821 }
822 setverdict(pass);
823 }
824
825 /* create two local RTP emulations; create two connections on MGW EP, exchange some data */
826 testcase TC_two_crcx_and_rtp() runs on dummy_CT {
827 var RtpFlowData flow[2];
828 var RtpemStats stats[2];
829 var template MgcpCommand cmd;
830 var MgcpResponse resp;
831 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
832 var MgcpCallId call_id := '1226'H;
833
834 f_init(ep);
835
836 /* from us to MGW */
837 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
838 /* bind local RTP emulation sockets */
839 flow[0].em.portnr := 10000;
840 f_flow_create(RTPEM[0], ep, flow[0]);
841
842 /* from MGW back to us */
843 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
844 flow[1].em.portnr := 20000;
845 f_flow_create(RTPEM[1], ep, flow[1]);
846
847 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
848 f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
849
850 f_sleep(1.0);
851
852 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
853 f_sleep(0.1);
854
855 stats[0] := f_rtpem_stats_get(RTPEM[0]);
856 stats[1] := f_rtpem_stats_get(RTPEM[1]);
857 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
858 setverdict(fail, "RTP endpoint statistics don't match");
859 }
860
861 f_dlcx_ok(ep, call_id);
862 setverdict(pass);
863
864 }
Harald Weltef53f1642017-11-18 19:57:11 +0100865
Harald Weltee636afd2017-09-17 16:24:09 +0800866 /* TODO: Double-DLCX (no retransmission) */
867
868
869
870 /* TODO: AUEP (various) */
871 /* TODO: RSIP (various) */
872 /* TODO: RQNT (various) */
873 /* TODO: EPCF (various) */
874 /* TODO: AUCX (various) */
875 /* TODO: invalid verb (various) */
876
Harald Welte00a067f2017-09-13 23:27:17 +0200877 control {
878 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800879 execute(TC_crcx());
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100880 execute(TC_crcx_noprefix());
Harald Weltee636afd2017-09-17 16:24:09 +0800881 execute(TC_crcx_unsupp_mode());
882 execute(TC_crcx_early_bidir_mode());
883 execute(TC_crcx_unsupp_param());
884 execute(TC_crcx_missing_callid());
885 execute(TC_crcx_missing_mode());
886 execute(TC_crcx_unsupp_packet_intv());
887 execute(TC_crcx_illegal_double_lco());
888 execute(TC_crcx_sdp());
Philipp Maier5e06cee2018-02-01 18:28:08 +0100889 execute(TC_crcx_wildcarded());
890 execute(TC_crcx_wildcarded_exhaust());
Harald Weltee636afd2017-09-17 16:24:09 +0800891 execute(TC_mdcx_without_crcx());
892 execute(TC_dlcx_without_crcx());
Philipp Maier8a3dc922018-02-02 14:55:12 +0100893 execute(TC_mdcx_wildcarded());
894 execute(TC_dlcx_wildcarded());
Harald Welte79181ff2017-11-18 19:26:11 +0100895 execute(TC_crcx_and_dlcx_ep_callid_connid());
896 execute(TC_crcx_and_dlcx_ep_callid());
897 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +0100898 execute(TC_crcx_and_dlcx_ep_callid_inval());
899 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +0100900 execute(TC_crcx_and_dlcx_retrans());
Harald Welte33d82162017-12-28 03:21:57 +0100901
902 execute(TC_crcx_dlcx_30ep());
Harald Weltebb7523b2018-03-29 08:52:01 +0200903
904 execute(TC_rtpem_selftest());
905 execute(TC_two_crcx_and_rtp());
Harald Welte00a067f2017-09-13 23:27:17 +0200906 }
907}