mgcp parsing, mgcp test

Change-Id: Ibe2ab17b3fa3a506a2e841ba979ea4175e3a21e8
This commit is contained in:
Neels Hofmeyr
2016-10-18 18:38:59 +02:00
parent 7c8a62a940
commit 601002ad4c
11 changed files with 509 additions and 136 deletions

View File

@@ -8,12 +8,17 @@ enum mgcp_connection_mode;
struct msgb;
struct mgcpgw_client;
struct vty;
#define MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
#define MGCPGW_CLIENT_LOCAL_PORT_DEFAULT 0
#define MGCPGW_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
#define MGCPGW_CLIENT_REMOTE_PORT_DEFAULT 2427
#define MSGB_CB_MGCP_TRANS_ID 0
typedef unsigned int mgcp_trans_id_t;
struct mgcpgw_client_conf {
const char *local_addr;
int local_port;
@@ -23,12 +28,12 @@ struct mgcpgw_client_conf {
struct mgcp_response_head {
int response_code;
unsigned int trans_id;
mgcp_trans_id_t trans_id;
const char *comment;
};
struct mgcp_response {
char *data;
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
};
@@ -40,7 +45,7 @@ typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv)
struct mgcp_response_pending {
struct llist_head entry;
unsigned int trans_id;
mgcp_trans_id_t trans_id;
mgcp_response_cb_t response_cb;
void *priv;
};
@@ -50,6 +55,7 @@ void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf);
struct mgcpgw_client *mgcpgw_client_init(void *ctx,
struct mgcpgw_client_conf *conf);
int mgcpgw_client_connect(struct mgcpgw_client *mgcp);
const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp);
uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp);
@@ -59,26 +65,23 @@ unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
int mgcp_response_parse_params(struct mgcp_response *r);
int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode);
int mgcpgw_client_tx_mdcx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode);
int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv);
int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
unsigned int trans_id,
const char *fmt, ...);
int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
const char *buf, int len,
unsigned int trans_id);
int mgcpgw_client_tx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
struct msgb *msg, unsigned int trans_id);
struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode);
struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode);
void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf);
int mgcpgw_client_config_write(struct vty *vty, const char *indent);
struct mgcp_response_pending * mgcpgw_client_pending_add(
struct mgcpgw_client *mgcp,
mgcp_trans_id_t trans_id,
mgcp_response_cb_t response_cb,
void *priv);
int mgcpgw_client_rx(struct mgcpgw_client *mgcp, struct msgb *msg);

View File

@@ -9,6 +9,14 @@
#include <osmocom/gsm/gsm0411_smc.h>
#include <osmocom/gsm/gsm0411_smr.h>
enum bridge_state {
BRIDGE_STATE_NONE,
BRIDGE_STATE_LOOPBACK_PENDING,
BRIDGE_STATE_LOOPBACK_ESTABLISHED,
BRIDGE_STATE_BRIDGE_PENDING,
BRIDGE_STATE_BRIDGE_ESTABLISHED,
};
/* One transaction */
struct gsm_trans {
/* Entry in list of all transactions */
@@ -57,6 +65,11 @@ struct gsm_trans {
struct gsm_sms *sms;
} sms;
};
struct {
struct gsm_trans *peer;
enum bridge_state state;
} bridge;
};

View File

@@ -39,7 +39,7 @@ struct mgcpgw_client {
struct mgcpgw_client_conf actual;
uint32_t remote_addr;
struct osmo_wqueue wq;
unsigned int next_trans_id;
mgcp_trans_id_t next_trans_id;
uint16_t next_endpoint;
struct llist_head responses_pending;
};
@@ -64,8 +64,11 @@ static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp,
struct mgcp_response_pending *pending,
struct mgcp_response *response)
{
if (!pending)
if (!pending) {
LOGP(DMGCP, LOGL_ERROR,
"Cannot handle NULL response\n");
return;
}
if (pending->response_cb)
pending->response_cb(response, pending->priv);
else
@@ -76,18 +79,27 @@ static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp,
static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg)
{
int comment_pos;
char *end;
if (mgcp_msg_terminate_nul(msg))
goto response_parse_failure;
r->data = (char *)msg->data;
r->body = (char *)msg->data;
if (sscanf(r->data, "%3d %u %n",
if (sscanf(r->body, "%3d %u %n",
&r->head.response_code, &r->head.trans_id,
&comment_pos) != 2)
goto response_parse_failure;
r->head.comment = r->data + comment_pos;
r->head.comment = r->body + comment_pos;
end = strchr(r->head.comment, '\r');
if (!end)
goto response_parse_failure;
/* Mark the end of the comment */
*end = '\0';
r->body = end + 1;
if (r->body[0] == '\n')
r->body ++;
return 0;
response_parse_failure:
@@ -132,8 +144,22 @@ response_parse_failure:
int mgcp_response_parse_params(struct mgcp_response *r)
{
char *line;
char *data = r->data;
int rc;
OSMO_ASSERT(r->body);
char *data = strstr(r->body, "\n\n");
if (!data) {
LOGP(DMGCP, LOGL_ERROR,
"MGCP response: cannot find start of parameters\n");
return -EINVAL;
}
/* Advance to after the \n\n, replace the second \n with \0. That's
* where the parameters start. */
data ++;
*data = '\0';
data ++;
for_each_line(line, data) {
if (!mgcp_line_is_valid(line))
return -EINVAL;
@@ -168,9 +194,15 @@ static struct mgcp_response_pending *mgcpgw_client_response_pending_get(
return NULL;
}
static int mgcpgw_client_read(struct mgcpgw_client *mgcp, struct msgb *msg)
/* Feed an MGCP message into the receive processing.
* Parse the head and call any callback registered for the transaction id found
* in the MGCP message. This is normally called directly from the internal
* mgcp_do_read that reads from the socket connected to the MGCP gateway. This
* function is published mainly to be able to feed data from the test suite.
*/
int mgcpgw_client_rx(struct mgcpgw_client *mgcp, struct msgb *msg)
{
struct mgcp_response r;
struct mgcp_response r = { 0 };
struct mgcp_response_pending *pending;
int rc;
@@ -216,7 +248,7 @@ static int mgcp_do_read(struct osmo_fd *fd)
}
msg->l2h = msgb_put(msg, ret);
ret = mgcpgw_client_read(mgcp, msg);
ret = mgcpgw_client_rx(mgcp, msg);
talloc_free(msg);
return ret;
}
@@ -243,10 +275,7 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
struct mgcpgw_client *mgcpgw_client_init(void *ctx,
struct mgcpgw_client_conf *conf)
{
int on;
struct sockaddr_in addr;
struct mgcpgw_client *mgcp;
struct osmo_wqueue *wq;
mgcp = talloc_zero(ctx, struct mgcpgw_client);
@@ -265,12 +294,27 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port :
MGCPGW_CLIENT_REMOTE_PORT_DEFAULT;
return mgcp;
}
int mgcpgw_client_connect(struct mgcpgw_client *mgcp)
{
int on;
struct sockaddr_in addr;
struct osmo_wqueue *wq;
int rc;
if (!mgcp) {
LOGP(DMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");
return -EINVAL;
}
wq = &mgcp->wq;
wq->bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (wq->bfd.fd < 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
goto error_free;
return -errno;
}
on = 1;
@@ -278,6 +322,7 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
LOGP(DMGCP, LOGL_FATAL,
"Failed to initialize socket for MGCP GW: %s\n",
strerror(errno));
rc = -errno;
goto error_close_fd;
}
@@ -290,6 +335,7 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
LOGP(DMGCP, LOGL_FATAL,
"Failed to bind for MGCP GW to %s %u\n",
mgcp->actual.local_addr, mgcp->actual.local_port);
rc = -errno;
goto error_close_fd;
}
@@ -301,6 +347,7 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
"Failed to connect to MGCP GW at %s %u: %s\n",
mgcp->actual.remote_addr, mgcp->actual.remote_port,
strerror(errno));
rc = -errno;
goto error_close_fd;
}
@@ -314,19 +361,18 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
if (osmo_fd_register(&wq->bfd) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
rc = -EIO;
goto error_close_fd;
}
LOGP(DMGCP, LOGL_INFO, "MGCP GW connection: %s:%u -> %s:%u\n",
mgcp->actual.local_addr, mgcp->actual.local_port,
mgcp->actual.remote_addr, mgcp->actual.remote_port);
return mgcp;
return 0;
error_close_fd:
close(wq->bfd.fd);
wq->bfd.fd = -1;
error_free:
talloc_free(mgcp);
return NULL;
return rc;
}
const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp)
@@ -345,12 +391,13 @@ uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp)
return mgcp->remote_addr;
}
int mgcpgw_client_tx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
struct msgb *msg, unsigned int trans_id)
struct mgcp_response_pending * mgcpgw_client_pending_add(
struct mgcpgw_client *mgcp,
mgcp_trans_id_t trans_id,
mgcp_response_cb_t response_cb,
void *priv)
{
struct mgcp_response_pending *pending;
int rc;
pending = talloc_zero(mgcp, struct mgcp_response_pending);
pending->trans_id = trans_id;
@@ -358,6 +405,31 @@ int mgcpgw_client_tx(struct mgcpgw_client *mgcp,
pending->priv = priv;
llist_add_tail(&pending->entry, &mgcp->responses_pending);
return pending;
}
/* Send the MGCP message in msg to the MGCP GW and handle a response with
* response_cb. NOTE: the response_cb still needs to call
* mgcp_response_parse_params(response) to get the parsed parameters -- to
* potentially save some CPU cycles, only the head line has been parsed when
* the response_cb is invoked. */
int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv)
{
struct mgcp_response_pending *pending;
mgcp_trans_id_t trans_id;
int rc;
trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
if (!trans_id) {
LOGP(DMGCP, LOGL_ERROR,
"Unset transaction id in mgcp send request\n");
talloc_free(msg);
return -EINVAL;
}
pending = mgcpgw_client_pending_add(mgcp, trans_id, response_cb, priv);
if (msgb_l2len(msg) > 4096) {
LOGP(DMGCP, LOGL_ERROR,
"Cannot send, MGCP message too large: %u\n",
@@ -383,35 +455,32 @@ mgcp_tx_error:
return -1;
}
int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
const char *buf, int len,
unsigned int trans_id)
static struct msgb *mgcp_msg_from_buf(mgcp_trans_id_t trans_id,
const char *buf, int len)
{
struct msgb *msg;
if (len > (4096 - 128)) {
LOGP(DMGCP, LOGL_ERROR, "Cannot send to MGCP GW:"
" message too large: %d\n", len);
return -ENOTSUP;
return NULL;
}
msg = msgb_alloc_headroom(4096, 128, "MGCP Tx");
msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
OSMO_ASSERT(msg);
char *dst = (char*)msgb_put(msg, len);
memcpy(dst, buf, len);
msg->l2h = msg->data;
msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
return mgcpgw_client_tx(mgcp, response_cb, priv, msg, trans_id);
return msg;
}
int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
unsigned int trans_id,
const char *fmt, ...)
static struct msgb *mgcp_msg_from_str(mgcp_trans_id_t trans_id,
const char *fmt, ...)
{
char compose[4096 - 128];
static char compose[4096 - 128];
va_list ap;
int len;
OSMO_ASSERT(fmt);
@@ -419,21 +488,35 @@ int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp,
va_start(ap, fmt);
len = vsnprintf(compose, sizeof(compose), fmt, ap);
va_end(ap);
if (len >= sizeof(compose))
return -EMSGSIZE;
if (len < 1)
return -EIO;
return mgcpgw_client_tx_buf(mgcp, response_cb, priv, compose, len, trans_id);
if (len >= sizeof(compose)) {
LOGP(DMGCP, LOGL_ERROR,
"Message too large: trans_id=%u len=%d\n",
trans_id, len);
return NULL;
}
if (len < 1) {
LOGP(DMGCP, LOGL_ERROR,
"Failed to compose message: trans_id=%u len=%d\n",
trans_id, len);
return NULL;
}
return mgcp_msg_from_buf(trans_id, compose, len);
}
int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode)
static mgcp_trans_id_t mgcpgw_client_next_trans_id(struct mgcpgw_client *mgcp)
{
unsigned int trans_id = mgcp->next_trans_id ++;
return mgcpgw_client_tx_str(mgcp,
response_cb, priv, trans_id,
/* avoid zero trans_id to distinguish from unset trans_id */
if (!mgcp->next_trans_id)
mgcp->next_trans_id ++;
return mgcp->next_trans_id ++;
}
struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode)
{
mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
return mgcp_msg_from_str(trans_id,
"CRCX %u %x@mgw MGCP 1.0\r\n"
"C: %x\r\n"
"L: p:20, a:AMR, nt:IN\r\n"
@@ -445,15 +528,13 @@ int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp,
mgcp_cmode_name(mode));
}
int mgcpgw_client_tx_mdcx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode)
struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode)
{
unsigned int trans_id = mgcp->next_trans_id ++;
return mgcpgw_client_tx_str(mgcp,
response_cb, priv, trans_id,
mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
return mgcp_msg_from_str(trans_id,
"MDCX %u %x@mgw MGCP 1.0\r\n"
"M: %s\r\n"
"\r\n"

View File

@@ -110,27 +110,35 @@ int msc_tx_common_id(struct gsm_subscriber_connection *conn)
}
#ifdef BUILD_IU
static int iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
uint32_t rtp_ip, uint16_t rtp_port)
static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
uint32_t rtp_ip, uint16_t rtp_port)
{
struct msgb *msg;
bool use_x213_nsap;
uint32_t conn_id = uectx->conn_id;
use_x213_nsap = (uectx->rab_assign_addr_enc == NSAP_ADDR_ENC_X213);
LOGP(DIUCS, LOGL_DEBUG, "Assigning RAB: rab_id=%d, rtp=%x:%u,"
" use_x213_nsap=%d\n", rab_id, rtp_ip, rtp_port, use_x213_nsap);
LOGP(DIUCS, LOGL_DEBUG, "Assigning RAB: conn_id=%u, rab_id=%d,"
" rtp=%x:%u, use_x213_nsap=%d\n", conn_id, rab_id, rtp_ip,
rtp_port, use_x213_nsap);
msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
use_x213_nsap);
msg->l2h = msg->data;
return iu_rab_act(uectx, msg);
if (iu_rab_act(uectx, msg))
LOGP(DIUCS, LOGL_ERROR, "Failed to send RAB Assignment:"
" conn_id=%d rab_id=%d rtp=%x:%u\n",
conn_id, rab_id, rtp_ip, rtp_port);
}
static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
{
struct gsm_trans *trans = priv;
struct gsm_subscriber_connection *conn = trans->conn;
struct ue_conn_ctx *uectx = conn->iu.ue_ctx;
uint32_t rtp_ip;
int rc;
if (r->head.response_code != 200) {
@@ -148,6 +156,10 @@ static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
goto rab_act_cs_error;
}
rtp_ip = mgcpgw_client_remote_addr_n(conn->network->mgcpgw.client);
iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip,
conn->iu.mgcp_rtp_port_ue);
/* use_x213_nsap == 0 for ip.access nano3G */
rab_act_cs_error:
/* FIXME abort call, invalidate conn, ... */
@@ -157,7 +169,8 @@ rab_act_cs_error:
static int conn_iu_rab_act_cs(struct gsm_trans *trans)
{
struct gsm_subscriber_connection *conn = trans->conn;
struct ue_conn_ctx *uectx = conn->iu.ue_ctx;
struct mgcpgw_client *mgcp = conn->network->mgcpgw.client;
struct msgb *msg;
/* HACK. where to scope the RAB Id? At the conn / subscriber /
* ue_conn_ctx? */
@@ -174,17 +187,9 @@ static int conn_iu_rab_act_cs(struct gsm_trans *trans)
/* Establish the RTP stream first as looping back to the originator.
* The MDCX will patch through to the counterpart. TODO: play a ring
* tone instead. */
mgcpgw_client_tx_crcx(conn->network->mgcpgw.client,
mgcp_response_rab_act_cs_crcx, trans,
conn->iu.mgcp_rtp_endpoint, trans->callref,
MGCP_CONN_LOOPBACK);
uint32_t rtp_ip =
mgcpgw_client_remote_addr_n(conn->network->mgcpgw.client);
return iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip,
conn->iu.mgcp_rtp_port_ue);
/* use_x213_nsap == 0 for ip.access nano3G */
msg = mgcp_msg_crcx(mgcp, conn->iu.mgcp_rtp_endpoint, trans->callref,
MGCP_CONN_LOOPBACK);
return mgcpgw_client_tx(mgcp, msg, mgcp_response_rab_act_cs_crcx, trans);
}
#endif
@@ -217,44 +222,85 @@ int msc_call_assignment(struct gsm_trans *trans)
}
}
static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv);
static void mgcp_bridge(struct gsm_trans *from, struct gsm_trans *to,
enum bridge_state state,
enum mgcp_connection_mode mode)
{
struct gsm_subscriber_connection *conn1 = from->conn;
struct gsm_subscriber_connection *conn2 = to->conn;
struct mgcpgw_client *mgcp = conn1->network->mgcpgw.client;
const char *ip;
struct msgb *msg;
OSMO_ASSERT(mgcp);
from->bridge.peer = to;
from->bridge.state = state;
/* Loop back to the same MGCP GW */
ip = mgcpgw_client_remote_addr_str(mgcp);
msg = mgcp_msg_mdcx(mgcp,
conn1->iu.mgcp_rtp_endpoint,
ip, conn2->iu.mgcp_rtp_port_cn,
mode);
if (mgcpgw_client_tx(mgcp, msg, mgcp_response_bridge_mdcx, from))
LOGP(DMGCP, LOGL_ERROR,
"Failed to send MDCX message for %s\n",
subscr_name(from->subscr));
}
static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv)
{
/* TODO */
struct gsm_trans *trans = priv;
struct gsm_trans *peer = trans->bridge.peer;
switch (trans->bridge.state) {
case BRIDGE_STATE_LOOPBACK_PENDING:
trans->bridge.state = BRIDGE_STATE_LOOPBACK_ESTABLISHED;
switch (peer->bridge.state) {
case BRIDGE_STATE_LOOPBACK_PENDING:
/* Wait until the other is done as well. */
return;
case BRIDGE_STATE_LOOPBACK_ESTABLISHED:
/* Now that both are in loopback, switch both to
* forwarding. */
mgcp_bridge(trans, peer, BRIDGE_STATE_BRIDGE_PENDING,
MGCP_CONN_RECV_SEND);
mgcp_bridge(peer, trans, BRIDGE_STATE_BRIDGE_PENDING,
MGCP_CONN_RECV_SEND);
break;
default:
LOGP(DMGCP, LOGL_ERROR,
"Unexpected bridge state: %d for %s\n",
trans->bridge.state, subscr_name(trans->subscr));
break;
}
case BRIDGE_STATE_BRIDGE_PENDING:
trans->bridge.state = BRIDGE_STATE_BRIDGE_ESTABLISHED;
break;
default:
LOGP(DMGCP, LOGL_ERROR,
"Unexpected bridge state: %d for %s\n",
trans->bridge.state, subscr_name(trans->subscr));
break;
}
}
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2)
{
struct gsm_subscriber_connection *conn1 = trans1->conn;
struct gsm_subscriber_connection *conn2 = trans2->conn;
struct mgcpgw_client *mgcp = conn1->network->mgcpgw.client;
OSMO_ASSERT(mgcp);
const char *ip = mgcpgw_client_remote_addr_str(mgcp);
/* First setup the counterparts' endpoints, so that when transmission
* starts the originating addresses are already known to be valid. */
mgcpgw_client_tx_mdcx(mgcp,
mgcp_response_bridge_mdcx, trans1,
conn1->iu.mgcp_rtp_endpoint,
ip, conn2->iu.mgcp_rtp_port_cn,
MGCP_CONN_LOOPBACK);
mgcpgw_client_tx_mdcx(mgcp,
mgcp_response_bridge_mdcx, trans2,
conn2->iu.mgcp_rtp_endpoint,
ip, conn1->iu.mgcp_rtp_port_cn,
MGCP_CONN_LOOPBACK);
/* Now enable sending to and receiving from the peer. */
mgcpgw_client_tx_mdcx(mgcp,
mgcp_response_bridge_mdcx, trans1,
conn1->iu.mgcp_rtp_endpoint,
ip, conn2->iu.mgcp_rtp_port_cn,
MGCP_CONN_RECV_SEND);
mgcpgw_client_tx_mdcx(mgcp,
mgcp_response_bridge_mdcx, trans2,
conn2->iu.mgcp_rtp_endpoint,
ip, conn1->iu.mgcp_rtp_port_cn,
MGCP_CONN_RECV_SEND);
/* First setup as loopback and configure the counterparts' endpoints,
* so that when transmission starts the originating addresses are
* already known to be valid. The callback will continue. */
mgcp_bridge(trans1, trans2, BRIDGE_STATE_LOOPBACK_PENDING,
MGCP_CONN_LOOPBACK);
mgcp_bridge(trans2, trans1, BRIDGE_STATE_LOOPBACK_PENDING,
MGCP_CONN_LOOPBACK);
return 0;
}

View File

@@ -459,9 +459,6 @@ TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_i
/* TODO: is this used for crypto?? Improve randomness, at least we
* should try to use the nanoseconds part of the current time. */
msc_network->mgcpgw.client = mgcpgw_client_init(
msc_network, &msc_network->mgcpgw.conf);
if (db_init(msc_cmdline_config.database_name)) {
printf("DB: Failed to init database: %s\n",
msc_cmdline_config.database_name);
@@ -506,6 +503,14 @@ TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_i
if (sms_queue_start(msc_network, 20) != 0)
return -1;
msc_network->mgcpgw.client = mgcpgw_client_init(
msc_network, &msc_network->mgcpgw.conf);
if (mgcpgw_client_connect(msc_network->mgcpgw.client)) {
printf("MGCPGW connect failed\n");
return 7;
}
/* Set up A-Interface */
/* TODO: implement A-Interface and remove above legacy stuff. */

View File

@@ -264,16 +264,17 @@ void vlr_proc_acc_req() {}
void vlr_init() {}
unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
{ return 0; }
int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode)
{ return -ENOTSUP; }
int mgcpgw_client_tx_mdcx(struct mgcpgw_client *mgcp,
mgcp_response_cb_t response_cb, void *priv,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode)
{ return -ENOTSUP; }
struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode)
{ return NULL; }
struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode)
{ return NULL; }
int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv)
{ return -EINVAL; }
const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp)
{ return "0.0.0.0"; }
uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp)

View File

@@ -22,10 +22,12 @@ AM_LDFLAGS = \
EXTRA_DIST = \
mgcp_test.ok \
mgcp_transcoding_test.ok \
mgcpgw_client_test.ok \
$(NULL)
noinst_PROGRAMS = \
mgcp_test \
mgcpgw_client_test \
$(NULL)
if BUILD_MGCP_TRANSCODING
noinst_PROGRAMS += \
@@ -70,3 +72,21 @@ mgcp_transcoding_test_LDADD = \
-lrt \
-lm \
$(NULL)
mgcpgw_client_test_SOURCES = \
mgcpgw_client_test.c \
$(NULL)
mgcpgw_client_test_LDADD = \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmgcp/libmgcp.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOSCCP_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBRARY_DL) \
$(LIBOSMONETIF_LIBS) \
-lrt \
-lm \
$(NULL)

View File

@@ -0,0 +1,165 @@
/*
* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/application.h>
#include <openbsc/mgcp.h>
#include <openbsc/mgcpgw_client.h>
void *ctx;
#define buf_len 4096
#if 0
static struct msgb *from_hex(const char *hex)
{
struct msgb *msg = msgb_alloc(buf_len, "mgcpgw_test_from_hex");
unsigned int l = osmo_hexparse(hex, msg->data, buf_len);
msg->l2h = msgb_put(msg, l);
return msg;
}
static struct msgb *mgcp_from_str(const char *head, const char *params)
{
struct msgb *msg = msgb_alloc(buf_len, "mgcp_from_str");
unsigned int l;
char *data;
l = strlen(head);
msg->l2h = msgb_put(msg, l);
data = (char*)msgb_l2(msg);
strncpy(data, head, l);
data = (char*)msgb_put(msg, 1);
*data = '\n';
l = strlen(params);
data = (char*)msgb_put(msg, l);
strncpy(data, params, l);
return msg;
}
#endif
static struct msgb *from_str(const char *str)
{
struct msgb *msg = msgb_alloc(buf_len, "from_str");
unsigned int l = strlen(str);
char *data;
msg->l2h = msgb_put(msg, l);
data = (char*)msgb_l2(msg);
strncpy(data, str, l);
return msg;
}
static struct mgcpgw_client_conf conf;
struct mgcpgw_client *mgcp = NULL;
static void reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
int conn_id, const char *params)
{
static char compose[4096 - 128];
int len;
len = snprintf(compose, sizeof(compose),
"%d %u %s\r\nI: %d\n\n%s",
code, trans_id, comment, conn_id, params);
OSMO_ASSERT(len < sizeof(compose));
OSMO_ASSERT(len > 0);
printf("composed response:\n-----\n%s\n-----\n",
compose);
mgcpgw_client_rx(mgcp, from_str(compose));
}
void test_response_cb(struct mgcp_response *response, void *priv)
{
OSMO_ASSERT(priv == mgcp);
mgcp_response_parse_params(response);
printf("response cb received:\n"
" head.response_code = %d\n"
" head.trans_id = %u\n"
" head.comment = %s\n"
" audio_port = %u\n",
response->head.response_code,
response->head.trans_id,
response->head.comment,
response->audio_port
);
}
mgcp_trans_id_t dummy_mgcp_send(struct msgb *msg)
{
mgcp_trans_id_t trans_id;
trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
char *end;
OSMO_ASSERT(mgcpgw_client_pending_add(mgcp, trans_id, test_response_cb, mgcp));
end = msgb_put(msg, 1);
*end = '\0';
printf("composed:\n-----\n%s\n-----\n",
(char*)msgb_l2(msg));
talloc_free(msg);
return trans_id;
}
void test_crcx(void)
{
struct msgb *msg;
mgcp_trans_id_t trans_id;
printf("\n===== %s =====\n", __func__);
if (mgcp)
talloc_free(mgcp);
mgcp = mgcpgw_client_init(ctx, &conf);
msg = mgcp_msg_crcx(mgcp, 23, 42, MGCP_CONN_LOOPBACK);
trans_id = dummy_mgcp_send(msg);
reply_to(trans_id, 200, "OK", 1,
"v=0\r\n"
"o=- 1 23 IN IP4 10.9.1.120\r\n"
"s=-\r\n"
"c=IN IP4 10.9.1.120\r\n"
"t=0 0\r\n"
"m=audio 16002 RTP/AVP 98\r\n"
"a=rtpmap:98 AMR/8000\r\n"
"a=ptime:20\r\n");
}
int main(int argc, char **argv)
{
ctx = talloc_named_const(NULL, 1, "mgcpgw_client_test");
msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging(&log_info);
mgcpgw_client_conf_init(&conf);
test_crcx();
printf("Done\n");
fprintf(stderr, "Done\n");
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1 @@
Done

View File

@@ -0,0 +1,31 @@
===== test_crcx =====
composed:
-----
CRCX 1 17@mgw MGCP 1.0
C: 2a
L: p:20, a:AMR, nt:IN
M: loopback
-----
composed response:
-----
200 1 OK
I: 1
v=0
o=- 1 23 IN IP4 10.9.1.120
s=-
c=IN IP4 10.9.1.120
t=0 0
m=audio 16002 RTP/AVP 98
a=rtpmap:98 AMR/8000
a=ptime:20
-----
response cb received:
head.response_code = 200
head.trans_id = 1
head.comment = OK
audio_port = 16002
Done

View File

@@ -33,6 +33,13 @@ cat $abs_srcdir/mgcp/mgcp_transcoding_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_transcoding_test], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([mgcpgw_client])
AT_KEYWORDS([mgcpgw_client])
cat $abs_srcdir/mgcp/mgcpgw_client_test.ok > expout
cat $abs_srcdir/mgcp/mgcpgw_client_test.err > experr
AT_CHECK([$abs_top_builddir/tests/mgcp/mgcpgw_client_test], [], [expout], [experr])
AT_CLEANUP
AT_SETUP([gprs])
AT_KEYWORDS([gprs])
cat $abs_srcdir/gprs/gprs_test.ok > expout