aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-08-05 08:08:17 +0800
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-08-05 08:08:17 +0800
commitf138f917ec7b535e0d71b8e70c71be7816e572da (patch)
tree0eeb40a4776413600697b0fef3114761a752ed46
parent1be9f2fddcfd9ba02f9f3a8203fa79b3b4e9b3e2 (diff)
mgcp: Allow to dynamically allocate ports from a range..
Allow to switch to a dynamic port allocator and not reuse the ports for a long time... This should help with a crazy network sending two streams at the same time.
-rw-r--r--openbsc/include/openbsc/mgcp_internal.h2
-rw-r--r--openbsc/src/mgcp/mgcp_network.c22
-rw-r--r--openbsc/src/mgcp/mgcp_protocol.c64
-rw-r--r--openbsc/src/mgcp/mgcp_vty.c2
4 files changed, 83 insertions, 7 deletions
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 6c236735f..92e5f9955 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -66,6 +66,7 @@ struct mgcp_rtp_end {
struct bsc_fd rtcp;
int local_port;
+ int local_alloc;
};
struct mgcp_endpoint {
@@ -100,5 +101,6 @@ 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_free_rtp_port(struct mgcp_rtp_end *end);
#endif
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
index 729a89c95..ea95c6182 100644
--- a/openbsc/src/mgcp/mgcp_network.c
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -394,3 +394,25 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
endp->net_end.rtcp.cb = rtp_data_net;
return bind_rtp(endp->cfg, &endp->net_end, ENDPOINT_NUMBER(endp));
}
+
+int mgcp_free_rtp_port(struct mgcp_rtp_end *end)
+{
+ if (end->local_alloc != PORT_ALLOC_DYNAMIC) {
+ LOGP(DMGCP, LOGL_ERROR, "Should only be called for dynamic ports.\n");
+ return -1;
+ }
+
+ if (end->rtp.fd != -1) {
+ close(end->rtp.fd);
+ end->rtp.fd = -1;
+ bsc_unregister_fd(&end->rtp);
+ }
+
+ if (end->rtcp.fd != -1) {
+ close(end->rtcp.fd);
+ end->rtcp.fd = -1;
+ bsc_unregister_fd(&end->rtcp);
+ }
+
+ return 0;
+}
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
index ba0ae8d8e..1d2b6607c 100644
--- a/openbsc/src/mgcp/mgcp_protocol.c
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -72,6 +72,7 @@
} \
}
+static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
struct mgcp_request {
char *name;
@@ -367,6 +368,54 @@ static int parse_conn_mode(const char* msg, int *conn_mode)
return ret;
}
+static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
+ struct mgcp_port_range *range, int for_net)
+{
+ int i;
+
+ if (range->mode == PORT_ALLOC_STATIC) {
+ end->local_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), range->base_port);
+ end->local_alloc = PORT_ALLOC_STATIC;
+ return 0;
+ }
+
+ /* attempt to find a port */
+ for (i = 0; i < 200; ++i) {
+ int rc;
+
+ 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);
+
+ range->last_port += 2;
+ if (rc == 0) {
+ end->local_alloc = PORT_ALLOC_DYNAMIC;
+ return 0;
+ }
+
+ }
+
+ LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x net: %d\n",
+ ENDPOINT_NUMBER(endp), for_net);
+ return -1;
+}
+
+static int allocate_ports(struct mgcp_endpoint *endp)
+{
+ if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports, 0) != 0)
+ return -1;
+
+ if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports, 1) != 0) {
+ mgcp_rtp_end_reset(&endp->net_end);
+ return -1;
+ }
+
+ return 0;
+}
+
static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
{
struct mgcp_msg_ptr data_ptrs[6];
@@ -374,7 +423,6 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
- int port;
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
@@ -427,11 +475,8 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
/* bind to the port now */
- port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->bts_ports.base_port);
- endp->bts_end.local_port = port;
-
- port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->net_ports.base_port);
- endp->net_end.local_port = port;
+ if (allocate_ports(endp) != 0)
+ goto error2;
/* assign a local call identifier or fail */
endp->ci = generate_call_id(cfg);
@@ -470,6 +515,7 @@ error:
LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
hexdump(msg->l3h, msgb_l3len(msg)),
ENDPOINT_NUMBER(endp), line_start, i);
+ mgcp_free_endp(endp);
return create_response(error_code, "CRCX", trans_id);
error2:
@@ -719,10 +765,14 @@ struct mgcp_config *mgcp_config_alloc(void)
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
{
+ if (end->local_alloc == PORT_ALLOC_DYNAMIC)
+ mgcp_free_rtp_port(end);
+
end->packets = 0;
memset(&end->addr, 0, sizeof(end->addr));
- end->rtp_port = end->rtcp_port = end->local_port;
+ end->rtp_port = end->rtcp_port = end->local_port = 0;
end->payload_type = -1;
+ end->local_alloc = -1;
}
static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index d8f611961..f3b5f458a 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -377,6 +377,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
return -1;
}
+ endp->bts_end.local_alloc = PORT_ALLOC_STATIC;
}
if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC) {
@@ -386,6 +387,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
return -1;
}
+ endp->net_end.local_alloc = PORT_ALLOC_STATIC;
}
}