From f138f917ec7b535e0d71b8e70c71be7816e572da Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 5 Aug 2010 08:08:17 +0800 Subject: 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. --- openbsc/include/openbsc/mgcp_internal.h | 2 ++ openbsc/src/mgcp/mgcp_network.c | 22 ++++++++++++ openbsc/src/mgcp/mgcp_protocol.c | 64 +++++++++++++++++++++++++++++---- openbsc/src/mgcp/mgcp_vty.c | 2 ++ 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; } } -- cgit v1.2.3