blob: beef9e8de64004a60d030e1aaeea05d2e1b33c68 [file] [log] [blame]
Daniel Willmannfa870f52018-01-17 12:37:14 +01001module MGCP_Emulation {
2
Harald Weltea02515f2018-01-26 10:33:23 +01003/* MGCP Emulation, runs on top of MGCP_CodecPort. It multiplexes/demultiplexes
4 * the individual connections, so there can be separate TTCN-3 components handling
5 * each of the connections.
6 *
7 * The MGCP_Emulation.main() function processes MGCP primitives from the MGCP
8 * socket via the MGCP_CodecPort, and dispatches them to the per-connection components.
9 *
10 * For each new inbound connection, the MgcpOps.create_cb() is called. It can create
11 * or resolve a TTCN-3 component, and returns a component reference to which that inbound
12 * connection is routed/dispatched.
13 *
14 * If a pre-existing component wants to register to handle a future inbound call, it can
15 * do so by registering an "expect" with the expected destination phone number. This is e.g. useful
16 * if you are simulating BSC + MGCP, and first trigger a connection from BSC side in a
17 * component which then subsequently should also handle the MGCP emulation.
18 *
19 * Inbound Unit Data messages (such as are dispatched to the MgcpOps.unitdata_cb() callback,
20 * which is registered with an argument to the main() function below.
21 *
22 * (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
23 * (C) 2018 by sysmocom - s.f.m.c. GmbH, Author: Daniel Willmann
24 * All rights reserved.
25 *
26 * Released under the terms of GNU General Public License, Version 2 or
27 * (at your option) any later version.
28 */
29
Daniel Willmannfa870f52018-01-17 12:37:14 +010030import from MGCP_CodecPort all;
31import from MGCP_CodecPort_CtrlFunct all;
32import from MGCP_Types all;
33import from MGCP_Templates all;
34import from Osmocom_Types all;
35import from IPL4asp_Types all;
36
37type component MGCP_ConnHdlr {
38 port MGCP_Conn_PT MGCP;
Harald Weltec27eaae2018-01-25 18:43:23 +010039 var MgcpConnectionId mgcp_conn_id;
Daniel Willmannfa870f52018-01-17 12:37:14 +010040}
41
42/* port between individual per-connection components and this dispatcher */
43type port MGCP_Conn_PT message {
44 inout MgcpCommand, MgcpResponse;
45} with { extension "internal" };
46
47
48type component MGCP_Emulation_CT {
49 /* Port facing to the UDP SUT */
50 port MGCP_CODEC_PT MGCP;
51 /* All MGCP_ConnHdlr MGCP ports connect here
52 * MGCP_Emulation_CT.main needs to figure out what messages
53 * to send where with CLIENT.send() to vc_conn */
54 port MGCP_Conn_PT CLIENT;
55 /* currently tracked connections */
56// var ConnectionData ConnectionTable[16];
57 /* pending expected CRCX */
58 var ExpectData ExpectTable[8];
59 /* procedure based port to register for incoming connections */
60 port MGCPEM_PROC_PT PROC;
61
62 var charstring g_mgcp_id;
Daniel Willmann166bbb32018-01-17 15:28:04 +010063 var integer g_mgcp_conn_id := -1;
Daniel Willmannfa870f52018-01-17 12:37:14 +010064}
65
66type function MGCPCreateCallback(MgcpCommand cmd, charstring id)
67runs on MGCP_Emulation_CT return MGCP_ConnHdlr;
68
69type record MGCPOps {
70 MGCPCreateCallback create_cb
71}
72
73type record MGCP_conn_parameters {
74 charstring callagent_ip,
75 uint16_t callagent_udp_port,
76 charstring mgw_ip,
77 uint16_t mgw_udp_port
78}
79
Daniel Willmann166bbb32018-01-17 15:28:04 +010080function tr_MGCP_RecvFrom_R(template MgcpMessage msg)
81runs on MGCP_Emulation_CT return template MGCP_RecvFrom {
82 var template MGCP_RecvFrom mrf := {
83 connId := g_mgcp_conn_id,
84 remName := ?,
85 remPort := ?,
86 locName := ?,
87 locPort := ?,
88 msg := msg
89 }
90 return mrf;
91}
92
Daniel Willmann955627a2018-01-17 15:22:32 +010093function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_Emulation_CT {
Daniel Willmannfa870f52018-01-17 12:37:14 +010094 var Result res;
95 g_mgcp_id := id;
96 //f_conn_table_init();
Daniel Willmann955627a2018-01-17 15:22:32 +010097 f_expect_table_init();
Daniel Willmannfa870f52018-01-17 12:37:14 +010098
99 map(self:MGCP, system:MGCP_CODEC_PT);
100 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, p.mgw_ip,
101p.mgw_udp_port,
102 p.callagent_ip, p.callagent_udp_port, 0, { udp:={} });
103
Daniel Willmann166bbb32018-01-17 15:28:04 +0100104 g_mgcp_conn_id := res.connId;
Daniel Willmannfa870f52018-01-17 12:37:14 +0100105
106 while (true) {
Daniel Willmann166bbb32018-01-17 15:28:04 +0100107 var MGCP_ConnHdlr vc_conn;
108 var ExpectCriteria crit;
109 var MGCP_RecvFrom mrf;
110 var MgcpMessage msg;
111 var MgcpCommand cmd;
112 var MgcpResponse resp;
113
Daniel Willmannfa870f52018-01-17 12:37:14 +0100114 alt {
Daniel Willmann166bbb32018-01-17 15:28:04 +0100115 /* MGCP from client */
116 [] CLIENT.receive(MgcpResponse:?) -> value resp sender vc_conn {
117 /* Pass message through */
118 msg.response := resp;
119 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Daniel Willmannfa870f52018-01-17 12:37:14 +0100120 }
Daniel Willmann166bbb32018-01-17 15:28:04 +0100121 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) -> value mrf {
122 if (ischosen(mrf.msg.command)) {
123 cmd := mrf.msg.command;
124 vc_conn := ops.create_cb.apply(cmd, id);
125 f_handle_userData(vc_conn, cmd);
126 } else {
127 setverdict(fail, "Received unexpected MGCP response: ", mrf.msg.response);
128 self.stop;
129 }
Daniel Willmannfa870f52018-01-17 12:37:14 +0100130 }
Daniel Willmann955627a2018-01-17 15:22:32 +0100131 [] PROC.getcall(MGCPEM_register:{?,?}) -> param(crit, vc_conn) {
132 f_create_expect(crit, vc_conn);
133 PROC.reply(MGCPEM_register:{crit, vc_conn});
134 }
Daniel Willmannfa870f52018-01-17 12:37:14 +0100135 }
136 }
137}
138
Daniel Willmann166bbb32018-01-17 15:28:04 +0100139private function f_handle_userData(MGCP_ConnHdlr conn, MgcpCommand cmd)
140runs on MGCP_Emulation_CT {
141 CLIENT.send(cmd) to conn;
142}
143
Daniel Willmannfa870f52018-01-17 12:37:14 +0100144/* "Expect" Handling */
145
146/* */
Daniel Willmann955627a2018-01-17 15:22:32 +0100147type record ExpectCriteria {
148 MgcpConnectionId connid optional,
149 MgcpEndpoint endpoint optional,
150 MgcpTransId transid optional
Daniel Willmannfa870f52018-01-17 12:37:14 +0100151}
152
153type record ExpectData {
154 ExpectCriteria crit optional,
Daniel Willmann955627a2018-01-17 15:22:32 +0100155 MGCP_ConnHdlr vc_conn
Daniel Willmannfa870f52018-01-17 12:37:14 +0100156}
157
Daniel Willmann955627a2018-01-17 15:22:32 +0100158signature MGCPEM_register(in ExpectCriteria cmd, in MGCP_ConnHdlr hdlr);
Daniel Willmannfa870f52018-01-17 12:37:14 +0100159
160type port MGCPEM_PROC_PT procedure {
161 inout MGCPEM_register;
162} with { extension "internal" };
163
164function f_get_mgcp_by_crit(ExpectCriteria crit)
165return template MgcpCommand {
166 template MgcpCommand ret := {
167 };
168
169 return ret;
170}
171
172/* Function that can be used as create_cb and will usse the expect table */
173function ExpectedCreateCallback(MgcpCommand cmd, charstring id)
174runs on MGCP_Emulation_CT return MGCP_ConnHdlr {
175 var MGCP_ConnHdlr ret := null;
176 var template MgcpCommand mgcpcmd;
177 var integer i;
178
179 /* Ensure cmd is a CRCX? */
180
181 for (i := 0; i < sizeof(ExpectTable); i := i+1) {
Daniel Willmann955627a2018-01-17 15:22:32 +0100182 if (not ispresent(ExpectTable[i].crit)) {
Daniel Willmannfa870f52018-01-17 12:37:14 +0100183 continue;
184 }
Daniel Willmann955627a2018-01-17 15:22:32 +0100185 /* FIXME: Ignore criteria for now */
186// mgcpcmd := f_get_mgcp_by_crit(ExpectTable[i].crit);
187// if (match(cmd, mgcpcmd)) {
Daniel Willmannfa870f52018-01-17 12:37:14 +0100188 ret := ExpectTable[i].vc_conn;
189 /* Release this entry */
190 ExpectTable[i].crit := omit;
191 ExpectTable[i].vc_conn := null;
192 log("Found Expect[", i, "] for ", cmd, " handled at ", ret);
193 return ret;
Daniel Willmann955627a2018-01-17 15:22:32 +0100194// }
Daniel Willmannfa870f52018-01-17 12:37:14 +0100195 }
196 setverdict(fail, "Couldn't find Expect for CRCX", cmd);
197 return ret;
198}
199
200private function f_create_expect(ExpectCriteria crit, MGCP_ConnHdlr hdlr)
201runs on MGCP_Emulation_CT {
202 var integer i;
203
204 /* Check an entry like this is not already presnt */
205 for (i := 0; i < sizeof(ExpectTable); i := i+1) {
206 if (crit == ExpectTable[i].crit) {
207 setverdict(fail, "Crit already present", crit);
208 self.stop;
209 }
210 }
211 for (i := 0; i < sizeof(ExpectTable); i := i+1) {
212 if (not ispresent(ExpectTable[i].crit)) {
213 ExpectTable[i].crit := crit;
214 ExpectTable[i].vc_conn := hdlr;
215 log("Created Expect[", i, "] for ", crit, " to be handled at ", hdlr);
216 return;
217 }
218 }
219 setverdict(fail, "No space left in ExpectTable")
220}
221
Daniel Willmann955627a2018-01-17 15:22:32 +0100222private function f_expect_table_init()
223runs on MGCP_Emulation_CT {
224 var integer i;
225 for (i := 0; i < sizeof(ExpectTable); i := i + 1) {
226 ExpectTable[i].crit := omit;
227 }
228}
229
Daniel Willmannfa870f52018-01-17 12:37:14 +0100230}