blob: e509da81d282c5b6b21f8173be8975979841b02d [file] [log] [blame]
Harald Welte4029e8c2017-11-23 22:00:42 +01001module MGCP_Templates {
2
Harald Welte35bb7162018-01-03 21:07:52 +01003/* MGCP Templates, building on top of MGCP_Types (Osmocom) and SDP_Types from Ericsson.
4 *
5 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
6 * All rights reserved.
7 *
8 * Released under the terms of GNU General Public License, Version 2 or
9 * (at your option) any later version.
10 */
11
12
Harald Welte4029e8c2017-11-23 22:00:42 +010013 import from MGCP_Types all;
14 import from SDP_Types all;
15
16 function f_mgcp_par_append(inout template MgcpParameterList list, template MgcpParameter par) {
17 var integer len := lengthof(list);
18 list[len] := par;
19 }
20
21 /* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
22 * conttest, netwloop, netwtest) */
23 template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
24
25 /* 3.2.2.2 CallId: maximum 32 hex chars */
26 template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
27 code := "C",
28 val := hex2str(cid)
29 };
30
31 /* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
32 template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
33 code := "X",
34 val := hex2str(rid)
35 };
36
Harald Welte363cb0a2018-01-30 19:35:53 +010037 /* 3.2.1.3 SpecificEndpointId */
38 template MgcpParameter ts_MgcpParSpecEP(MgcpEndpoint ep) := {
39 code := "Z",
40 val := ep
41 };
42
Harald Welte4029e8c2017-11-23 22:00:42 +010043 /* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
44 template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
45
46 /* 3.2.2.5: ConnectionId: maximum 32 hex chars */
47 template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
48 code := "I",
49 val := hex2str(cid)
50 };
51
52 /* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
53 /* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
54
55 template MgcpResponse tr_MgcpResp_Err(template MgcpResponseCode code) := {
56 line := {
57 code := code,
58 trans_id := ?,
59 string := ?
60 },
61 params := {},
62 sdp := omit
63 }
64
65 template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
66 verb := verb,
67 trans_id := trans_id,
68 ep := ep,
69 ver := "1.0"
70 };
71
72 template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
73 line := t_MgcpCmdLine("CRCX", trans_id, ep),
74 params := {
75 t_MgcpParConnMode(mode),
76 ts_MgcpParCallId(call_id),
77 //t_MgcpParReqId(omit),
Daniel Willmannfbef7142017-11-30 13:16:14 +010078 t_MgcpParLocConnOpt("p:20, a:AMR")
Harald Welte4029e8c2017-11-23 22:00:42 +010079 },
80 sdp := sdp
81 }
82
Harald Welte4017d552018-01-26 21:40:05 +010083 template MgcpCommand tr_CRCX(template MgcpEndpoint ep := ?) := {
84 line := t_MgcpCmdLine("CRCX", ?, ep),
Harald Welte90029572017-11-24 23:39:50 +010085 params := *,
86 sdp := *
87 }
88
Harald Welte4029e8c2017-11-23 22:00:42 +010089 template MgcpResponse tr_CRCX_ACK := {
90 line := {
91 code := "200",
Harald Welte51f34ad2017-11-24 20:40:43 +010092 trans_id := ?,
Harald Welte4029e8c2017-11-23 22:00:42 +010093 string := "OK"
94 },
95 params:= { { "I", ? }, *},
96 sdp := ?
97 }
98
Harald Welte90029572017-11-24 23:39:50 +010099 template MgcpResponse ts_CRCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
100 line := {
101 code := "200",
102 trans_id := trans_id,
103 string := "OK"
104 },
105 params:= { ts_MgcpParConnectionId(conn_id) },
106 sdp := sdp
107 }
108
Harald Welte4029e8c2017-11-23 22:00:42 +0100109 template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
110 line := t_MgcpCmdLine("MDCX", trans_id, ep),
111 params := {
112 t_MgcpParConnMode(mode),
113 ts_MgcpParCallId(call_id),
114 ts_MgcpParConnectionId(conn_id),
115 //t_MgcpParReqId(omit),
Daniel Willmannfbef7142017-11-30 13:16:14 +0100116 t_MgcpParLocConnOpt("p:20, a:AMR")
Harald Welte4029e8c2017-11-23 22:00:42 +0100117 },
118 sdp := sdp
119 }
120
Harald Welte90029572017-11-24 23:39:50 +0100121 template MgcpCommand tr_MDCX := {
122 line := t_MgcpCmdLine("MDCX", ?, ?),
123 params := *,
124 sdp := *
125 }
126
Harald Weltebb7523b2018-03-29 08:52:01 +0200127 template MgcpResponse tr_MDCX_ACK := {
128 line := {
129 code := "200",
130 trans_id := ?,
131 string := "OK"
132 },
133 params := *,
134 sdp := ?
135 }
136
Harald Welte90029572017-11-24 23:39:50 +0100137 template MgcpResponse ts_MDCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
138
Harald Welte4029e8c2017-11-23 22:00:42 +0100139 /* have a function that generates a template, rather than a template in order to handle
140 * optional parameters */
141 function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
142 template MgcpConnectionId conn_id := omit) return template MgcpCommand {
143 var template MgcpCommand cmd;
144 cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
145 cmd.params := {};
146 cmd.sdp := omit;
147 if (isvalue(call_id)) {
148 f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
149 if (isvalue(conn_id)) {
150 f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
151 }
152 }
153 return cmd;
154 }
155
Harald Welteb71901a2018-01-26 19:16:05 +0100156 template MgcpCommand tr_DLCX(template MgcpEndpoint ep := ?) := {
157 line := t_MgcpCmdLine("DLCX", ?, ep),
Harald Welte90029572017-11-24 23:39:50 +0100158 params := *,
159 sdp := *
160 }
161
Harald Weltec82eef42017-11-24 20:40:12 +0100162 template MgcpResponse tr_DLCX_ACK := {
163 line := {
Daniel Willmann961e5c92017-11-30 16:37:40 +0100164 code := ("200", "250"),
Harald Weltec82eef42017-11-24 20:40:12 +0100165 trans_id := ?,
166 string := "OK"
167 },
168 params:= *,
169 sdp := *
170 }
171
Harald Welteb71901a2018-01-26 19:16:05 +0100172 template MgcpResponse ts_DLCX_ACK2(MgcpTransId trans_id) := {
173 line := {
174 code := "250",
175 trans_id := trans_id,
176 string := "OK"
177 },
178 params:= { /* list of ConnectionIDs */ },
179 sdp := omit
180 }
181
182
183
Harald Welte90029572017-11-24 23:39:50 +0100184 template MgcpResponse ts_DLCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
185
Harald Weltee98bb2e2017-11-29 12:09:48 +0100186 template MgcpCommand tr_RSIP := {
187 line := t_MgcpCmdLine("RSIP", ?, ?),
188 params := *,
189 sdp := *
190 }
191
Harald Welte4029e8c2017-11-23 22:00:42 +0100192 /* SDP Templates */
193 template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
194 charstring session_version := "1",
195 charstring addr_type := "IP4",
196 charstring user_name := "-") := {
197 user_name := user_name,
198 session_id := session_id,
199 session_version := session_version,
200 net_type := "IN",
201 addr_type := addr_type,
202 addr := addr
203 }
204
205 template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
206 template integer ttl := omit,
207 template integer num_of_addr := omit) :={
208 net_type := "IN",
209 addr_type := addr_type,
210 conn_addr := {
211 addr := addr,
212 ttl := ttl,
213 num_of_addr := num_of_addr
214 }
215 }
216
217 template SDP_time ts_SDP_time(charstring beg, charstring end) := {
218 time_field := {
219 start_time := beg,
220 stop_time := end
221 },
222 time_repeat := omit
223 }
224
225 template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
226 SDP_attribute_list attributes) := {
227 media_field := {
228 media := "audio",
229 ports := {
230 port_number := port_number,
231 num_of_ports := omit
232 },
233 transport := "RTP/AVP",
234 fmts := fmts
235 },
236 information := omit,
237 connections := omit,
238 bandwidth := omit,
239 key := omit,
240 attributes := attributes
241 }
242
243 /* master template for generating SDP based in template arguments */
244 template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
245 charstring session_id, charstring session_version,
246 integer rtp_port, SDP_fmt_list fmts,
247 SDP_attribute_list attributes) := {
248 protocol_version := 0,
249 origin := ts_SDP_origin(local_addr, session_id, session_version),
250 session_name := "-",
251 information := omit,
252 uri := omit,
253 emails := omit,
254 phone_numbers := omit,
255 connection := ts_SDP_connection_IP(remote_addr),
256 bandwidth := omit,
257 times := { ts_SDP_time("0","0") },
258 timezone_adjustments := omit,
259 key := omit,
260 attributes := omit,
261 media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
262 }
263
264 template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
265 rtpmap := {
266 attr_value := int2str(fmt) & " " & val
267 }
268 }
269 template SDP_attribute ts_SDP_ptime(integer p) := {
270 ptime := {
271 attr_value := int2str(p)
272 }
273 }
274
Harald Welteb71901a2018-01-26 19:16:05 +0100275 function f_mgcp_extract_par(MgcpMessage msg, MgcpInfoCode code) return charstring {
276 var MgcpParameterList pars;
277 if (ischosen(msg.command)) {
278 pars := msg.command.params;
279 } else {
280 pars := msg.response.params;
281 }
282 for (var integer i := 0; i < lengthof(pars); i := i + 1) {
283 var MgcpParameter par := pars[i];
284 if (par.code == code) {
285 return par.val;
Harald Welte4c11d562017-11-24 23:39:00 +0100286 }
287 }
288 setverdict(fail);
Harald Welteb71901a2018-01-26 19:16:05 +0100289 return "";
290 }
291
Harald Welte1fe74812018-01-29 21:57:26 +0100292 function f_MgcpResp_extract_par(MgcpResponse resp, MgcpInfoCode code) return charstring {
Harald Welteb71901a2018-01-26 19:16:05 +0100293 var MgcpMessage msg := {
294 response := resp
295 }
Harald Welte1fe74812018-01-29 21:57:26 +0100296 return f_mgcp_extract_par(msg, code);
Harald Welteb71901a2018-01-26 19:16:05 +0100297 }
298
Harald Welte1fe74812018-01-29 21:57:26 +0100299 function f_MgcpCmd_extract_par(MgcpCommand cmd, MgcpInfoCode code) return charstring {
Harald Welteb71901a2018-01-26 19:16:05 +0100300 var MgcpMessage msg := {
301 command := cmd
302 }
Harald Welte1fe74812018-01-29 21:57:26 +0100303 return f_mgcp_extract_par(msg, code);
Harald Welte4c11d562017-11-24 23:39:00 +0100304 }
305
Harald Welte1fe74812018-01-29 21:57:26 +0100306 function f_MgcpResp_extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
307 return str2hex(f_MgcpResp_extract_par(resp, "I"));
308 }
309
310 function f_MgcpCmd_extract_call_id(MgcpCommand cmd) return MgcpCallId {
311 return str2hex(f_MgcpCmd_extract_par(cmd, "C"));
312 }
313
314 function f_MgcpCmd_extract_conn_id(MgcpCommand cmd) return MgcpConnectionId {
315 return str2hex(f_MgcpCmd_extract_par(cmd, "I"));
316 }
317
318
Harald Welte4c11d562017-11-24 23:39:00 +0100319 function f_mgcp_alloc_tid() return MgcpTransId {
320 return int2str(float2int(rnd()*2147483647.0));
321 }
322
323 function f_mgcp_alloc_call_id() return MgcpCallId {
324 return int2hex(float2int(rnd()*2147483647.0), 8);
325 }
326
327 function f_mgcp_alloc_conn_id() return MgcpConnectionId {
328 return int2hex(float2int(rnd()*2147483647.0), 8);
329 }
330
Harald Weltebb5a1212018-01-26 10:34:44 +0100331 /* those verbs that related to a connection (and hence have ConnectionId) */
332 template MgcpVerb tr_MgcpVerb_ConnectionOriented := ("CRCX", "MDCX", "DLCX", "AUCX");
333 /* entire command template matching only connection oriented verbs */
334 template MgcpCommand tr_MgcpCommand_CO := {
335 line := {
336 verb := tr_MgcpVerb_ConnectionOriented,
337 trans_id := ?,
338 ep := ?,
339 ver := ?
340 },
341 params := *,
342 sdp := *
343 }
344
Harald Welte363cb0a2018-01-30 19:35:53 +0100345 function f_mgcp_find_param(MgcpMessage msg, MgcpInfoCode code, out charstring ret)
346 return boolean {
347 var MgcpParameterList pars;
348 if (ischosen(msg.command)) {
349 pars := msg.command.params;
350 } else {
351 pars := msg.response.params;
352 }
353 for (var integer i := 0; i < sizeof(pars); i := i+1) {
354 if (pars[i].code == code) {
355 ret := pars[i].val;
356 return true;
357 }
358 }
359 return false;
360 }
361
362 /* template to determine if a MGCP endpoint is a wildcard endpoint */
363 template charstring t_MGCP_EP_wildcard := (pattern "\*@*", pattern "rtpbridge/\*@*");
364
Harald Welteb71901a2018-01-26 19:16:05 +0100365
Harald Welte4029e8c2017-11-23 22:00:42 +0100366}