mgcp: Forward data from the BTS-in to the transcoder

Bind a new port for the transcoder, forward data from the BTS
to the transcoder, and from the transcoder to the network. Leave
BTS-IN where it is, BTS-OUT can now be after the transcoding took
place. We send the data from the BTS RTP port.

This whole route will be guarded by the transcoder_ip and if it is
NULL (current default) it will not go through the transcoder.
This commit is contained in:
Holger Hans Peter Freyther 2010-09-18 02:30:02 +08:00
parent 54aaa0fbed
commit 218f8564e1
4 changed files with 128 additions and 8 deletions

View File

@ -98,6 +98,7 @@ struct mgcp_endpoint {
/* port status for bts/net */
struct mgcp_rtp_end bts_end;
struct mgcp_rtp_end net_end;
struct mgcp_rtp_end transcoder_end;
/* sequence bits */
struct mgcp_rtp_state net_state;
@ -123,6 +124,7 @@ int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
int mgcp_send_dummy(struct mgcp_endpoint *endp);
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_bind_transcoder_rtp_port(struct mgcp_endpoint *enp, int rtp_port);
int mgcp_free_rtp_port(struct mgcp_rtp_end *end);
#endif

View File

@ -159,6 +159,42 @@ static int forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf, int l
return sendto(fd, buf, len, 0,
(struct sockaddr *)&tap->forward, sizeof(tap->forward));
}
static int send_transcoder(struct mgcp_endpoint *endp, int is_rtp,
const char *buf, int len)
{
int rc;
int port;
struct mgcp_config *cfg = endp->cfg;
struct sockaddr_in addr;
if (endp->transcoder_end.rtp_port == 0) {
LOGP(DMGCP, LOGL_ERROR, "Transcoder port not known on 0x%x\n",
ENDPOINT_NUMBER(endp));
return -1;
}
port = rtp_calculate_port(ENDPOINT_NUMBER(endp), 4000);
if (!is_rtp)
port += 1;
addr.sin_family = AF_INET;
addr.sin_addr = cfg->transcoder_in;
addr.sin_port = htons(port);
rc = sendto(is_rtp ?
endp->bts_end.rtp.fd :
endp->bts_end.rtcp.fd, buf, len, 0,
(struct sockaddr *) &addr, sizeof(addr));
if (rc != len)
LOGP(DMGCP, LOGL_ERROR,
"Failed to send data to the transcoder: %s\n",
strerror(errno));
return rc;
}
static int send_to(struct mgcp_endpoint *endp, int dest, int is_rtp,
struct sockaddr_in *addr, char *buf, int rc)
{
@ -339,6 +375,51 @@ static int rtp_data_bts(struct bsc_fd *fd, unsigned int what)
endp->bts_end.packets += 1;
forward_data(fd->fd, &endp->taps[MGCP_TAP_BTS_IN], buf, rc);
if (cfg->transcoder_ip)
return send_transcoder(endp, proto == PROTO_RTP, &buf[0], rc);
else
return send_to(endp, DEST_NETWORK, proto == PROTO_RTP, &addr, &buf[0], rc);
}
static int rtp_data_transcoder(struct bsc_fd *fd, unsigned int what)
{
char buf[4096];
struct sockaddr_in addr;
struct mgcp_endpoint *endp;
struct mgcp_config *cfg;
int rc, proto;
endp = (struct mgcp_endpoint *) fd->data;
cfg = endp->cfg;
rc = recevice_from(endp, fd->fd, &addr, buf, sizeof(buf));
if (rc <= 0)
return -1;
proto = fd == &endp->transcoder_end.rtp ? PROTO_RTP : PROTO_RTCP;
if (memcmp(&addr.sin_addr, &cfg->transcoder_in, sizeof(addr.sin_addr)) != 0) {
LOGP(DMGCP, LOGL_ERROR,
"Data not coming from transcoder: %s on 0x%x\n",
inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
return -1;
}
if (endp->transcoder_end.rtp_port != addr.sin_port &&
endp->transcoder_end.rtcp_port != addr.sin_port) {
LOGP(DMGCP, LOGL_ERROR,
"Data from wrong transcoder source port %d on 0x%x\n",
ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
return -1;
}
/* throw away the dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from transcoder on 0x%x\n",
ENDPOINT_NUMBER(endp));
return 0;
}
return send_to(endp, DEST_NETWORK, proto == PROTO_RTP, &addr, &buf[0], rc);
}
@ -453,6 +534,22 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
return bind_rtp(endp->cfg, &endp->net_end, ENDPOINT_NUMBER(endp));
}
int mgcp_bind_transcoder_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
{
if (endp->transcoder_end.rtp.fd != -1 || endp->transcoder_end.rtcp.fd != -1) {
LOGP(DMGCP, LOGL_ERROR, "Previous net-port was still bound on %d\n",
ENDPOINT_NUMBER(endp));
mgcp_free_rtp_port(&endp->transcoder_end);
}
endp->transcoder_end.local_port = rtp_port;
endp->transcoder_end.rtp.cb = rtp_data_transcoder;
endp->transcoder_end.rtp.data = endp;
endp->transcoder_end.rtcp.data = endp;
endp->transcoder_end.rtcp.cb = rtp_data_transcoder;
return bind_rtp(endp->cfg, &endp->transcoder_end, ENDPOINT_NUMBER(endp));
}
int mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp.fd != -1) {

View File

@ -373,7 +373,8 @@ static int parse_conn_mode(const char *msg, int *conn_mode)
}
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
struct mgcp_port_range *range, int for_net)
struct mgcp_port_range *range,
int (*alloc)(struct mgcp_endpoint *endp, int port))
{
int i;
@ -390,9 +391,7 @@ static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
if (range->last_port >= range->range_end)
range->last_port = range->range_start;
rc = for_net ?
mgcp_bind_net_rtp_port(endp, range->last_port) :
mgcp_bind_bts_rtp_port(endp, range->last_port);
rc = alloc(endp, range->last_port);
range->last_port += 2;
if (rc == 0) {
@ -402,21 +401,31 @@ static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
}
LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x net: %d\n",
ENDPOINT_NUMBER(endp), for_net);
LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
ENDPOINT_NUMBER(endp));
return -1;
}
static int allocate_ports(struct mgcp_endpoint *endp)
{
if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports, 1) != 0)
if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
mgcp_bind_net_rtp_port) != 0)
return -1;
if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports, 0) != 0) {
if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
mgcp_bind_bts_rtp_port) != 0) {
mgcp_rtp_end_reset(&endp->net_end);
return -1;
}
if (endp->cfg->transcoder_ip &&
allocate_port(endp, &endp->transcoder_end, &endp->cfg->transcoder_ports,
mgcp_bind_transcoder_rtp_port) != 0) {
mgcp_rtp_end_reset(&endp->net_end);
mgcp_rtp_end_reset(&endp->bts_end);
return -1;
}
return 0;
}
@ -805,6 +814,7 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg)
cfg->endpoints[i].cfg = cfg;
mgcp_rtp_end_init(&cfg->endpoints[i].net_end);
mgcp_rtp_end_init(&cfg->endpoints[i].bts_end);
mgcp_rtp_end_init(&cfg->endpoints[i].transcoder_end);
}
return 0;
@ -828,6 +838,7 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
mgcp_rtp_end_reset(&endp->bts_end);
mgcp_rtp_end_reset(&endp->net_end);
mgcp_rtp_end_reset(&endp->transcoder_end);
memset(&endp->net_state, 0, sizeof(endp->net_state));
memset(&endp->bts_state, 0, sizeof(endp->bts_state));

View File

@ -505,6 +505,16 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
}
endp->net_end.local_alloc = PORT_ALLOC_STATIC;
}
if (g_cfg->transcoder_ip && g_cfg->transcoder_ports.mode == PORT_ALLOC_STATIC) {
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
g_cfg->transcoder_ports.base_port);
if (mgcp_bind_transcoder_rtp_port(endp, rtp_port) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
return -1;
}
endp->transcoder_end.local_alloc = PORT_ALLOC_STATIC;
}
}
return 0;