lib/mgcp: Add new port with support to handle multiple MGCP sockets

* Some scenarios like MGW BSC-attached in SCCPlite require handling of
2 MGCP-over-UDP sockets in MGCP Emulation: 1 for regular
libosmomgcp-client from osmo-bsc and another one from the forward socket
from osmo-bsc (of MGCP-over-IPA messages communicated with MSC).

* Old port is kept for backward compatibility with other tests and
enabled by default. It's also interesting to keep it because it makes
tests without special needs (2 sockets) to use the old port/API which
produces simpler code to read and mantain.

* Users of the new port have to enable multi_conn_mode parameter and
expect to interact with port MGCP_CLIENT_MULTI instead of MGCP_CLIENT,
which will offer messages containing information about the UDP
connection being used by that message.

Change-Id: Ic0ba8c5cde068c07671512a83095d83e28b86746
This commit is contained in:
Pau Espin 2019-06-18 17:21:52 +02:00 committed by laforge
parent 513b831cda
commit 1a026a52d3
4 changed files with 84 additions and 13 deletions

View File

@ -294,7 +294,8 @@ function f_init_mgcp(charstring id) runs on test_CT {
callagent_ip := mp_bsc_ip,
callagent_udp_port := -1,
mgw_ip := mp_test_ip,
mgw_udp_port := 2427
mgw_udp_port := 2427,
multi_conn_mode := false
};
vc_MGCP := MGCP_Emulation_CT.create(id);

View File

@ -41,11 +41,33 @@ module MGCP_CodecPort {
MgcpMessage msg
}
type record MGCP_SendTo {
ConnectionId connId,
HostName remName,
PortNumber remPort,
MgcpMessage msg
};
template MGCP_Send t_MGCP_Send(template ConnectionId connId, template MgcpMessage msg) := {
connId := connId,
msg := msg
}
template MGCP_SendTo t_MGCP_SendTo(template ConnectionId connId, HostName remName,
PortNumber remPort,template MgcpMessage msg) := {
connId := connId,
remName := remName,
remPort := remPort,
msg := msg
}
template MGCP_SendTo t_MGCP_SendToMrf(MGCP_RecvFrom mrf,template MgcpMessage msg) := {
connId := mrf.connId,
remName := mrf.remName,
remPort := mrf.remPort,
msg := msg
}
private function IPL4_to_MGCP_RecvFrom(in ASP_RecvFrom pin, out MGCP_RecvFrom pout) {
pout.connId := pin.connId;
pout.remName := pin.remName;
@ -65,13 +87,23 @@ module MGCP_CodecPort {
pout.msg := char2oct(enc_MgcpMessage(pin.msg));
} with { extension "prototype(fast)" };
private function MGCP_to_IPL4_SendTo(in MGCP_SendTo pin, out ASP_SendTo out_ud) {
out_ud.connId := pin.connId;
out_ud.remName := pin.remName;
out_ud.remPort := pin.remPort;
out_ud.proto := { udp := {} };
out_ud.msg := char2oct(enc_MgcpMessage(pin.msg));
} with { extension "prototype(fast)" };
type port MGCP_CODEC_PT message {
out MGCP_Send;
out MGCP_Send,
MGCP_SendTo;
in MGCP_RecvFrom,
ASP_ConnId_ReadyToRelease,
ASP_Event;
} with { extension "user IPL4asp_PT
out(MGCP_Send -> ASP_Send:function(MGCP_to_IPL4_Send))
out(MGCP_Send -> ASP_Send:function(MGCP_to_IPL4_Send);
MGCP_SendTo -> ASP_SendTo: function(MGCP_to_IPL4_SendTo))
in(ASP_RecvFrom -> MGCP_RecvFrom: function(IPL4_to_MGCP_RecvFrom);
ASP_ConnId_ReadyToRelease -> ASP_ConnId_ReadyToRelease: simple;
ASP_Event -> ASP_Event: simple)"

View File

@ -37,8 +37,11 @@ import from Osmocom_Types all;
import from IPL4asp_Types all;
type component MGCP_ConnHdlr {
/* Simple send/recv without caring about peer addr+port. Used with multi_conn_mode=false. */
port MGCP_Conn_PT MGCP;
/* procedure based port to register for incoming connections */
/* Handle multiple connections concurrently. Used with multi_conn_mode=true. */
port MGCP_Conn_Multi_PT MGCP_MULTI;
/* procedure based port to register for incoming connections. */
port MGCPEM_PROC_PT MGCP_PROC;
}
@ -47,6 +50,11 @@ type port MGCP_Conn_PT message {
inout MgcpCommand, MgcpResponse;
} with { extension "internal" };
/* port between individual per-connection components and this dispatcher */
type port MGCP_Conn_Multi_PT message {
inout MGCP_RecvFrom, MGCP_SendTo;
} with { extension "internal" };
/* represents a single MGCP Endpoint */
type record EndpointData {
MGCP_ConnHdlr comp_ref,
@ -63,6 +71,8 @@ type component MGCP_Emulation_CT {
* MGCP_Emulation_CT.main needs to figure out what messages
* to send where with CLIENT.send() to vc_conn */
port MGCP_Conn_PT MGCP_CLIENT;
/* This one is used with multi_conn_mode=true and allows differentiating UDP sockets */
port MGCP_Conn_Multi_PT MGCP_CLIENT_MULTI;
/* currently tracked connections */
var EndpointData MgcpEndpointTable[16];
var MgcpTransIds MgcpPendingTrans := {};
@ -73,6 +83,8 @@ type component MGCP_Emulation_CT {
var charstring g_mgcp_id;
var integer g_mgcp_conn_id := -1;
var MGCP_conn_parameters g_pars;
}
type function MGCPCreateCallback(MgcpCommand cmd, charstring id)
@ -90,7 +102,8 @@ type record MGCP_conn_parameters {
HostName callagent_ip,
PortNumber callagent_udp_port,
HostName mgw_ip,
PortNumber mgw_udp_port
PortNumber mgw_udp_port,
boolean multi_conn_mode
}
function tr_MGCP_RecvFrom_R(template MgcpMessage msg)
@ -224,14 +237,23 @@ runs on MGCP_Emulation_CT {
}
}
private function f_forward_to_client(MGCP_RecvFrom mrf, MGCP_ConnHdlr vc_conn) runs on MGCP_Emulation_CT {
if (g_pars.multi_conn_mode) {
MGCP_CLIENT_MULTI.send(mrf) to vc_conn;
} else {
MGCP_CLIENT.send(mrf.msg.command) to vc_conn;
}
}
function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_Emulation_CT {
var Result res;
g_pars := p;
g_mgcp_id := id;
f_ep_table_init();
f_expect_table_init();
map(self:MGCP, system:MGCP_CODEC_PT);
if (p.callagent_udp_port == -1) {
if (p.multi_conn_mode or p.callagent_udp_port == -1) {
res := MGCP_CodecPort_CtrlFunct.f_IPL4_listen(MGCP, p.mgw_ip, p.mgw_udp_port, { udp:={} });
} else {
res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, p.callagent_ip, p.callagent_udp_port, p.mgw_ip, p.mgw_udp_port, -1, { udp:={} });
@ -246,6 +268,7 @@ function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_E
var MGCP_ConnHdlr vc_conn;
var ExpectCriteria crit;
var MGCP_RecvFrom mrf;
var MGCP_SendTo mst;
var MgcpMessage msg;
var MgcpCommand cmd;
var MgcpResponse resp;
@ -253,7 +276,7 @@ function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_E
alt {
/* MGCP from client */
[] MGCP_CLIENT.receive(MgcpResponse:?) -> value resp sender vc_conn {
[not p.multi_conn_mode] MGCP_CLIENT.receive(MgcpResponse:?) -> value resp sender vc_conn {
msg := {
response := resp
};
@ -265,9 +288,23 @@ function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_E
/* TODO: check which ConnectionID client has allocated + store in table? */
MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
}
/* MGCP from client in Multi Conn mode */
[p.multi_conn_mode] MGCP_CLIENT_MULTI.receive(MGCP_SendTo:?) -> value mst sender vc_conn {
/* If this is the resposne to a pending CRCX, extract Endpoint and store in table */
if (f_trans_id_was_pending(mst.msg.response.line.trans_id)) {
f_ep_table_add(vc_conn, f_mgcp_ep(mst.msg));
}
/* Pass message through */
/* TODO: check which ConnectionID client has allocated + store in table? */
MGCP.send(mst);
}
[] MGCP.receive(tr_MGCP_RecvFrom_R(?)) -> value mrf {
if (p.callagent_udp_port == -1) {
/* we aren't yet connected to the remote side port, let's fix this */
if (not p.multi_conn_mode and p.callagent_udp_port == -1) {
/* we aren't yet connected to the remote side
port, let's fix this. This way upper layers
can use Send/Recv without caring about UDP
src/dst addr + port */
p.callagent_udp_port := mrf.remPort;
res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, p.callagent_ip, p.callagent_udp_port, p.mgw_ip, p.mgw_udp_port, g_mgcp_conn_id, { udp:={} });
if (not ispresent(res.connId)) {
@ -279,7 +316,7 @@ function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_E
cmd := mrf.msg.command;
if (f_ep_known(cmd.line.ep)) {
vc_conn := f_comp_by_ep(cmd.line.ep);
MGCP_CLIENT.send(cmd) to vc_conn;
f_forward_to_client(mrf, vc_conn);
} else {
if (cmd.line.verb == "CRCX") {
vc_conn := ops.create_cb.apply(cmd, id);
@ -290,12 +327,12 @@ function main(MGCPOps ops, MGCP_conn_parameters p, charstring id) runs on MGCP_E
/* add this transaction to list of pending transactions */
MgcpPendingTrans := MgcpPendingTrans & {cmd.line.trans_id};
}
MGCP_CLIENT.send(cmd) to vc_conn;
f_forward_to_client(mrf, vc_conn);
} else {
/* connectionless MGCP, i.e. messages without ConnectionId */
var template MgcpMessage r := ops.unitdata_cb.apply(mrf.msg);
if (isvalue(r)) {
MGCP.send(t_MGCP_Send(g_mgcp_conn_id, r));
MGCP.send(t_MGCP_SendToMrf(mrf, r));
}
}
}

View File

@ -230,7 +230,8 @@ function f_init_mgcp(charstring id) runs on MTC_CT {
callagent_ip := mp_msc_ip,
callagent_udp_port := -1,
mgw_ip := mp_mgw_ip,
mgw_udp_port := mp_mgw_port
mgw_udp_port := mp_mgw_port,
multi_conn_mode := false
}
vc_MGCP := MGCP_Emulation_CT.create(id);