376 lines
10 KiB
Plaintext
376 lines
10 KiB
Plaintext
module MGCP_Templates {
|
|
|
|
/* MGCP Templates, building on top of MGCP_Types (Osmocom) and SDP_Types from Ericsson.
|
|
*
|
|
* (C) 2017 by Harald Welte <laforge@gnumonks.org>
|
|
* All rights reserved.
|
|
*
|
|
* Released under the terms of GNU General Public License, Version 2 or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
|
|
import from MGCP_Types all;
|
|
import from SDP_Types all;
|
|
|
|
function f_mgcp_par_append(inout template MgcpParameterList list, template MgcpParameter par) {
|
|
var integer len := lengthof(list);
|
|
list[len] := par;
|
|
}
|
|
|
|
/* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
|
|
* conttest, netwloop, netwtest) */
|
|
template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
|
|
|
|
/* 3.2.2.2 CallId: maximum 32 hex chars */
|
|
template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
|
|
code := "C",
|
|
val := hex2str(cid)
|
|
};
|
|
|
|
/* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
|
|
template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
|
|
code := "X",
|
|
val := hex2str(rid)
|
|
};
|
|
|
|
/* 3.2.1.3 SpecificEndpointId */
|
|
template MgcpParameter ts_MgcpParSpecEP(MgcpEndpoint ep) := {
|
|
code := "Z",
|
|
val := ep
|
|
};
|
|
|
|
/* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
|
|
template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
|
|
|
|
/* 3.2.2.5: ConnectionId: maximum 32 hex chars */
|
|
template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
|
|
code := "I",
|
|
val := hex2str(cid)
|
|
};
|
|
|
|
/* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
|
|
/* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
|
|
|
|
template MgcpResponse tr_MgcpResp_Err(template MgcpResponseCode code) := {
|
|
line := {
|
|
code := code,
|
|
trans_id := ?,
|
|
string := ?
|
|
},
|
|
params := {},
|
|
sdp := omit
|
|
}
|
|
|
|
template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
|
|
verb := verb,
|
|
trans_id := trans_id,
|
|
ep := ep,
|
|
ver := "1.0"
|
|
};
|
|
|
|
template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
|
|
line := t_MgcpCmdLine("CRCX", trans_id, ep),
|
|
params := {
|
|
t_MgcpParConnMode(mode),
|
|
ts_MgcpParCallId(call_id),
|
|
//t_MgcpParReqId(omit),
|
|
t_MgcpParLocConnOpt("p:20, a:AMR")
|
|
},
|
|
sdp := sdp
|
|
}
|
|
|
|
template MgcpCommand ts_CRCX_no_lco(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
|
|
line := t_MgcpCmdLine("CRCX", trans_id, ep),
|
|
params := {
|
|
t_MgcpParConnMode(mode),
|
|
ts_MgcpParCallId(call_id)
|
|
},
|
|
sdp := sdp
|
|
}
|
|
|
|
template MgcpCommand tr_CRCX(template MgcpEndpoint ep := ?) := {
|
|
line := t_MgcpCmdLine("CRCX", ?, ep),
|
|
params := *,
|
|
sdp := *
|
|
}
|
|
|
|
template MgcpResponse tr_CRCX_ACK := {
|
|
line := {
|
|
code := "200",
|
|
trans_id := ?,
|
|
string := "OK"
|
|
},
|
|
params:= { { "I", ? }, *},
|
|
sdp := ?
|
|
}
|
|
|
|
template MgcpResponse ts_CRCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
|
|
line := {
|
|
code := "200",
|
|
trans_id := trans_id,
|
|
string := "OK"
|
|
},
|
|
params:= { ts_MgcpParConnectionId(conn_id) },
|
|
sdp := sdp
|
|
}
|
|
|
|
template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
|
|
line := t_MgcpCmdLine("MDCX", trans_id, ep),
|
|
params := {
|
|
t_MgcpParConnMode(mode),
|
|
ts_MgcpParCallId(call_id),
|
|
ts_MgcpParConnectionId(conn_id),
|
|
//t_MgcpParReqId(omit),
|
|
t_MgcpParLocConnOpt("p:20, a:AMR")
|
|
},
|
|
sdp := sdp
|
|
}
|
|
|
|
template MgcpCommand tr_MDCX := {
|
|
line := t_MgcpCmdLine("MDCX", ?, ?),
|
|
params := *,
|
|
sdp := *
|
|
}
|
|
|
|
template MgcpResponse tr_MDCX_ACK := {
|
|
line := {
|
|
code := "200",
|
|
trans_id := ?,
|
|
string := "OK"
|
|
},
|
|
params := *,
|
|
sdp := ?
|
|
}
|
|
|
|
template MgcpResponse ts_MDCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
|
|
|
|
/* have a function that generates a template, rather than a template in order to handle
|
|
* optional parameters */
|
|
function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
|
|
template MgcpConnectionId conn_id := omit) return template MgcpCommand {
|
|
var template MgcpCommand cmd;
|
|
cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
|
|
cmd.params := {};
|
|
cmd.sdp := omit;
|
|
if (isvalue(call_id)) {
|
|
f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
|
|
if (isvalue(conn_id)) {
|
|
f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
|
|
}
|
|
}
|
|
return cmd;
|
|
}
|
|
|
|
template MgcpCommand tr_DLCX(template MgcpEndpoint ep := ?) := {
|
|
line := t_MgcpCmdLine("DLCX", ?, ep),
|
|
params := *,
|
|
sdp := *
|
|
}
|
|
|
|
template MgcpResponse tr_DLCX_ACK := {
|
|
line := {
|
|
code := ("200", "250"),
|
|
trans_id := ?,
|
|
string := "OK"
|
|
},
|
|
params:= *,
|
|
sdp := *
|
|
}
|
|
|
|
template MgcpResponse ts_DLCX_ACK2(MgcpTransId trans_id) := {
|
|
line := {
|
|
code := "250",
|
|
trans_id := trans_id,
|
|
string := "OK"
|
|
},
|
|
params:= { /* list of ConnectionIDs */ },
|
|
sdp := omit
|
|
}
|
|
|
|
|
|
|
|
template MgcpResponse ts_DLCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
|
|
|
|
template MgcpCommand tr_RSIP := {
|
|
line := t_MgcpCmdLine("RSIP", ?, ?),
|
|
params := *,
|
|
sdp := *
|
|
}
|
|
|
|
/* SDP Templates */
|
|
template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
|
|
charstring session_version := "1",
|
|
charstring addr_type := "IP4",
|
|
charstring user_name := "-") := {
|
|
user_name := user_name,
|
|
session_id := session_id,
|
|
session_version := session_version,
|
|
net_type := "IN",
|
|
addr_type := addr_type,
|
|
addr := addr
|
|
}
|
|
|
|
template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
|
|
template integer ttl := omit,
|
|
template integer num_of_addr := omit) :={
|
|
net_type := "IN",
|
|
addr_type := addr_type,
|
|
conn_addr := {
|
|
addr := addr,
|
|
ttl := ttl,
|
|
num_of_addr := num_of_addr
|
|
}
|
|
}
|
|
|
|
template SDP_time ts_SDP_time(charstring beg, charstring end) := {
|
|
time_field := {
|
|
start_time := beg,
|
|
stop_time := end
|
|
},
|
|
time_repeat := omit
|
|
}
|
|
|
|
template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
|
|
SDP_attribute_list attributes) := {
|
|
media_field := {
|
|
media := "audio",
|
|
ports := {
|
|
port_number := port_number,
|
|
num_of_ports := omit
|
|
},
|
|
transport := "RTP/AVP",
|
|
fmts := fmts
|
|
},
|
|
information := omit,
|
|
connections := omit,
|
|
bandwidth := omit,
|
|
key := omit,
|
|
attributes := attributes
|
|
}
|
|
|
|
/* master template for generating SDP based in template arguments */
|
|
template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
|
|
charstring session_id, charstring session_version,
|
|
integer rtp_port, SDP_fmt_list fmts,
|
|
SDP_attribute_list attributes) := {
|
|
protocol_version := 0,
|
|
origin := ts_SDP_origin(local_addr, session_id, session_version),
|
|
session_name := "-",
|
|
information := omit,
|
|
uri := omit,
|
|
emails := omit,
|
|
phone_numbers := omit,
|
|
connection := ts_SDP_connection_IP(remote_addr),
|
|
bandwidth := omit,
|
|
times := { ts_SDP_time("0","0") },
|
|
timezone_adjustments := omit,
|
|
key := omit,
|
|
attributes := omit,
|
|
media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
|
|
}
|
|
|
|
template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
|
|
rtpmap := {
|
|
attr_value := int2str(fmt) & " " & val
|
|
}
|
|
}
|
|
template SDP_attribute ts_SDP_ptime(integer p) := {
|
|
ptime := {
|
|
attr_value := int2str(p)
|
|
}
|
|
}
|
|
|
|
function f_mgcp_extract_par(MgcpMessage msg, MgcpInfoCode code) return charstring {
|
|
var MgcpParameterList pars;
|
|
if (ischosen(msg.command)) {
|
|
pars := msg.command.params;
|
|
} else {
|
|
pars := msg.response.params;
|
|
}
|
|
for (var integer i := 0; i < lengthof(pars); i := i + 1) {
|
|
var MgcpParameter par := pars[i];
|
|
if (par.code == code) {
|
|
return par.val;
|
|
}
|
|
}
|
|
setverdict(fail, "Could not extract parameters for code ", code);
|
|
return "";
|
|
}
|
|
|
|
function f_MgcpResp_extract_par(MgcpResponse resp, MgcpInfoCode code) return charstring {
|
|
var MgcpMessage msg := {
|
|
response := resp
|
|
}
|
|
return f_mgcp_extract_par(msg, code);
|
|
}
|
|
|
|
function f_MgcpCmd_extract_par(MgcpCommand cmd, MgcpInfoCode code) return charstring {
|
|
var MgcpMessage msg := {
|
|
command := cmd
|
|
}
|
|
return f_mgcp_extract_par(msg, code);
|
|
}
|
|
|
|
function f_MgcpResp_extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
|
|
return str2hex(f_MgcpResp_extract_par(resp, "I"));
|
|
}
|
|
|
|
function f_MgcpCmd_extract_call_id(MgcpCommand cmd) return MgcpCallId {
|
|
return str2hex(f_MgcpCmd_extract_par(cmd, "C"));
|
|
}
|
|
|
|
function f_MgcpCmd_extract_conn_id(MgcpCommand cmd) return MgcpConnectionId {
|
|
return str2hex(f_MgcpCmd_extract_par(cmd, "I"));
|
|
}
|
|
|
|
|
|
function f_mgcp_alloc_tid() return MgcpTransId {
|
|
return int2str(float2int(rnd()*2147483647.0));
|
|
}
|
|
|
|
function f_mgcp_alloc_call_id() return MgcpCallId {
|
|
return int2hex(float2int(rnd()*2147483647.0), 8);
|
|
}
|
|
|
|
function f_mgcp_alloc_conn_id() return MgcpConnectionId {
|
|
return int2hex(float2int(rnd()*2147483647.0), 8);
|
|
}
|
|
|
|
/* those verbs that related to a connection (and hence have ConnectionId) */
|
|
template MgcpVerb tr_MgcpVerb_ConnectionOriented := ("CRCX", "MDCX", "DLCX", "AUCX");
|
|
/* entire command template matching only connection oriented verbs */
|
|
template MgcpCommand tr_MgcpCommand_CO := {
|
|
line := {
|
|
verb := tr_MgcpVerb_ConnectionOriented,
|
|
trans_id := ?,
|
|
ep := ?,
|
|
ver := ?
|
|
},
|
|
params := *,
|
|
sdp := *
|
|
}
|
|
|
|
function f_mgcp_find_param(MgcpMessage msg, MgcpInfoCode code, out charstring ret)
|
|
return boolean {
|
|
var MgcpParameterList pars;
|
|
if (ischosen(msg.command)) {
|
|
pars := msg.command.params;
|
|
} else {
|
|
pars := msg.response.params;
|
|
}
|
|
for (var integer i := 0; i < sizeof(pars); i := i+1) {
|
|
if (pars[i].code == code) {
|
|
ret := pars[i].val;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* template to determine if a MGCP endpoint is a wildcard endpoint */
|
|
template charstring t_MGCP_EP_wildcard := (pattern "\*@*", pattern "rtpbridge/\*@*");
|
|
|
|
|
|
}
|