blob: 9d6dea66fcd0c1ba3d11f7a505b6e4a6e41c914b [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
Philipp Maier45635f42018-06-05 17:28:02 +020083 template MgcpCommand ts_CRCX_no_lco(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
84 line := t_MgcpCmdLine("CRCX", trans_id, ep),
85 params := {
86 t_MgcpParConnMode(mode),
87 ts_MgcpParCallId(call_id)
88 },
89 sdp := sdp
90 }
91
Harald Welte4017d552018-01-26 21:40:05 +010092 template MgcpCommand tr_CRCX(template MgcpEndpoint ep := ?) := {
93 line := t_MgcpCmdLine("CRCX", ?, ep),
Harald Welte90029572017-11-24 23:39:50 +010094 params := *,
95 sdp := *
96 }
97
Harald Welte4029e8c2017-11-23 22:00:42 +010098 template MgcpResponse tr_CRCX_ACK := {
99 line := {
100 code := "200",
Harald Welte51f34ad2017-11-24 20:40:43 +0100101 trans_id := ?,
Harald Welte4029e8c2017-11-23 22:00:42 +0100102 string := "OK"
103 },
104 params:= { { "I", ? }, *},
105 sdp := ?
106 }
107
Harald Welte90029572017-11-24 23:39:50 +0100108 template MgcpResponse ts_CRCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
109 line := {
110 code := "200",
111 trans_id := trans_id,
112 string := "OK"
113 },
114 params:= { ts_MgcpParConnectionId(conn_id) },
115 sdp := sdp
116 }
117
Harald Welte4029e8c2017-11-23 22:00:42 +0100118 template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
119 line := t_MgcpCmdLine("MDCX", trans_id, ep),
120 params := {
121 t_MgcpParConnMode(mode),
122 ts_MgcpParCallId(call_id),
123 ts_MgcpParConnectionId(conn_id),
124 //t_MgcpParReqId(omit),
Daniel Willmannfbef7142017-11-30 13:16:14 +0100125 t_MgcpParLocConnOpt("p:20, a:AMR")
Harald Welte4029e8c2017-11-23 22:00:42 +0100126 },
127 sdp := sdp
128 }
129
Harald Welte90029572017-11-24 23:39:50 +0100130 template MgcpCommand tr_MDCX := {
131 line := t_MgcpCmdLine("MDCX", ?, ?),
132 params := *,
133 sdp := *
134 }
135
Harald Weltebb7523b2018-03-29 08:52:01 +0200136 template MgcpResponse tr_MDCX_ACK := {
137 line := {
138 code := "200",
139 trans_id := ?,
140 string := "OK"
141 },
142 params := *,
143 sdp := ?
144 }
145
Harald Welte90029572017-11-24 23:39:50 +0100146 template MgcpResponse ts_MDCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
147
Harald Welte4029e8c2017-11-23 22:00:42 +0100148 /* have a function that generates a template, rather than a template in order to handle
149 * optional parameters */
150 function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
151 template MgcpConnectionId conn_id := omit) return template MgcpCommand {
152 var template MgcpCommand cmd;
153 cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
154 cmd.params := {};
155 cmd.sdp := omit;
156 if (isvalue(call_id)) {
157 f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
158 if (isvalue(conn_id)) {
159 f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
160 }
161 }
162 return cmd;
163 }
164
Harald Welteb71901a2018-01-26 19:16:05 +0100165 template MgcpCommand tr_DLCX(template MgcpEndpoint ep := ?) := {
166 line := t_MgcpCmdLine("DLCX", ?, ep),
Harald Welte90029572017-11-24 23:39:50 +0100167 params := *,
168 sdp := *
169 }
170
Harald Weltec82eef42017-11-24 20:40:12 +0100171 template MgcpResponse tr_DLCX_ACK := {
172 line := {
Daniel Willmann961e5c92017-11-30 16:37:40 +0100173 code := ("200", "250"),
Harald Weltec82eef42017-11-24 20:40:12 +0100174 trans_id := ?,
175 string := "OK"
176 },
177 params:= *,
178 sdp := *
179 }
180
Harald Welteb71901a2018-01-26 19:16:05 +0100181 template MgcpResponse ts_DLCX_ACK2(MgcpTransId trans_id) := {
182 line := {
183 code := "250",
184 trans_id := trans_id,
185 string := "OK"
186 },
187 params:= { /* list of ConnectionIDs */ },
188 sdp := omit
189 }
190
191
192
Harald Welte90029572017-11-24 23:39:50 +0100193 template MgcpResponse ts_DLCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
194
Harald Weltee98bb2e2017-11-29 12:09:48 +0100195 template MgcpCommand tr_RSIP := {
196 line := t_MgcpCmdLine("RSIP", ?, ?),
197 params := *,
198 sdp := *
199 }
200
Harald Welte4029e8c2017-11-23 22:00:42 +0100201 /* SDP Templates */
202 template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
203 charstring session_version := "1",
204 charstring addr_type := "IP4",
205 charstring user_name := "-") := {
206 user_name := user_name,
207 session_id := session_id,
208 session_version := session_version,
209 net_type := "IN",
210 addr_type := addr_type,
211 addr := addr
212 }
213
214 template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
215 template integer ttl := omit,
216 template integer num_of_addr := omit) :={
217 net_type := "IN",
218 addr_type := addr_type,
219 conn_addr := {
220 addr := addr,
221 ttl := ttl,
222 num_of_addr := num_of_addr
223 }
224 }
225
226 template SDP_time ts_SDP_time(charstring beg, charstring end) := {
227 time_field := {
228 start_time := beg,
229 stop_time := end
230 },
231 time_repeat := omit
232 }
233
234 template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
235 SDP_attribute_list attributes) := {
236 media_field := {
237 media := "audio",
238 ports := {
239 port_number := port_number,
240 num_of_ports := omit
241 },
242 transport := "RTP/AVP",
243 fmts := fmts
244 },
245 information := omit,
246 connections := omit,
247 bandwidth := omit,
248 key := omit,
249 attributes := attributes
250 }
251
252 /* master template for generating SDP based in template arguments */
253 template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
254 charstring session_id, charstring session_version,
255 integer rtp_port, SDP_fmt_list fmts,
256 SDP_attribute_list attributes) := {
257 protocol_version := 0,
258 origin := ts_SDP_origin(local_addr, session_id, session_version),
259 session_name := "-",
260 information := omit,
261 uri := omit,
262 emails := omit,
263 phone_numbers := omit,
264 connection := ts_SDP_connection_IP(remote_addr),
265 bandwidth := omit,
266 times := { ts_SDP_time("0","0") },
267 timezone_adjustments := omit,
268 key := omit,
269 attributes := omit,
270 media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
271 }
272
273 template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
274 rtpmap := {
275 attr_value := int2str(fmt) & " " & val
276 }
277 }
278 template SDP_attribute ts_SDP_ptime(integer p) := {
279 ptime := {
280 attr_value := int2str(p)
281 }
282 }
283
Harald Welteb71901a2018-01-26 19:16:05 +0100284 function f_mgcp_extract_par(MgcpMessage msg, MgcpInfoCode code) return charstring {
285 var MgcpParameterList pars;
286 if (ischosen(msg.command)) {
287 pars := msg.command.params;
288 } else {
289 pars := msg.response.params;
290 }
291 for (var integer i := 0; i < lengthof(pars); i := i + 1) {
292 var MgcpParameter par := pars[i];
293 if (par.code == code) {
294 return par.val;
Harald Welte4c11d562017-11-24 23:39:00 +0100295 }
296 }
297 setverdict(fail);
Harald Welteb71901a2018-01-26 19:16:05 +0100298 return "";
299 }
300
Harald Welte1fe74812018-01-29 21:57:26 +0100301 function f_MgcpResp_extract_par(MgcpResponse resp, MgcpInfoCode code) return charstring {
Harald Welteb71901a2018-01-26 19:16:05 +0100302 var MgcpMessage msg := {
303 response := resp
304 }
Harald Welte1fe74812018-01-29 21:57:26 +0100305 return f_mgcp_extract_par(msg, code);
Harald Welteb71901a2018-01-26 19:16:05 +0100306 }
307
Harald Welte1fe74812018-01-29 21:57:26 +0100308 function f_MgcpCmd_extract_par(MgcpCommand cmd, MgcpInfoCode code) return charstring {
Harald Welteb71901a2018-01-26 19:16:05 +0100309 var MgcpMessage msg := {
310 command := cmd
311 }
Harald Welte1fe74812018-01-29 21:57:26 +0100312 return f_mgcp_extract_par(msg, code);
Harald Welte4c11d562017-11-24 23:39:00 +0100313 }
314
Harald Welte1fe74812018-01-29 21:57:26 +0100315 function f_MgcpResp_extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
316 return str2hex(f_MgcpResp_extract_par(resp, "I"));
317 }
318
319 function f_MgcpCmd_extract_call_id(MgcpCommand cmd) return MgcpCallId {
320 return str2hex(f_MgcpCmd_extract_par(cmd, "C"));
321 }
322
323 function f_MgcpCmd_extract_conn_id(MgcpCommand cmd) return MgcpConnectionId {
324 return str2hex(f_MgcpCmd_extract_par(cmd, "I"));
325 }
326
327
Harald Welte4c11d562017-11-24 23:39:00 +0100328 function f_mgcp_alloc_tid() return MgcpTransId {
329 return int2str(float2int(rnd()*2147483647.0));
330 }
331
332 function f_mgcp_alloc_call_id() return MgcpCallId {
333 return int2hex(float2int(rnd()*2147483647.0), 8);
334 }
335
336 function f_mgcp_alloc_conn_id() return MgcpConnectionId {
337 return int2hex(float2int(rnd()*2147483647.0), 8);
338 }
339
Harald Weltebb5a1212018-01-26 10:34:44 +0100340 /* those verbs that related to a connection (and hence have ConnectionId) */
341 template MgcpVerb tr_MgcpVerb_ConnectionOriented := ("CRCX", "MDCX", "DLCX", "AUCX");
342 /* entire command template matching only connection oriented verbs */
343 template MgcpCommand tr_MgcpCommand_CO := {
344 line := {
345 verb := tr_MgcpVerb_ConnectionOriented,
346 trans_id := ?,
347 ep := ?,
348 ver := ?
349 },
350 params := *,
351 sdp := *
352 }
353
Harald Welte363cb0a2018-01-30 19:35:53 +0100354 function f_mgcp_find_param(MgcpMessage msg, MgcpInfoCode code, out charstring ret)
355 return boolean {
356 var MgcpParameterList pars;
357 if (ischosen(msg.command)) {
358 pars := msg.command.params;
359 } else {
360 pars := msg.response.params;
361 }
362 for (var integer i := 0; i < sizeof(pars); i := i+1) {
363 if (pars[i].code == code) {
364 ret := pars[i].val;
365 return true;
366 }
367 }
368 return false;
369 }
370
371 /* template to determine if a MGCP endpoint is a wildcard endpoint */
372 template charstring t_MGCP_EP_wildcard := (pattern "\*@*", pattern "rtpbridge/\*@*");
373
Harald Welteb71901a2018-01-26 19:16:05 +0100374
Harald Welte4029e8c2017-11-23 22:00:42 +0100375}