blob: 07086c97f5e77116bea774387688aba94a02af1c [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 Welte3c6ebb92017-09-16 00:56:57 +08004 import from SDP_Types all;
5 import from MGCP_CodecPort all;
6 import from MGCP_CodecPort_CtrlFunct all;
Harald Weltef07c2862017-11-18 17:16:24 +01007 import from RTP_CodecPort all;
8 import from RTP_CodecPort_CtrlFunct all;
9 import from RTP_Endpoint all;
Harald Welte3c6ebb92017-09-16 00:56:57 +080010 import from IPL4asp_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +020011
Harald Welte21ba5572017-09-19 17:55:05 +080012 /* any variables declared in the component will be available to
13 * all functions that 'run on' the named component, similar to
14 * class members in C++ */
Harald Welte00a067f2017-09-13 23:27:17 +020015 type component dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080016 port MGCP_CODEC_PT MGCP;
Harald Weltef07c2862017-11-18 17:16:24 +010017 port RTP_CODEC_PT RTP;
Harald Welte3c6ebb92017-09-16 00:56:57 +080018 var boolean initialized := false;
Harald Welte55015362017-11-18 16:02:42 +010019 var ConnectionId g_mgcp_conn_id := -1;
Harald Weltee1e18c52017-09-17 16:23:07 +080020 var integer g_trans_id;
Harald Weltef07c2862017-11-18 17:16:24 +010021
22 var RtpEndpoint g_rtp_ep[2];
Harald Welte00a067f2017-09-13 23:27:17 +020023 };
24
Harald Weltee1e18c52017-09-17 16:23:07 +080025 function get_next_trans_id() runs on dummy_CT return MgcpTransId {
26 var MgcpTransId tid := int2str(g_trans_id);
27 g_trans_id := g_trans_id + 1;
28 return tid;
29 }
30
Harald Welte21ba5572017-09-19 17:55:05 +080031 /* all parameters declared here can be modified / overridden by
32 * the config file in the [MODULE_PARAMETERS] section. If no
33 * config file is used or the file doesn't specify them, the
34 * default values assigned below are used */
Harald Welte3c6ebb92017-09-16 00:56:57 +080035 modulepar {
36 PortNumber mp_local_udp_port := 2727;
37 charstring mp_local_ip := "127.0.0.1";
38 PortNumber mp_remote_udp_port := 2427;
39 charstring mp_remote_ip := "127.0.0.1";
Harald Weltef07c2862017-11-18 17:16:24 +010040 PortNumber mp_local_rtp_port_base := 10000;
Harald Welte3c6ebb92017-09-16 00:56:57 +080041 }
42
Harald Welte21ba5572017-09-19 17:55:05 +080043 /* initialization function, called by each test case at the
44 * beginning, but 'initialized' variable ensures its body is
45 * only executed once */
Harald Welte3c6ebb92017-09-16 00:56:57 +080046 private function f_init()runs on dummy_CT {
47 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010048 var uint32_t ssrc;
Harald Welte3c6ebb92017-09-16 00:56:57 +080049 if (initialized == true) {
50 return;
51 }
52 initialized := true;
53
Harald Welte21ba5572017-09-19 17:55:05 +080054 /* some random number for the initial transaction id */
Harald Weltee1e18c52017-09-17 16:23:07 +080055 g_trans_id := float2int(rnd()*65535.0);
Harald Welte3c6ebb92017-09-16 00:56:57 +080056 map(self:MGCP, system:MGCP_CODEC_PT);
Harald Welte21ba5572017-09-19 17:55:05 +080057 /* connect the MGCP test port using the given
Harald Welte55015362017-11-18 16:02:42 +010058 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
Harald Welte21ba5572017-09-19 17:55:05 +080059 * */
Harald Welte55015362017-11-18 16:02:42 +010060 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
61 g_mgcp_conn_id := res.connId;
Harald Weltef07c2862017-11-18 17:16:24 +010062
63 map(self:RTP, system:RTP_CODEC_PT);
64 ssrc := float2int(rnd()*4294967296.0);
65 rtp_endpoint_init(g_rtp_ep[0], mp_local_ip, mp_local_rtp_port_base, ssrc);
66 rtp_endpoint_bind(RTP, g_rtp_ep[0]);
67 rtp_endpoint_init(g_rtp_ep[1], mp_local_ip, mp_local_rtp_port_base+2, ssrc);
68 rtp_endpoint_bind(RTP, g_rtp_ep[1]);
Harald Welte3c6ebb92017-09-16 00:56:57 +080069 }
70
71 /* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
72 * conttest, netwloop, netwtest) */
73 template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
74
75 /* 3.2.2.2 CallId: maximum 32 hex chars */
76 template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
77 code := "C",
78 val := hex2str(cid)
79 };
80
81 /* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
82 template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
83 code := "X",
84 val := hex2str(rid)
85 };
86
87 /* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
88 template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
89
90 /* 3.2.2.5: ConnectionId: maximum 32 hex chars */
91 template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
92 code := "I",
93 val := hex2str(cid)
94 };
95
96 /* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
97 /* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
98
Harald Weltee636afd2017-09-17 16:24:09 +080099 template MgcpResponse tr_MgcpResp_Err(template MgcpResponseCode code) := {
100 line := {
101 code := code,
102 trans_id := ?,
103 string := ?
104 },
105 params := {},
106 sdp := omit
107 }
108
Harald Welte3c6ebb92017-09-16 00:56:57 +0800109 template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
110 verb := verb,
111 trans_id := trans_id,
112 ep := ep,
113 ver := "1.0"
114 };
115
116 template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
117 line := t_MgcpCmdLine("CRCX", trans_id, ep),
118 params := {
119 t_MgcpParConnMode(mode),
120 ts_MgcpParCallId(call_id),
121 //t_MgcpParReqId(omit),
122 t_MgcpParLocConnOpt("p: 20")
123 },
124 sdp := sdp
125 }
126
Harald Weltee636afd2017-09-17 16:24:09 +0800127 template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
128 line := t_MgcpCmdLine("MDCX", trans_id, ep),
129 params := {
130 t_MgcpParConnMode(mode),
131 ts_MgcpParCallId(call_id),
132 //t_MgcpParReqId(omit),
133 t_MgcpParLocConnOpt("p: 20")
134 },
135 sdp := sdp
136 }
137
138 template MgcpCommand ts_DLCX(MgcpTransId trans_id, charstring ep, MgcpCallId call_id) := {
139 line := t_MgcpCmdLine("DLCX", trans_id, ep),
140 params := {
141 ts_MgcpParCallId(call_id)
142 },
143 sdp := omit
144 }
145
146 /* SDP Templates */
147 template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
148 charstring session_version := "1",
149 charstring addr_type := "IP4",
150 charstring user_name := "-") := {
151 user_name := user_name,
152 session_id := session_id,
153 session_version := session_version,
154 net_type := "IN",
155 addr_type := addr_type,
156 addr := addr
157 }
158
159 template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
160 template integer ttl := omit,
161 template integer num_of_addr := omit) :={
162 net_type := "IN",
163 addr_type := addr_type,
164 conn_addr := {
165 addr := addr,
166 ttl := ttl,
167 num_of_addr := num_of_addr
168 }
169 }
170
171 template SDP_time ts_SDP_time(charstring beg, charstring end) := {
172 time_field := {
173 start_time := beg,
174 stop_time := end
175 },
176 time_repeat := omit
177 }
178
179 template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
180 SDP_attribute_list attributes) := {
181 media_field := {
182 media := "audio",
183 ports := {
184 port_number := port_number,
185 num_of_ports := omit
186 },
187 transport := "ARTP/AVP",
188 fmts := fmts
189 },
190 information := omit,
191 connections := omit,
192 bandwidth := omit,
193 key := omit,
194 attributes := attributes
195 }
196
Harald Welte21ba5572017-09-19 17:55:05 +0800197 /* master template for generating SDP based in template arguments */
Harald Weltee636afd2017-09-17 16:24:09 +0800198 template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
199 charstring session_id, charstring session_version,
200 integer rtp_port, SDP_fmt_list fmts,
201 SDP_attribute_list attributes) := {
202 protocol_version := 0,
203 origin := ts_SDP_origin(local_addr, session_id, session_version),
204 session_name := "-",
205 information := omit,
206 uri := omit,
207 emails := omit,
208 phone_numbers := omit,
209 connection := ts_SDP_connection_IP(remote_addr),
210 bandwidth := omit,
211 times := { ts_SDP_time("0","0") },
212 timezone_adjustments := omit,
213 key := omit,
214 attributes := omit,
215 media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
216 }
217
218 template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
219 rtpmap := {
220 attr_value := int2str(fmt) & " " & val
221 }
222 }
223 template SDP_attribute ts_SDP_ptime(integer p) := {
224 ptime := {
225 attr_value := int2str(p)
226 }
227 }
228
Harald Welte00a067f2017-09-13 23:27:17 +0200229 testcase TC_selftest() runs on dummy_CT {
230 const charstring c_auep := "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n";
231 const charstring c_mdcx3 := "MDCX 18983215 1@mgw MGCP 1.0\r\n";
232 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
233 "I: 1\n" &
234 "\n" &
235 "v=0\r\n" &
236 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
237 "s=-\r\n" &
238 "c=IN IP4 0.0.0.0\r\n" &
239 "t=0 0\r\n" &
240 "m=audio 0 RTP/AVP 126\r\n" &
241 "a=rtpmap:126 AMR/8000\r\n" &
242 "a=ptime:20\r\n";
243 const charstring c_mdcx4 := "MDCX 18983216 1@mgw MGCP 1.0\r\n" &
244 "M: sendrecv\r" &
245 "C: 2\r\n" &
246 "I: 1\r\n" &
247 "L: p:20, a:AMR, nt:IN\r\n" &
248 "\n" &
249 "v=0\r\n" &
250 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800251 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200252 "c=IN IP4 0.0.0.0\r\n" &
253 "t=0 0\r\n" &
254 "m=audio 4441 RTP/AVP 99\r\n" &
255 "a=rtpmap:99 AMR/8000\r\n" &
256 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800257 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200258
259 log(c_auep);
260 log(dec_MgcpCommand(c_auep));
261
262 log(c_mdcx3);
263 log(dec_MgcpCommand(c_mdcx3));
264
265 log(c_mdcx3_ret);
266 log(dec_MgcpResponse(c_mdcx3_ret));
267
268 log(c_mdcx4);
269 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800270
271 log(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H));
272 log(enc_MgcpCommand(valueof(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H))));
273
274 log(c_crcx510_ret);
275 log(dec_MgcpResponse(c_crcx510_ret));
276 log(dec_MgcpMessage(c_crcx510_ret));
277 }
278
Harald Weltee636afd2017-09-17 16:24:09 +0800279 /* CRCX test ideas:
280 * - without mandatory CallId
281 * - without mandatory ConnectionId
282 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
283 * - CRCX with remote session description and without
284 *
285 * general ideas:
286 * - packetization != 20ms
287 * - invalid mode
288 * x unsupported mode (517)
289 * x bidirectional mode before RemoteConnDesc: 527
290 * - invalid codec
291 * - retransmission of same transaction
292 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
293 */
294
Harald Welte21ba5572017-09-19 17:55:05 +0800295 /* build a receive template for receiving a MGCP message. You
296 * pass the MGCP response template in, and it will generate an
297 * MGCP_RecvFrom template that can match the primitives arriving on the
298 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800299 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
300 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100301 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800302 remName := mp_remote_ip,
303 remPort := mp_remote_udp_port,
304 locName := mp_local_ip,
305 locPort := mp_local_udp_port,
306 msg := { response := resp }
307 }
308 return mrf;
309 }
310
311 /* Send a MGCP request + receive a (matching!) response */
312 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
313 var MgcpMessage msg := { command := valueof(cmd) };
314 resp.line.trans_id := cmd.line.trans_id;
315 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800316 var MGCP_RecvFrom mrf;
317 timer T := 5.0;
318
Harald Welte55015362017-11-18 16:02:42 +0100319 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800320 T.start;
321 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800322 [] MGCP.receive(mrt) -> value mrf { }
323 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800324 [] MGCP.receive { repeat; }
325 [] T.timeout { setverdict(fail); }
326 }
327 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800328
329 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
330 return mrf.msg.response;
331 } else {
332 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
333 return r;
334 }
Harald Welte00a067f2017-09-13 23:27:17 +0200335 }
336
Harald Weltee636afd2017-09-17 16:24:09 +0800337 /* test valid CRCX without SDP */
338 testcase TC_crcx() runs on dummy_CT {
339 var template MgcpCommand cmd;
340 var MgcpResponse resp;
341 var template MgcpResponse rtmpl := {
342 line := {
343 code := "200",
344 string := "OK"
345 },
Harald Welte6f960b12017-11-17 23:24:46 +0100346 params := { { "I", ? }, *},
Harald Weltee636afd2017-09-17 16:24:09 +0800347 sdp := ?
348 };
349
350 f_init();
351
352 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "sendrecv", '1234'H);
353 resp := mgcp_transceive_mgw(cmd, rtmpl);
354 setverdict(pass);
355 }
356
357 /* test CRCX with unsupported mode, expect 517 */
358 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
359 var template MgcpCommand cmd;
360 var MgcpResponse resp;
361 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
362
363 f_init();
364
365 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "netwtest", '1234'H);
366 resp := mgcp_transceive_mgw(cmd, rtmpl);
367 setverdict(pass);
368 }
369
Harald Welte21ba5572017-09-19 17:55:05 +0800370 /* test CRCX with early bi-directional mode, expect 527 as
371 * bi-diretional media can only be established once both local and
372 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800373 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
374 var template MgcpCommand cmd;
375 var MgcpResponse resp;
376 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
377
378 f_init();
379
380 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "sendrecv", '1234'H);
381 resp := mgcp_transceive_mgw(cmd, rtmpl);
382 setverdict(pass);
383 }
384
385 /* test CRCX with unsupported Parameters */
386 testcase TC_crcx_unsupp_param() runs on dummy_CT {
387 var template MgcpCommand cmd;
388 var MgcpResponse resp;
389 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
390
391 f_init();
392
393 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "recvonly", '1234'H);
394 cmd.params := {
395 t_MgcpParConnMode("recvonly"),
396 ts_MgcpParCallId('1234'H),
397 t_MgcpParLocConnOpt("p:20"),
398 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
399 { "N", "foobar" }
400 }
401 resp := mgcp_transceive_mgw(cmd, rtmpl);
402 setverdict(pass);
403 }
404
405 /* test CRCX with missing CallId */
406 testcase TC_crcx_missing_callid() runs on dummy_CT {
407 var template MgcpCommand cmd;
408 var MgcpResponse resp;
409 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
410
411 f_init();
412
413 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "recvonly", '1234'H);
414 cmd.params := {
415 t_MgcpParConnMode("recvonly"),
416 t_MgcpParLocConnOpt("p:20")
417 }
418 resp := mgcp_transceive_mgw(cmd, rtmpl);
419 setverdict(pass);
420 }
421
422 /* test CRCX with missing Mode */
423 testcase TC_crcx_missing_mode() runs on dummy_CT {
424 var template MgcpCommand cmd;
425 var MgcpResponse resp;
426 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
427
428 f_init();
429
430 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "recvonly", '1234'H);
431 cmd.params := {
432 ts_MgcpParCallId('1234'H),
433 t_MgcpParLocConnOpt("p:20")
434 }
435 resp := mgcp_transceive_mgw(cmd, rtmpl);
436 setverdict(pass);
437 }
438
439 /* test CRCX with unsupported packetization interval */
440 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
441 var template MgcpCommand cmd;
442 var MgcpResponse resp;
443 var template MgcpResponse rtmpl := tr_MgcpResp_Err("532");
444
445 f_init();
446
447 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "recvonly", '1234'H);
448 cmd.params := {
449 t_MgcpParConnMode("recvonly"),
450 ts_MgcpParCallId('1234'H),
451 t_MgcpParLocConnOpt("p:111")
452 }
453 resp := mgcp_transceive_mgw(cmd, rtmpl);
454 setverdict(pass);
455 }
456
457 /* test CRCX with illegal double presence of local connection option */
458 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
459 var template MgcpCommand cmd;
460 var MgcpResponse resp;
461 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
462
463 f_init();
464
465 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "recvonly", '1234'H);
466 cmd.params := {
467 t_MgcpParConnMode("recvonly"),
468 ts_MgcpParCallId('1234'H),
Harald Welte21ba5572017-09-19 17:55:05 +0800469 /* p:20 is permitted only once and not twice! */
Harald Weltee636afd2017-09-17 16:24:09 +0800470 t_MgcpParLocConnOpt("p:20, a:AMR, p:20")
471 }
472 resp := mgcp_transceive_mgw(cmd, rtmpl);
473 setverdict(pass);
474 }
475
476 /* test valid CRCX with valid SDP */
477 testcase TC_crcx_sdp() runs on dummy_CT {
478 var template MgcpCommand cmd;
479 var MgcpResponse resp;
480 var template MgcpResponse rtmpl := {
481 line := {
482 code := "200",
483 string := "OK"
484 },
Harald Welte6f960b12017-11-17 23:24:46 +0100485 params := { { "I", ? }, *},
Harald Weltee636afd2017-09-17 16:24:09 +0800486 sdp := ?
487 };
488
489 f_init();
490
491 cmd := ts_CRCX(get_next_trans_id(), "2@mgw", "sendrecv", '1234'H);
492 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
493 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
494 valueof(ts_SDP_ptime(20)) });
495 resp := mgcp_transceive_mgw(cmd, rtmpl);
496 setverdict(pass);
497 }
498
499 /* TODO: various SDP related bits */
500
501
502 /* TODO: CRCX with X-Osmux */
503 /* TODO: double CRCX without force_realloc */
504
505 /* TODO: MDCX (various) */
506
507 /* TODO: MDCX without CRCX first */
508 testcase TC_mdcx_without_crcx() runs on dummy_CT {
509 var template MgcpCommand cmd;
510 var MgcpResponse resp;
511 var template MgcpResponse rtmpl := {
512 line := {
513 /* TODO: accept/enforce better error? */
514 code := "400",
515 string := ?
516 },
517 params:= { },
518 sdp := omit
519 };
520
521 f_init();
522
523 cmd := ts_MDCX(get_next_trans_id(), "3@mgw", "sendrecv", '31234'H);
524 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
525 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
526 valueof(ts_SDP_ptime(20)) });
527 resp := mgcp_transceive_mgw(cmd, rtmpl);
528 setverdict(pass);
529 }
530
531 /* DLCX without CRCX first */
532 testcase TC_dlcx_without_crcx() runs on dummy_CT {
533 var template MgcpCommand cmd;
534 var MgcpResponse resp;
535 var template MgcpResponse rtmpl := {
536 line := {
537 /* TODO: accept/enforce better error? */
538 code := "400",
539 string := ?
540 },
541 params:= { },
542 sdp := omit
543 };
544
545 f_init();
546
547 cmd := ts_DLCX(get_next_trans_id(), "4@mgw", '41234'H);
548 resp := mgcp_transceive_mgw(cmd, rtmpl);
549 setverdict(pass);
550 }
551
Harald Welte21ba5572017-09-19 17:55:05 +0800552 /* Test (valid) CRCX followed by (valid) DLCX */
Harald Welte5b4c44e2017-09-17 16:35:27 +0800553 testcase TC_crcx_and_dlcx() runs on dummy_CT {
554 var template MgcpCommand cmd;
555 var MgcpResponse resp;
556 var template MgcpResponse rtmpl := {
557 line := {
558 code := ("200", "250"),
559 string := "OK"
560 },
Harald Welte6f960b12017-11-17 23:24:46 +0100561 params:= { { "I", ? }, *},
Harald Welte5b4c44e2017-09-17 16:35:27 +0800562 sdp := ?
563 };
564
565 f_init();
566
567 cmd := ts_CRCX(get_next_trans_id(), "5@mgw", "sendrecv", '51234'H);
568 resp := mgcp_transceive_mgw(cmd, rtmpl);
569
570 cmd := ts_DLCX(get_next_trans_id(), "5@mgw", '51234'H);
571 rtmpl.sdp := omit;
Harald Weltecbae9d12017-11-17 23:25:26 +0100572 rtmpl.params := *;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800573 resp := mgcp_transceive_mgw(cmd, rtmpl);
574
575 setverdict(pass);
576 }
577
Harald Weltee636afd2017-09-17 16:24:09 +0800578 /* TODO: DLCX of valid endpoint but invalid call-id */
579 /* TODO: Double-DLCX (retransmission) */
580 /* TODO: Double-DLCX (no retransmission) */
581
582
583
584 /* TODO: AUEP (various) */
585 /* TODO: RSIP (various) */
586 /* TODO: RQNT (various) */
587 /* TODO: EPCF (various) */
588 /* TODO: AUCX (various) */
589 /* TODO: invalid verb (various) */
590
Harald Welte00a067f2017-09-13 23:27:17 +0200591 control {
592 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800593 execute(TC_crcx());
Harald Weltee636afd2017-09-17 16:24:09 +0800594 execute(TC_crcx_unsupp_mode());
595 execute(TC_crcx_early_bidir_mode());
596 execute(TC_crcx_unsupp_param());
597 execute(TC_crcx_missing_callid());
598 execute(TC_crcx_missing_mode());
599 execute(TC_crcx_unsupp_packet_intv());
600 execute(TC_crcx_illegal_double_lco());
601 execute(TC_crcx_sdp());
602 execute(TC_mdcx_without_crcx());
603 execute(TC_dlcx_without_crcx());
Harald Welte5b4c44e2017-09-17 16:35:27 +0800604 execute(TC_crcx_and_dlcx());
Harald Welte00a067f2017-09-13 23:27:17 +0200605 }
606}