aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmgcp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmgcp')
-rw-r--r--src/libmgcp/mgcp_protocol.c44
-rw-r--r--src/libmgcp/mgcpgw_client.c95
-rw-r--r--src/libmgcp/mgcpgw_client_vty.c51
3 files changed, 175 insertions, 15 deletions
diff --git a/src/libmgcp/mgcp_protocol.c b/src/libmgcp/mgcp_protocol.c
index 96542c5a0..c8b6e8660 100644
--- a/src/libmgcp/mgcp_protocol.c
+++ b/src/libmgcp/mgcp_protocol.c
@@ -66,6 +66,45 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp);
static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
+/* Display an mgcp message on the log output */
+void display_mgcp_message(unsigned char *message, unsigned int len,
+ char *preamble)
+{
+ unsigned char line[80];
+ unsigned char *ptr;
+ unsigned int consumed = 0;
+ unsigned int consumed_line = 0;
+ unsigned int line_count = 0;
+
+ if (!log_check_level(DMGCP, LOGL_DEBUG))
+ return;
+
+ while (1) {
+ memset(line, 0, sizeof(line));
+ ptr = line;
+ consumed_line = 0;
+ do {
+ if (*message != '\n' && *message != '\r') {
+ *ptr = *message;
+ ptr++;
+ }
+ message++;
+ consumed++;
+ consumed_line++;
+ } while (*message != '\n' && consumed < len
+ && consumed_line < sizeof(line));
+
+ if (strlen((const char *)line)) {
+ LOGP(DMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
+ preamble, line_count, line);
+ line_count++;
+ }
+
+ if (consumed >= len)
+ return;
+ }
+}
+
static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
{
const size_t line_len = strlen(line);
@@ -157,7 +196,8 @@ static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
}
res->l2h = msgb_put(res, len);
- LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
+ LOGP(DMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
+ display_mgcp_message(res->l2h, msgb_l2len(res), "Generated response");
/*
* Remember the last transmission per endpoint.
@@ -329,6 +369,8 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
if (mgcp_msg_terminate_nul(msg))
return NULL;
+ display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
+
/* attempt to treat it as a response */
if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
diff --git a/src/libmgcp/mgcpgw_client.c b/src/libmgcp/mgcpgw_client.c
index 9f0c84de2..1910a9f35 100644
--- a/src/libmgcp/mgcpgw_client.c
+++ b/src/libmgcp/mgcpgw_client.c
@@ -35,15 +35,6 @@
#include <unistd.h>
#include <string.h>
-struct mgcpgw_client {
- struct mgcpgw_client_conf actual;
- uint32_t remote_addr;
- struct osmo_wqueue wq;
- mgcp_trans_id_t next_trans_id;
- uint16_t next_endpoint;
- struct llist_head responses_pending;
-};
-
void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf)
{
/* NULL and -1 default to MGCPGW_CLIENT_*_DEFAULT values */
@@ -52,12 +43,68 @@ void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf)
.local_port = -1,
.remote_addr = NULL,
.remote_port = -1,
+ .first_endpoint = 0,
+ .last_endpoint = 0,
+ .bts_base = 0,
};
}
-unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
+/* Test if a given endpoint id is currently in use */
+static bool endpoint_in_use(uint16_t id, struct mgcpgw_client *client)
{
- return client->next_endpoint ++;
+ struct mgcp_inuse_endpoint *endpoint;
+ llist_for_each_entry(endpoint, &client->inuse_endpoints, entry) {
+ if (endpoint->id == id)
+ return true;
+ }
+
+ return false;
+}
+
+/* Find and seize an unsused endpoint id */
+int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
+{
+ int i;
+ uint16_t first_endpoint = client->actual.first_endpoint;
+ uint16_t last_endpoint = client->actual.last_endpoint;
+ struct mgcp_inuse_endpoint *endpoint;
+
+ /* Use the maximum permitted range if the VTY
+ * configuration does not specify a range */
+ if (client->actual.last_endpoint == 0) {
+ first_endpoint = 1;
+ last_endpoint = 65534;
+ }
+
+ /* Test the permitted endpoint range for an endpoint
+ * number that is not in use. When a suitable endpoint
+ * number can be found, seize it by adding it to the
+ * inuse list. */
+ for (i=first_endpoint;i<last_endpoint;i++)
+ {
+ if (endpoint_in_use(i,client) == false) {
+ endpoint = talloc_zero(client, struct mgcp_inuse_endpoint);
+ endpoint->id = i;
+ llist_add_tail(&endpoint->entry, &client->inuse_endpoints);
+ return endpoint->id;
+ }
+ }
+
+ /* All endpoints are busy! */
+ return -EINVAL;
+}
+
+/* Release a seized endpoint id to make it available again for other calls */
+void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client)
+{
+ struct mgcp_inuse_endpoint *endpoint;
+ struct mgcp_inuse_endpoint *endpoint_tmp;
+ llist_for_each_entry_safe(endpoint, endpoint_tmp, &client->inuse_endpoints, entry) {
+ if (endpoint->id == id) {
+ llist_del(&endpoint->entry);
+ talloc_free(endpoint);
+ }
+ }
}
static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp,
@@ -257,9 +304,16 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
{
int ret;
static char strbuf[4096];
- unsigned int l = msg->len < sizeof(strbuf)-1 ? msg->len : sizeof(strbuf)-1;
+ unsigned int l = msg->len < sizeof(strbuf) ? msg->len : sizeof(strbuf);
+ unsigned int i;
+
strncpy(strbuf, (const char*)msg->data, l);
- strbuf[l] = '\0';
+ for (i = 0; i < sizeof(strbuf); i++) {
+ if (strbuf[i] == '\n' || strbuf[i] == '\r') {
+ strbuf[i] = '\0';
+ break;
+ }
+ }
DEBUGP(DMGCP, "Tx MGCP msg to MGCP GW: '%s'\n", strbuf);
LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
@@ -280,9 +334,9 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
mgcp = talloc_zero(ctx, struct mgcpgw_client);
INIT_LLIST_HEAD(&mgcp->responses_pending);
+ INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
mgcp->next_trans_id = 1;
- mgcp->next_endpoint = 1;
mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT;
@@ -294,6 +348,10 @@ 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;
+ mgcp->actual.first_endpoint = conf->first_endpoint > 0 ? (uint16_t)conf->first_endpoint : 0;
+ mgcp->actual.last_endpoint = conf->last_endpoint > 0 ? (uint16_t)conf->last_endpoint : 0;
+ mgcp->actual.bts_base = conf->bts_base > 0 ? (uint16_t)conf->bts_base : 4000;
+
return mgcp;
}
@@ -547,3 +605,12 @@ struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
rtp_conn_addr,
rtp_port);
}
+
+struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
+ unsigned int call_id)
+{
+ mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
+ return mgcp_msg_from_str(trans_id,
+ "DLCX %u %x@mgw MGCP 1.0\r\n"
+ "C: %x\r\n", trans_id, rtp_endpoint, call_id);
+}
diff --git a/src/libmgcp/mgcpgw_client_vty.c b/src/libmgcp/mgcpgw_client_vty.c
index a42ee4e5d..806800078 100644
--- a/src/libmgcp/mgcpgw_client_vty.c
+++ b/src/libmgcp/mgcpgw_client_vty.c
@@ -79,10 +79,46 @@ DEFUN(cfg_mgcpgw_remote_port, cfg_mgcpgw_remote_port_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_mgcpgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
+ "mgcpgw endpoint-range <1-65534> <1-65534>",
+ MGCPGW_STR "usable range of endpoint identifiers\n"
+ "set first useable endpoint identifier\n"
+ "set the last useable endpoint identifier\n")
+{
+ uint16_t first_endpoint = atoi(argv[0]);
+ uint16_t last_endpoint = atoi(argv[1]);
+
+ if (last_endpoint < first_endpoint) {
+ vty_out(vty, "last endpoint must be greater than first endpoint!%s",
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ global_mgcpgw_client_conf->first_endpoint = first_endpoint;
+ global_mgcpgw_client_conf->last_endpoint = last_endpoint;
+ return CMD_SUCCESS;
+}
+
+#define BTS_START_STR "First UDP port allocated for the BTS side\n"
+#define UDP_PORT_STR "UDP Port number\n"
+DEFUN(cfg_mgcp_rtp_bts_base_port,
+ cfg_mgcp_rtp_bts_base_port_cmd,
+ "mgcpgw bts-base <0-65534>",
+ MGCPGW_STR
+ BTS_START_STR
+ UDP_PORT_STR)
+{
+ global_mgcpgw_client_conf->bts_base = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
int mgcpgw_client_config_write(struct vty *vty, const char *indent)
{
const char *addr;
int port;
+ uint16_t first_endpoint;
+ uint16_t last_endpoint;
+ uint16_t bts_base;
addr = global_mgcpgw_client_conf->local_addr;
if (addr)
@@ -102,6 +138,19 @@ int mgcpgw_client_config_write(struct vty *vty, const char *indent)
vty_out(vty, "%smgcpgw remote-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
+ first_endpoint = global_mgcpgw_client_conf->first_endpoint;
+ last_endpoint = global_mgcpgw_client_conf->last_endpoint;
+ if (last_endpoint != 0) {
+ vty_out(vty, "%smgcpgw endpoint-range %u %u%s", indent,
+ first_endpoint, last_endpoint, VTY_NEWLINE);
+ }
+
+ bts_base = global_mgcpgw_client_conf->bts_base;
+ if (bts_base) {
+ vty_out(vty, "%smgcpgw bts-base %u%s", indent,
+ bts_base, VTY_NEWLINE);
+ }
+
return CMD_SUCCESS;
}
@@ -113,4 +162,6 @@ void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf)
install_element(node, &cfg_mgcpgw_local_port_cmd);
install_element(node, &cfg_mgcpgw_remote_ip_cmd);
install_element(node, &cfg_mgcpgw_remote_port_cmd);
+ install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
+ install_element(node, &cfg_mgcp_rtp_bts_base_port_cmd);
}