osmo-mgw: refactor endpoint and trunk handling
The trunk and endpoint handling in osmo-mgw is still very complex and
implemented in various places (mostly mgcp_protocol.c). Also we use
still integers for endpoint identification, which is not flexible enough
to address timeslots/subslots on an E1 trunk. Some refactoring is needed.
- get rid of integers as endpoint identifiers, use strings instead and
find the endpoint based on its string name on the trunk.
- identify the trunk based on the trunk prefix given in the endpoint
name.
- refactor trunk and endpoint allocation. Aggregate functionality in
in mgcp_endp.c and mgcp_trunk.c. Also remove non-reusable code that
relates to the still exisiting, but unfinished E1 trunk support.
- refactor rate counters, put them into a separate module and do no
longer allocate them per trunk. Allocate them globally instead.
Change-Id: Ia8cf4d6caf05a4e13f1f507dc68cbabb7e6239aa
Related: OS#2659
diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am
index a0c015b..77d0cdf 100644
--- a/src/libosmo-mgcp/Makefile.am
+++ b/src/libosmo-mgcp/Makefile.am
@@ -40,5 +40,7 @@
mgcp_conn.c \
mgcp_stat.c \
mgcp_endp.c \
+ mgcp_trunk.c \
mgcp_ctrl.c \
+ mgcp_ratectr.c \
$(NULL)
diff --git a/src/libosmo-mgcp/mgcp_codec.c b/src/libosmo-mgcp/mgcp_codec.c
index 3cea495..c251317 100644
--- a/src/libosmo-mgcp/mgcp_codec.c
+++ b/src/libosmo-mgcp/mgcp_codec.c
@@ -19,6 +19,7 @@
*/
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
#include <errno.h>
/* Helper function to dump codec information of a specified codec to a printable
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index 0b499b4..6802b91 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -25,6 +25,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/gsm/gsm_utils.h>
@@ -254,10 +255,9 @@
return NULL;
}
-static void
-aggregate_rtp_conn_stats(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp)
+static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
{
- struct rate_ctr_group *all_stats = trunk->all_rtp_conn_stats;
+ struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
if (all_stats == NULL || conn_stats == NULL)
@@ -296,7 +296,7 @@
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
- aggregate_rtp_conn_stats(endp->trunk, &conn->u.rtp);
+ aggregate_rtp_conn_stats(endp, &conn->u.rtp);
mgcp_rtp_conn_cleanup(&conn->u.rtp);
break;
default:
diff --git a/src/libosmo-mgcp/mgcp_endp.c b/src/libosmo-mgcp/mgcp_endp.c
index eec46bf..6c78de2 100644
--- a/src/libosmo-mgcp/mgcp_endp.c
+++ b/src/libosmo-mgcp/mgcp_endp.c
@@ -1,7 +1,7 @@
/* Endpoint types */
/*
- * (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
@@ -23,6 +23,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
/* Endpoint typeset definition */
const struct mgcp_endpoint_typeset ep_typeset = {
@@ -32,6 +33,39 @@
.rtp.cleanup_cb = mgcp_cleanup_rtp_bridge_cb
};
+/*! allocate an endpoint and set default values.
+ * \param[in] trunk configuration.
+ * \param[in] name endpoint name.
+ * \returns endpoint on success, NULL on failure. */
+struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, char *name)
+{
+ struct mgcp_endpoint *endp;
+
+ endp = talloc_zero(trunk->endpoints, struct mgcp_endpoint);
+ if (!endp)
+ return NULL;
+
+ INIT_LLIST_HEAD(&endp->conns);
+ endp->cfg = trunk->cfg;
+ endp->trunk = trunk;
+ endp->name = talloc_strdup(endp, name);
+
+ switch (trunk->trunk_type) {
+ case MGCP_TRUNK_VIRTUAL:
+ endp->type = &ep_typeset.rtp;
+ break;
+ case MGCP_TRUNK_E1:
+ /* FIXME: Implement E1 allocation */
+ LOGP(DLMGCP, LOGL_FATAL, "E1 trunks not implemented!\n");
+ break;
+ default:
+ osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
+ trunk->trunk_type, __FILE__, __LINE__);
+ }
+
+ return endp;
+}
+
/*! release endpoint, all open connections are closed.
* \param[in] endp endpoint to release */
void mgcp_endp_release(struct mgcp_endpoint *endp)
@@ -53,3 +87,223 @@
endp->local_options.codec = NULL;
endp->wildcarded_req = false;
}
+
+/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
+ * "ds/e1-") and write the epname without the prefix back to the memory
+ * pointed at by epname. (per trunk the prefix is the same for all endpoints,
+ * so no ambiguity is introduced) */
+static void chop_epname_prefix(char *epname, const struct mgcp_trunk *trunk)
+{
+ size_t prefix_len;
+ switch (trunk->trunk_type) {
+ case MGCP_TRUNK_VIRTUAL:
+ prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
+ if (strncmp
+ (epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
+ prefix_len) == 0)
+ memmove(epname, epname + prefix_len,
+ strlen(epname) - prefix_len + 1);
+ return;
+ case MGCP_TRUNK_E1:
+ prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
+ if (strncmp
+ (epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
+ prefix_len) == 0)
+ memmove(epname, epname + prefix_len,
+ strlen(epname) - prefix_len + 1);
+ return;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+/* Check if the endpoint name contains a suffix (e.g. "@mgw") and truncate
+ * epname by writing a '\0' char where the suffix starts. */
+static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
+{
+ char *suffix_begin;
+
+ /* Endpoints on the virtual trunk may have a domain name that is
+ * followed after an @ character, this can be chopped off. All
+ * other supported trunk types do not have any suffixes that may
+ * be chopped off */
+ if (trunk->trunk_type == MGCP_TRUNK_VIRTUAL) {
+ suffix_begin = strchr(epname, '@');
+ if (!suffix_begin)
+ return;
+ *suffix_begin = '\0';
+ }
+}
+
+/* Convert all characters in epname to lowercase and strip trunk prefix and
+ * endpoint name suffix (domain name) from epname. The result is written to
+ * to the memory pointed at by epname_stripped. The expected size of the
+ * result is either equal or lower then the length of the input string
+ * (epname) */
+static void strip_epname(char *epname_stripped, const char *epname,
+ const struct mgcp_trunk *trunk)
+{
+ osmo_str_tolower_buf(epname_stripped, MGCP_ENDPOINT_MAXLEN, epname);
+ chop_epname_prefix(epname_stripped, trunk);
+ chop_epname_suffix(epname_stripped, trunk);
+}
+
+/* Go through the trunk and find a random free (no active calls) endpoint,
+ * this function is called when a wildcarded request is carried out, which
+ * means that it is up to the MGW to choose a random free endpoint. */
+static struct mgcp_endpoint *find_free_endpoint(const struct mgcp_trunk *trunk)
+{
+ struct mgcp_endpoint *endp;
+ unsigned int i;
+
+ for (i = 0; i < trunk->number_endpoints; i++) {
+ endp = trunk->endpoints[i];
+ if (endp->callid == NULL)
+ return endp;
+ }
+
+ return NULL;
+}
+
+/* Find an endpoint specified by its name. If the endpoint can not be found,
+ * return NULL */
+static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
+ const struct mgcp_trunk *trunk)
+{
+ char epname_stripped[MGCP_ENDPOINT_MAXLEN];
+ char epname_stripped_endp[MGCP_ENDPOINT_MAXLEN];
+ struct mgcp_endpoint *endp;
+ unsigned int i;
+
+ /* Strip irrelevant information from the endpoint name */
+ strip_epname(epname_stripped, epname, trunk);
+
+ for (i = 0; i < trunk->number_endpoints; i++) {
+ endp = trunk->endpoints[i];
+ strip_epname(epname_stripped_endp, endp->name, trunk);
+ if (strcmp(epname_stripped_endp, epname_stripped) == 0)
+ return endp;
+ }
+
+ return NULL;
+}
+
+/*! Find an endpoint by its name on a specified trunk.
+ * \param[out] cause pointer to store cause code, can be NULL.
+ * \param[in] epname endpoint name to lookup.
+ * \param[in] trunk where the endpoint is located.
+ * \returns endpoint or NULL if endpoint was not found. */
+struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
+ const struct mgcp_trunk *trunk)
+{
+ struct mgcp_endpoint *endp;
+
+ if (cause)
+ *cause = 0;
+
+ /* At the moment we only support a primitive ('*'-only) method of
+ * wildcarded endpoint searches that picks the next free endpoint on
+ * a trunk. */
+ if (strstr(epname, "*")) {
+ endp = find_free_endpoint(trunk);
+ if (endp) {
+ LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
+ "(trunk:%d) found free endpoint: %s\n",
+ trunk->trunk_nr, endp->name);
+ endp->wildcarded_req = true;
+ return endp;
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR,
+ "(trunk:%d) Not able to find a free endpoint\n",
+ trunk->trunk_nr);
+ if (cause)
+ *cause = -403;
+ return NULL;
+ }
+
+ /* Find an endpoint by its name (if wildcarded request is not
+ * applicable) */
+ endp = find_specific_endpoint(epname, trunk);
+ if (endp) {
+ LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
+ "(trunk:%d) found endpoint: %s\n",
+ trunk->trunk_nr, endp->name);
+ endp->wildcarded_req = false;
+ return endp;
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR,
+ "(trunk:%d) Not able to find specified endpoint: %s\n",
+ trunk->trunk_nr, epname);
+ if (cause)
+ *cause = -500;
+
+ return NULL;
+}
+
+/* Check if the domain name, which is supplied with the endpoint name
+ * matches the configuration. */
+static int check_domain_name(const char *epname, struct mgcp_config *cfg)
+{
+ char *domain_to_check;
+
+ domain_to_check = strstr(epname, "@");
+ if (!domain_to_check) {
+ LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
+ epname, cfg->domain);
+ return -EINVAL;
+ }
+
+ /* Accept any domain if configured as "*" */
+ if (!strcmp(cfg->domain, "*"))
+ return 0;
+
+ if (strcmp(domain_to_check+1, cfg->domain) != 0) {
+ LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
+ epname, cfg->domain);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*! Find an endpoint by its name, search at all trunks.
+ * \param[out] cause, pointer to store cause code, can be NULL.
+ * \param[in] epname, must contain trunk prefix.
+ * \param[in] cfg, mgcp configuration (trunks).
+ * \returns endpoint or NULL if endpoint was not found. */
+struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
+ struct mgcp_config *cfg)
+{
+ struct mgcp_trunk *trunk;
+ struct mgcp_endpoint *endp;
+ char epname_lc[MGCP_ENDPOINT_MAXLEN];
+
+ osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
+ epname = epname_lc;
+
+ if (cause)
+ *cause = -500;
+
+ /* Identify the trunk where the endpoint is located */
+ trunk = mgcp_trunk_by_name(cfg, epname);
+ if (!trunk)
+ return NULL;
+
+ /* Virtual endpoints require a domain name (see RFC3435, section E.3) */
+ if (trunk->trunk_type == MGCP_TRUNK_VIRTUAL) {
+ if (check_domain_name(epname, cfg))
+ return NULL;
+ }
+
+ /* Identify the endpoint on the trunk */
+ endp = mgcp_endp_by_name_trunk(cause, epname, trunk);
+ if (!endp) {
+ return NULL;
+ }
+
+ if (cause)
+ *cause = 0;
+ return endp;
+}
diff --git a/src/libosmo-mgcp/mgcp_msg.c b/src/libosmo-mgcp/mgcp_msg.c
index 7124a39..019466e 100644
--- a/src/libosmo-mgcp/mgcp_msg.c
+++ b/src/libosmo-mgcp/mgcp_msg.c
@@ -129,167 +129,6 @@
return ret;
}
-/* We have a null terminated string with the endpoint name here. We only
- * support two kinds. Simple ones as seen on the BSC level and the ones
- * seen on the trunk side. (helper function for find_endpoint()) */
-static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
- const char *mgcp)
-{
- char *rest = NULL;
- struct mgcp_trunk *trunk;
- int trunk_index, endp;
- struct mgcp_endpoint *endp_ptr;
-
- trunk_index = strtoul(mgcp + 6, &rest, 10);
- if (rest == NULL || rest[0] != '/' || trunk_index < 1) {
- LOGP(DLMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
- return NULL;
- }
-
- endp = strtoul(rest + 1, &rest, 10);
- if (rest == NULL || rest[0] != '@') {
- LOGP(DLMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
- return NULL;
- }
-
- /* signalling is on timeslot 1 */
- if (endp == 1)
- return NULL;
-
- trunk = mgcp_trunk_num(cfg, trunk_index);
- if (!trunk) {
- LOGP(DLMGCP, LOGL_ERROR, "The trunk %d is not declared.\n",
- trunk_index);
- return NULL;
- }
-
- if (!trunk->endpoints) {
- LOGP(DLMGCP, LOGL_ERROR,
- "Endpoints of trunk %d not allocated.\n", trunk_index);
- return NULL;
- }
-
- if (endp < 1 || endp >= trunk->number_endpoints) {
- LOGP(DLMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n",
- mgcp);
- return NULL;
- }
-
- endp_ptr = &trunk->endpoints[endp];
- endp_ptr->wildcarded_req = false;
- return endp_ptr;
-}
-
-/* Find an endpoint that is not in use. Do this by going through the endpoint
- * array, check the callid. A callid nullpointer indicates that the endpoint
- * is free */
-static struct mgcp_endpoint *find_free_endpoint(struct mgcp_endpoint *endpoints,
- unsigned int number_endpoints)
-{
- struct mgcp_endpoint *endp;
- unsigned int i;
-
- for (i = 0; i < number_endpoints; i++) {
- if (endpoints[i].callid == NULL) {
- endp = &endpoints[i];
- LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
- "found free endpoint\n");
- endp->wildcarded_req = true;
- return endp;
- }
- }
-
- LOGP(DLMGCP, LOGL_ERROR, "Not able to find a free endpoint\n");
- return NULL;
-}
-
-/* Check if the domain name, which is supplied with the endpoint name
- * matches the configuration. */
-static int check_domain_name(struct mgcp_config *cfg, const char *mgcp)
-{
- char *domain_to_check;
-
- domain_to_check = strstr(mgcp, "@");
- if (!domain_to_check)
- return -EINVAL;
-
- /* Accept any domain if configured as "*" */
- if (!strcmp(cfg->domain, "*"))
- return 0;
-
- if (strcmp(domain_to_check+1, cfg->domain) != 0) {
- LOGP(DLMGCP, LOGL_ERROR, "Wrong domain name '%s', expecting '%s'\n", mgcp, cfg->domain);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Search the endpoint pool for the endpoint that had been selected via the
- * MGCP message (helper function for mgcp_analyze_header()) */
-static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg,
- const char *mgcp,
- int *cause)
-{
- char *endptr = NULL;
- unsigned int gw = INT_MAX;
- const char *endpoint_number_str;
- struct mgcp_endpoint *endp;
- struct mgcp_trunk *virt_trunk = cfg->virt_trunk;
-
- *cause = 0;
-
- /* Check if the domainname in the request is correct */
- if (check_domain_name(cfg, mgcp)) {
- *cause = -500;
- return NULL;
- }
-
- /* Check if the E1 trunk is requested */
- if (strncmp(mgcp, "ds/e1", 5) == 0) {
- endp = find_e1_endpoint(cfg, mgcp);
- if (!endp)
- *cause = -500;
- return endp;
- }
-
- /* Check if the virtual trunk is addressed (new, correct way with prefix) */
- if (strncmp
- (mgcp, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
- strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK)) == 0) {
- endpoint_number_str =
- mgcp + strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
- if (endpoint_number_str[0] == '*') {
- endp = find_free_endpoint(virt_trunk->endpoints,
- virt_trunk->number_endpoints);
- if (!endp)
- *cause = -403;
- return endp;
- }
- gw = strtoul(endpoint_number_str, &endptr, 16);
- if (gw < virt_trunk->number_endpoints && endptr[0] == '@') {
- endp = &virt_trunk->endpoints[gw];
- endp->wildcarded_req = false;
- return endp;
- }
- }
-
- /* Deprecated method without prefix */
- LOGP(DLMGCP, LOGL_NOTICE,
- "Addressing virtual trunk without prefix (deprecated), please use %s: '%s'\n",
- MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, mgcp);
- gw = strtoul(mgcp, &endptr, 16);
- if (gw < virt_trunk->number_endpoints && endptr[0] == '@') {
- endp = &virt_trunk->endpoints[gw];
- endp->wildcarded_req = false;
- return endp;
- }
-
- LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
- *cause = -500;
- return NULL;
-}
-
/*! Analyze and parse the the hader of an MGCP messeage string.
* \param[out] pdata caller provided memory to store the parsing results
* \param[in] data mgcp message string
@@ -317,7 +156,7 @@
pdata->trans = elem;
break;
case 1:
- pdata->endp = find_endpoint(pdata->cfg, elem, &cause);
+ pdata->endp = mgcp_endp_by_name(&cause, elem, pdata->cfg);
if (!pdata->endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Unable to find Endpoint `%s'\n", elem);
@@ -391,8 +230,8 @@
const size_t line_len = strlen(line);
if (line[0] != '\0' && line_len < 2) {
LOGP(DLMGCP, LOGL_ERROR,
- "Wrong MGCP option format: '%s' on 0x%x\n",
- line, ENDPOINT_NUMBER(endp));
+ "Wrong MGCP option format: '%s' on %s\n",
+ line, endp->name);
return 0;
}
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index 2d3fdc3..8efc6b7 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -42,6 +42,7 @@
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/debug.h>
#include <osmocom/codec/codec.h>
@@ -61,11 +62,11 @@
int id, int inc)
{
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
- struct rate_ctr_group *trunk_stats = endp->trunk->all_rtp_conn_stats;
+ struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
- /* add to both the per-connection and the per-trunk global stats */
+ /* add to both the per-connection and the global stats */
rate_ctr_add(&conn_stats->ctr[id], inc);
- rate_ctr_add(&trunk_stats->ctr[id], inc);
+ rate_ctr_add(&mgw_stats->ctr[id], inc);
}
static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
@@ -648,9 +649,8 @@
return;
#if 0
- DEBUGP(DRTP,
- "endpoint:0x%x payload hdr payload %u -> endp payload %u\n",
- ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
+ LOGPENDP(endp, DRTP, LOGL_DEBUG, "payload hdr payload %u -> endp payload %u\n",
+ rtp_hdr->payload_type, payload);
rtp_hdr->payload_type = payload;
#endif
}
@@ -1436,11 +1436,10 @@
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
- struct mgcp_rtp_end *rtp_end, int endpno)
+ struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
{
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
- struct mgcp_endpoint *endp = &cfg->virt_trunk->endpoints[endpno];
if (mgcp_create_bind(source_addr, &rtp_end->rtp,
rtp_end->local_port) != 0) {
@@ -1527,8 +1526,7 @@
mgcp_get_local_addr(local_ip_addr, conn);
- return bind_rtp(endp->cfg, local_ip_addr, end,
- ENDPOINT_NUMBER(endp));
+ return bind_rtp(endp->cfg, local_ip_addr, end, endp);
}
/*! free allocated RTP and RTCP ports.
diff --git a/src/libosmo-mgcp/mgcp_osmux.c b/src/libosmo-mgcp/mgcp_osmux.c
index 8da7361..ca8b5f0 100644
--- a/src/libosmo-mgcp/mgcp_osmux.c
+++ b/src/libosmo-mgcp/mgcp_osmux.c
@@ -27,6 +27,7 @@
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
static struct osmo_fd osmux_fd;
@@ -204,7 +205,7 @@
for (i=0; i<cfg->virt_trunk->number_endpoints; i++) {
- endp = &cfg->virt_trunk->endpoints[i];
+ endp = cfg->virt_trunk->endpoints[i];
llist_for_each_entry(conn, &endp->conns, entry) {
if (conn->type != MGCP_CONN_TYPE_RTP)
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 4d77a4c..1d25c45 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -32,7 +32,6 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
-#include <osmocom/core/stats.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_common.h>
@@ -40,6 +39,7 @@
#include <osmocom/mgcp/mgcp_stat.h>
#include <osmocom/mgcp/mgcp_msg.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_conn.h>
@@ -53,101 +53,6 @@
#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
{ .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
-static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
- /* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
- [MGCP_GENERAL_RX_MSGS_TOTAL] = {"mgcp:rx_msgs", "total number of MGCP messages received."},
- [MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = {"mgcp:rx_msgs_retransmitted", "number of received retransmissions."},
- [MGCP_GENERAL_RX_MSGS_HANDLED] = {"mgcp:rx_msgs_handled", "number of handled MGCP messages."},
- [MGCP_GENERAL_RX_MSGS_UNHANDLED] = {"mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages."},
- [MGCP_GENERAL_RX_FAIL_MSG_PARSE] = {"mgcp:err_rx_msg_parse", "error parsing MGCP message."},
- [MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] = {"mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints."},
-};
-
-const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
- .group_name_prefix = "mgcp",
- .group_description = "mgcp general statistics",
- .class_id = OSMO_STATS_CLASS_GLOBAL,
- .num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
- .ctr_desc = mgcp_general_ctr_desc
-};
-
-static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
- [MGCP_CRCX_SUCCESS] = {"crcx:success", "CRCX command processed successfully."},
- [MGCP_CRCX_FAIL_BAD_ACTION] = {"crcx:bad_action", "bad action in CRCX command."},
- [MGCP_CRCX_FAIL_UNHANDLED_PARAM] = {"crcx:unhandled_param", "unhandled parameter in CRCX command."},
- [MGCP_CRCX_FAIL_MISSING_CALLID] = {"crcx:missing_callid", "missing CallId in CRCX command."},
- [MGCP_CRCX_FAIL_INVALID_MODE] = {"crcx:invalid_mode", "invalid connection mode in CRCX command."},
- [MGCP_CRCX_FAIL_LIMIT_EXCEEDED] = {"crcx:limit_exceeded", "limit of concurrent connections was reached."},
- [MGCP_CRCX_FAIL_UNKNOWN_CALLID] = {"crcx:unkown_callid", "unknown CallId in CRCX command."},
- [MGCP_CRCX_FAIL_ALLOC_CONN] = {"crcx:alloc_conn_fail", "connection allocation failure."},
- [MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] = {"crcx:no_remote_conn_desc", "no opposite end specified for connection."},
- [MGCP_CRCX_FAIL_START_RTP] = {"crcx:start_rtp_failure", "failure to start RTP processing."},
- [MGCP_CRCX_FAIL_REJECTED_BY_POLICY] = {"crcx:conn_rejected", "connection rejected by policy."},
- [MGCP_CRCX_FAIL_NO_OSMUX] = {"crcx:no_osmux", "no osmux offered by peer."},
- [MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = {"crcx:conn_opt", "connection options invalid."},
- [MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = {"crcx:codec_nego", "codec negotiation failure."},
- [MGCP_CRCX_FAIL_BIND_PORT] = {"crcx:bind_port", "port bind failure."},
-};
-
-const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
- .group_name_prefix = "crcx",
- .group_description = "crxc statistics",
- .class_id = OSMO_STATS_CLASS_GLOBAL,
- .num_ctr = ARRAY_SIZE(mgcp_crcx_ctr_desc),
- .ctr_desc = mgcp_crcx_ctr_desc
-};
-
-static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
- [MGCP_MDCX_SUCCESS] = {"mdcx:success", "MDCX command processed successfully."},
- [MGCP_MDCX_FAIL_WILDCARD] = {"mdcx:wildcard", "wildcard endpoint names in MDCX commands are unsupported."},
- [MGCP_MDCX_FAIL_NO_CONN] = {"mdcx:no_conn", "endpoint specified in MDCX command has no active connections."},
- [MGCP_MDCX_FAIL_INVALID_CALLID] = {"mdcx:callid", "invalid CallId specified in MDCX command."},
- [MGCP_MDCX_FAIL_INVALID_CONNID] = {"mdcx:connid", "invalid connection ID specified in MDCX command."},
- [MGCP_MDCX_FAIL_UNHANDLED_PARAM] = {"crcx:unhandled_param", "unhandled parameter in MDCX command."},
- [MGCP_MDCX_FAIL_NO_CONNID] = {"mdcx:no_connid", "no connection ID specified in MDCX command."},
- [MGCP_MDCX_FAIL_CONN_NOT_FOUND] = {"mdcx:conn_not_found", "connection specified in MDCX command does not exist."},
- [MGCP_MDCX_FAIL_INVALID_MODE] = {"mdcx:invalid_mode", "invalid connection mode in MDCX command."},
- [MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = {"mdcx:conn_opt", "connection options invalid."},
- [MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] = {"mdcx:no_remote_conn_desc", "no opposite end specified for connection."},
- [MGCP_MDCX_FAIL_START_RTP] = {"mdcx:start_rtp_failure", "failure to start RTP processing."},
- [MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = {"mdcx:conn_rejected", "connection rejected by policy."},
- [MGCP_MDCX_DEFERRED_BY_POLICY] = {"mdcx:conn_deferred", "connection deferred by policy."},
-};
-
-const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
- .group_name_prefix = "mdcx",
- .group_description = "mdcx statistics",
- .class_id = OSMO_STATS_CLASS_GLOBAL,
- .num_ctr = ARRAY_SIZE(mgcp_mdcx_ctr_desc),
- .ctr_desc = mgcp_mdcx_ctr_desc
-};
-
-static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
- [MGCP_DLCX_SUCCESS] = {"dlcx:success", "DLCX command processed successfully."},
- [MGCP_DLCX_FAIL_WILDCARD] = {"dlcx:wildcard", "wildcard names in DLCX commands are unsupported."},
- [MGCP_DLCX_FAIL_NO_CONN] = {"dlcx:no_conn", "endpoint specified in DLCX command has no active connections."},
- [MGCP_DLCX_FAIL_INVALID_CALLID] = {"dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ."},
- [MGCP_DLCX_FAIL_INVALID_CONNID] = {"dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint."},
- [MGCP_DLCX_FAIL_UNHANDLED_PARAM] = {"dlcx:unhandled_param", "unhandled parameter in DLCX command."},
- [MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = {"dlcx:rejected", "connection deletion rejected by policy."},
- [MGCP_DLCX_DEFERRED_BY_POLICY] = {"dlcx:deferred", "connection deletion deferred by policy."},
-};
-
-const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
- .group_name_prefix = "dlcx",
- .group_description = "dlcx statistics",
- .class_id = OSMO_STATS_CLASS_GLOBAL,
- .num_ctr = ARRAY_SIZE(mgcp_dlcx_ctr_desc),
- .ctr_desc = mgcp_dlcx_ctr_desc
-};
-
-const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
- .group_name_prefix = "all_rtp_conn",
- .group_description = "aggregated statistics for all rtp connections",
- .class_id = 1,
- .num_ctr = ARRAY_SIZE(all_rtp_conn_rate_ctr_desc),
- .ctr_desc = all_rtp_conn_rate_ctr_desc
-};
static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
static struct msgb *handle_create_con(struct mgcp_parse_data *data);
@@ -297,9 +202,7 @@
/* NOTE: Only in the virtual trunk we allow dynamic endpoint names */
if (endp->wildcarded_req
&& endp->trunk->trunk_type == MGCP_TRUNK_VIRTUAL) {
- rc = msgb_printf(msg, "Z: %s%x@%s\r\n",
- MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
- ENDPOINT_NUMBER(endp), endp->cfg->domain);
+ rc = msgb_printf(msg, "Z: %s\r\n", endp->name);
if (rc < 0)
return -EINVAL;
}
@@ -379,8 +282,7 @@
* - or a response (three numbers, space, transaction id) */
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_trunk *trunk = cfg->virt_trunk;
- struct rate_ctr_group *rate_ctrs = trunk->mgcp_general_ctr_group;
+ struct rate_ctr_group *rate_ctrs = cfg->ratectr.mgcp_general_ctr_group;
struct mgcp_parse_data pdata;
int rc, i, code, handled = 0;
struct msgb *resp = NULL;
@@ -832,7 +734,7 @@
{
struct mgcp_trunk *trunk = p->endp->trunk;
struct mgcp_endpoint *endp = p->endp;
- struct rate_ctr_group *rate_ctrs = trunk->mgcp_crcx_ctr_group;
+ struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
int error_code = 400;
const char *local_options = NULL;
const char *callid = NULL;
@@ -1043,8 +945,7 @@
/* policy CB */
if (p->cfg->policy_cb) {
int rc;
- rc = p->cfg->policy_cb(trunk, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_CRCX, p->trans);
+ rc = p->cfg->policy_cb(endp, MGCP_ENDP_CRCX, p->trans);
switch (rc) {
case MGCP_POLICY_REJECT:
LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
@@ -1066,7 +967,7 @@
LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
"CRCX: Creating connection: port: %u\n", conn->end.local_port);
if (p->cfg->change_cb)
- p->cfg->change_cb(trunk, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
+ p->cfg->change_cb(endp, MGCP_ENDP_CRCX);
/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
@@ -1088,9 +989,8 @@
/* MDCX command handler, processes the received command */
static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
{
- struct mgcp_trunk *trunk = p->endp->trunk;
struct mgcp_endpoint *endp = p->endp;
- struct rate_ctr_group *rate_ctrs = trunk->mgcp_mdcx_ctr_group;
+ struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.mgcp_mdcx_ctr_group;
int error_code = 500;
int silent = 0;
int have_sdp = 0;
@@ -1257,8 +1157,7 @@
/* policy CB */
if (p->cfg->policy_cb) {
int rc;
- rc = p->cfg->policy_cb(endp->trunk, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_MDCX, p->trans);
+ rc = p->cfg->policy_cb(endp, MGCP_ENDP_MDCX, p->trans);
switch (rc) {
case MGCP_POLICY_REJECT:
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
@@ -1287,8 +1186,7 @@
LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
"MDCX: modified conn:%s\n", mgcp_conn_dump(conn->conn));
if (p->cfg->change_cb)
- p->cfg->change_cb(endp->trunk, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_MDCX);
+ p->cfg->change_cb(endp, MGCP_ENDP_MDCX);
/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
OSMO_ASSERT(endp->trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
@@ -1314,9 +1212,8 @@
/* DLCX command handler, processes the received command */
static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
{
- struct mgcp_trunk *trunk = p->endp->trunk;
struct mgcp_endpoint *endp = p->endp;
- struct rate_ctr_group *rate_ctrs = trunk->mgcp_dlcx_ctr_group;
+ struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.mgcp_dlcx_ctr_group;
int error_code = 400;
int silent = 0;
char *line;
@@ -1377,8 +1274,7 @@
/* policy CB */
if (p->cfg->policy_cb) {
int rc;
- rc = p->cfg->policy_cb(endp->trunk, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_DLCX, p->trans);
+ rc = p->cfg->policy_cb(endp, MGCP_ENDP_DLCX, p->trans);
switch (rc) {
case MGCP_POLICY_REJECT:
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "DLCX: rejected by policy\n");
@@ -1442,8 +1338,7 @@
}
if (p->cfg->change_cb)
- p->cfg->change_cb(endp->trunk, ENDPOINT_NUMBER(endp),
- MGCP_ENDP_DLCX);
+ p->cfg->change_cb(endp, MGCP_ENDP_DLCX);
rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_SUCCESS]);
if (silent)
@@ -1548,7 +1443,7 @@
/* Send walk over all endpoints and send out dummy packets through
* every connection present on each endpoint */
for (i = 1; i < trunk->number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &trunk->endpoints[i];
+ struct mgcp_endpoint *endp = trunk->endpoints[i];
llist_for_each_entry(conn, &endp->conns, entry) {
if (conn->mode == MGCP_CONN_RECV_ONLY)
send_dummy(endp, &conn->u.rtp);
@@ -1574,66 +1469,12 @@
trunk->keepalive_interval, 0);
}
-static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
-{
- rate_ctr_group_free(rate_ctr_group);
- return 0;
-}
-
-static int alloc_mgcp_rate_counters(struct mgcp_trunk *trunk, void *ctx)
-{
- /* FIXME: Each new rate counter group requires a unique index. At the
- * moment we generate an index using a counter, but perhaps there is
- * a better way of assigning indices? */
- static unsigned int general_rate_ctr_index = 0;
- static unsigned int crcx_rate_ctr_index = 0;
- static unsigned int mdcx_rate_ctr_index = 0;
- static unsigned int dlcx_rate_ctr_index = 0;
- static unsigned int all_rtp_conn_rate_ctr_index = 0;
-
- if (trunk->mgcp_general_ctr_group == NULL) {
- trunk->mgcp_general_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
- if (!trunk->mgcp_general_ctr_group)
- return -1;
- talloc_set_destructor(trunk->mgcp_general_ctr_group, free_rate_counter_group);
- general_rate_ctr_index++;
- }
- if (trunk->mgcp_crcx_ctr_group == NULL) {
- trunk->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
- if (!trunk->mgcp_crcx_ctr_group)
- return -1;
- talloc_set_destructor(trunk->mgcp_crcx_ctr_group, free_rate_counter_group);
- crcx_rate_ctr_index++;
- }
- if (trunk->mgcp_mdcx_ctr_group == NULL) {
- trunk->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
- if (!trunk->mgcp_mdcx_ctr_group)
- return -1;
- talloc_set_destructor(trunk->mgcp_mdcx_ctr_group, free_rate_counter_group);
- mdcx_rate_ctr_index++;
- }
- if (trunk->mgcp_dlcx_ctr_group == NULL) {
- trunk->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
- if (!trunk->mgcp_dlcx_ctr_group)
- return -1;
- talloc_set_destructor(trunk->mgcp_dlcx_ctr_group, free_rate_counter_group);
- dlcx_rate_ctr_index++;
- }
- if (trunk->all_rtp_conn_stats == NULL) {
- trunk->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
- all_rtp_conn_rate_ctr_index);
- if (!trunk->all_rtp_conn_stats)
- return -1;
- talloc_set_destructor(trunk->all_rtp_conn_stats, free_rate_counter_group);
- all_rtp_conn_rate_ctr_index++;
- }
- return 0;
-}
-
/*! allocate configuration with default values.
* (called once at startup by main function) */
struct mgcp_config *mgcp_config_alloc(void)
{
+ /* FIXME: This is unrelated to the protocol, put this in some
+ * appropiate place! */
struct mgcp_config *cfg;
cfg = talloc_zero(NULL, struct mgcp_config);
@@ -1657,109 +1498,21 @@
cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
- INIT_LLIST_HEAD(&cfg->trunks);
-
- /* default trunk handling */
+ /* Allocate virtual trunk */
cfg->virt_trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, 0);
if (!cfg->virt_trunk) {
talloc_free(cfg);
return NULL;
}
- /* virtual trunk is not part of the list! */
- llist_del(&cfg->virt_trunk->entry);
+
+ /* Initalize list head for user configurable trunks */
+ INIT_LLIST_HEAD(&cfg->trunks);
+
+ mgcp_ratectr_global_alloc(cfg, &cfg->ratectr);
return cfg;
}
-/*! allocate configuration with default values. Do not link it into global list yet!
- * (called once at startup by VTY)
- * \param[in] cfg mgcp configuration
- * \param[in] nr trunk number
- * \returns pointer to allocated trunk configuration */
-struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
-{
- struct mgcp_trunk *trunk;
-
- trunk = talloc_zero(cfg, struct mgcp_trunk);
- if (!trunk) {
- LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
- return NULL;
- }
-
- trunk->cfg = cfg;
- trunk->trunk_type = ttype;
- trunk->trunk_nr = nr;
- trunk->audio_name = talloc_strdup(trunk, "AMR/8000");
- trunk->audio_payload = 126;
- trunk->audio_send_ptime = 1;
- trunk->audio_send_name = 1;
- trunk->vty_number_endpoints = 33;
- trunk->omit_rtcp = 0;
- mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
- if (alloc_mgcp_rate_counters(trunk, trunk) < 0) {
- talloc_free(trunk);
- return NULL;
- }
- llist_add_tail(&trunk->entry, &cfg->trunks);
-
- return trunk;
-}
-
-/*! get trunk configuration by trunk number (index).
- * \param[in] cfg mgcp configuration
- * \param[in] index trunk number
- * \returns pointer to trunk configuration, NULL on error */
-struct mgcp_trunk *mgcp_trunk_num(struct mgcp_config *cfg, int index)
-{
- struct mgcp_trunk *trunk;
-
- llist_for_each_entry(trunk, &cfg->trunks, entry)
- if (trunk->trunk_nr == index)
- return trunk;
-
- return NULL;
-}
-
-/*! allocate endpoints and set default values.
- * (called once at startup by VTY)
- * \param[in] trunk trunk configuration
- * \returns 0 on success, -1 on failure */
-int mgcp_endpoints_allocate(struct mgcp_trunk *trunk)
-{
- int i;
-
- trunk->endpoints = _talloc_zero_array(trunk->cfg,
- sizeof(struct mgcp_endpoint),
- trunk->vty_number_endpoints,
- "endpoints");
- if (!trunk->endpoints)
- return -1;
-
- for (i = 0; i < trunk->vty_number_endpoints; ++i) {
- INIT_LLIST_HEAD(&trunk->endpoints[i].conns);
- trunk->endpoints[i].cfg = trunk->cfg;
- trunk->endpoints[i].trunk = trunk;
-
- switch (trunk->trunk_type) {
- case MGCP_TRUNK_VIRTUAL:
- trunk->endpoints[i].type = &ep_typeset.rtp;
- break;
- case MGCP_TRUNK_E1:
- /* FIXME: Implement E1 allocation */
- LOGP(DLMGCP, LOGL_FATAL, "E1 trunks not implemented!\n");
- break;
- default:
- osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
- trunk->trunk_type, __FILE__, __LINE__);
- }
- }
-
- trunk->number_endpoints = trunk->vty_number_endpoints;
- alloc_mgcp_rate_counters(trunk, trunk->cfg);
-
- return 0;
-}
-
static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
{
return write(cfg->gw_fd.bfd.fd, buf, len);
@@ -1790,17 +1543,16 @@
/*! Reset a single endpoint by sending RSIP message to self.
* (called by VTY)
- * \param[in] endp trunk endpoint
- * \param[in] endpoint number
+ * \param[in] endp to reset
* \returns 0 on success, -1 on error */
-int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
+int mgcp_send_reset_ep(struct mgcp_endpoint *endp)
{
char buf[MGCP_ENDPOINT_MAXLEN + 128];
int len;
int rc;
len = snprintf(buf, sizeof(buf),
- "RSIP 39 %x@%s MGCP 1.0\r\n", endpoint, endp->cfg->domain);
+ "RSIP 39 %s MGCP 1.0\r\n", endp->name);
if (len < 0)
return -1;
diff --git a/src/libosmo-mgcp/mgcp_ratectr.c b/src/libosmo-mgcp/mgcp_ratectr.c
new file mode 100644
index 0000000..302786f
--- /dev/null
+++ b/src/libosmo-mgcp/mgcp_ratectr.c
@@ -0,0 +1,204 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* rate-counter implementation */
+
+/*
+ * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2012 by On-Waves
+ * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * 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 <errno.h>
+#include <osmocom/core/stats.h>
+#include <osmocom/mgcp/mgcp_internal.h>
+#include <osmocom/mgcp/mgcp_ratectr.h>
+
+static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
+ /* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
+ [MGCP_GENERAL_RX_MSGS_TOTAL] = { "mgcp:rx_msgs", "total number of MGCP messages received." },
+ [MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = { "mgcp:rx_msgs_retransmitted", "number of received retransmissions." },
+ [MGCP_GENERAL_RX_MSGS_HANDLED] = { "mgcp:rx_msgs_handled", "number of handled MGCP messages." },
+ [MGCP_GENERAL_RX_MSGS_UNHANDLED] = { "mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages." },
+ [MGCP_GENERAL_RX_FAIL_MSG_PARSE] = { "mgcp:err_rx_msg_parse", "error parsing MGCP message." },
+ [MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] =
+ { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
+};
+
+const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
+ .group_name_prefix = "mgcp",
+ .group_description = "mgcp general statistics",
+ .class_id = OSMO_STATS_CLASS_GLOBAL,
+ .num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
+ .ctr_desc = mgcp_general_ctr_desc
+};
+
+static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
+ [MGCP_CRCX_SUCCESS] = { "crcx:success", "CRCX command processed successfully." },
+ [MGCP_CRCX_FAIL_BAD_ACTION] = { "crcx:bad_action", "bad action in CRCX command." },
+ [MGCP_CRCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in CRCX command." },
+ [MGCP_CRCX_FAIL_MISSING_CALLID] = { "crcx:missing_callid", "missing CallId in CRCX command." },
+ [MGCP_CRCX_FAIL_INVALID_MODE] = { "crcx:invalid_mode", "invalid connection mode in CRCX command." },
+ [MGCP_CRCX_FAIL_LIMIT_EXCEEDED] = { "crcx:limit_exceeded", "limit of concurrent connections was reached." },
+ [MGCP_CRCX_FAIL_UNKNOWN_CALLID] = { "crcx:unkown_callid", "unknown CallId in CRCX command." },
+ [MGCP_CRCX_FAIL_ALLOC_CONN] = { "crcx:alloc_conn_fail", "connection allocation failure." },
+ [MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
+ { "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
+ [MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
+ [MGCP_CRCX_FAIL_REJECTED_BY_POLICY] = { "crcx:conn_rejected", "connection rejected by policy." },
+ [MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
+ [MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
+ [MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
+ [MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." },
+};
+
+const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
+ .group_name_prefix = "crcx",
+ .group_description = "crxc statistics",
+ .class_id = OSMO_STATS_CLASS_GLOBAL,
+ .num_ctr = ARRAY_SIZE(mgcp_crcx_ctr_desc),
+ .ctr_desc = mgcp_crcx_ctr_desc
+};
+
+static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
+ [MGCP_MDCX_SUCCESS] = { "mdcx:success", "MDCX command processed successfully." },
+ [MGCP_MDCX_FAIL_WILDCARD] = { "mdcx:wildcard", "wildcard endpoint names in MDCX commands are unsupported." },
+ [MGCP_MDCX_FAIL_NO_CONN] = { "mdcx:no_conn", "endpoint specified in MDCX command has no active connections." },
+ [MGCP_MDCX_FAIL_INVALID_CALLID] = { "mdcx:callid", "invalid CallId specified in MDCX command." },
+ [MGCP_MDCX_FAIL_INVALID_CONNID] = { "mdcx:connid", "invalid connection ID specified in MDCX command." },
+ [MGCP_MDCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in MDCX command." },
+ [MGCP_MDCX_FAIL_NO_CONNID] = { "mdcx:no_connid", "no connection ID specified in MDCX command." },
+ [MGCP_MDCX_FAIL_CONN_NOT_FOUND] =
+ { "mdcx:conn_not_found", "connection specified in MDCX command does not exist." },
+ [MGCP_MDCX_FAIL_INVALID_MODE] = { "mdcx:invalid_mode", "invalid connection mode in MDCX command." },
+ [MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
+ [MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
+ { "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
+ [MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
+ [MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = { "mdcx:conn_rejected", "connection rejected by policy." },
+ [MGCP_MDCX_DEFERRED_BY_POLICY] = { "mdcx:conn_deferred", "connection deferred by policy." },
+};
+
+const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
+ .group_name_prefix = "mdcx",
+ .group_description = "mdcx statistics",
+ .class_id = OSMO_STATS_CLASS_GLOBAL,
+ .num_ctr = ARRAY_SIZE(mgcp_mdcx_ctr_desc),
+ .ctr_desc = mgcp_mdcx_ctr_desc
+};
+
+static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
+ [MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
+ [MGCP_DLCX_FAIL_WILDCARD] = { "dlcx:wildcard", "wildcard names in DLCX commands are unsupported." },
+ [MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
+ [MGCP_DLCX_FAIL_INVALID_CALLID] =
+ { "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
+ [MGCP_DLCX_FAIL_INVALID_CONNID] =
+ { "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
+ [MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
+ [MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = { "dlcx:rejected", "connection deletion rejected by policy." },
+ [MGCP_DLCX_DEFERRED_BY_POLICY] = { "dlcx:deferred", "connection deletion deferred by policy." },
+};
+
+const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
+ .group_name_prefix = "dlcx",
+ .group_description = "dlcx statistics",
+ .class_id = OSMO_STATS_CLASS_GLOBAL,
+ .num_ctr = ARRAY_SIZE(mgcp_dlcx_ctr_desc),
+ .ctr_desc = mgcp_dlcx_ctr_desc
+};
+
+const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
+ .group_name_prefix = "all_rtp_conn",
+ .group_description = "aggregated statistics for all rtp connections",
+ .class_id = 1,
+ .num_ctr = ARRAY_SIZE(all_rtp_conn_rate_ctr_desc),
+ .ctr_desc = all_rtp_conn_rate_ctr_desc
+};
+
+static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
+{
+ rate_ctr_group_free(rate_ctr_group);
+ return 0;
+}
+
+/*! allocate global rate counters into a given rate counter struct
+ * (called once at startup)
+ * \param[in] ctx talloc context.
+ * \param[out] ratectr struct that holds the counters
+ * \returns 0 on success, -EINVAL on failure */
+int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr)
+{
+ /* FIXME: Each new rate counter group requires a unique index. At the
+ * moment we generate an index using a counter, but perhaps there is
+ * a better way of assigning indices? */
+ static unsigned int general_rate_ctr_index = 0;
+
+ if (ratectr->mgcp_general_ctr_group == NULL) {
+ ratectr->mgcp_general_ctr_group =
+ rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
+ if (!ratectr->mgcp_general_ctr_group)
+ return -EINVAL;
+ talloc_set_destructor(ratectr->mgcp_general_ctr_group, free_rate_counter_group);
+ general_rate_ctr_index++;
+ }
+ return 0;
+}
+
+/*! allocate trunk specific rate counters into a given rate counter struct
+ * (called once on trunk initialization)
+ * \param[in] ctx talloc context.
+ * \param[out] ratectr struct that holds the counters
+ * \returns 0 on success, -EINVAL on failure */
+int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr)
+{
+ /* FIXME: see comment in mgcp_ratectr_global_alloc() */
+ static unsigned int crcx_rate_ctr_index = 0;
+ static unsigned int mdcx_rate_ctr_index = 0;
+ static unsigned int dlcx_rate_ctr_index = 0;
+ static unsigned int all_rtp_conn_rate_ctr_index = 0;
+
+ if (ratectr->mgcp_crcx_ctr_group == NULL) {
+ ratectr->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
+ if (!ratectr->mgcp_crcx_ctr_group)
+ return -EINVAL;
+ talloc_set_destructor(ratectr->mgcp_crcx_ctr_group, free_rate_counter_group);
+ crcx_rate_ctr_index++;
+ }
+ if (ratectr->mgcp_mdcx_ctr_group == NULL) {
+ ratectr->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
+ if (!ratectr->mgcp_mdcx_ctr_group)
+ return -EINVAL;
+ talloc_set_destructor(ratectr->mgcp_mdcx_ctr_group, free_rate_counter_group);
+ mdcx_rate_ctr_index++;
+ }
+ if (ratectr->mgcp_dlcx_ctr_group == NULL) {
+ ratectr->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
+ if (!ratectr->mgcp_dlcx_ctr_group)
+ return -EINVAL;
+ talloc_set_destructor(ratectr->mgcp_dlcx_ctr_group, free_rate_counter_group);
+ dlcx_rate_ctr_index++;
+ }
+ if (ratectr->all_rtp_conn_stats == NULL) {
+ ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
+ all_rtp_conn_rate_ctr_index);
+ if (!ratectr->all_rtp_conn_stats)
+ return -EINVAL;
+ talloc_set_destructor(ratectr->all_rtp_conn_stats, free_rate_counter_group);
+ all_rtp_conn_rate_ctr_index++;
+ }
+ return 0;
+}
diff --git a/src/libosmo-mgcp/mgcp_sdp.c b/src/libosmo-mgcp/mgcp_sdp.c
index 428bde6..f80ebb8 100644
--- a/src/libosmo-mgcp/mgcp_sdp.c
+++ b/src/libosmo-mgcp/mgcp_sdp.c
@@ -25,6 +25,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_msg.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_sdp.h>
@@ -358,10 +359,11 @@
break;
default:
if (p->endp)
+ /* TODO: Check spec: We used the bare endpoint number before,
+ * now we use the endpoint name as a whole? Is this allowed? */
LOGP(DLMGCP, LOGL_NOTICE,
- "Unhandled SDP option: '%c'/%d on 0x%x\n",
- line[0], line[0],
- ENDPOINT_NUMBER(p->endp));
+ "Unhandled SDP option: '%c'/%d on %s\n",
+ line[0], line[0], endp->name);
else
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d\n",
@@ -381,7 +383,7 @@
codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
if (rc < 0)
- LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
+ LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
}
talloc_free(tmp_ctx);
diff --git a/src/libosmo-mgcp/mgcp_trunk.c b/src/libosmo-mgcp/mgcp_trunk.c
new file mode 100644
index 0000000..96c5318
--- /dev/null
+++ b/src/libosmo-mgcp/mgcp_trunk.c
@@ -0,0 +1,183 @@
+/* Trunk handling */
+
+/*
+ * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2012 by On-Waves
+ * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * 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 <osmocom/mgcp/mgcp_internal.h>
+#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
+
+/*! allocate trunk and add it (if required) to the trunk list
+ * (called once at startup by VTY)
+ * \param[in] cfg mgcp configuration
+ * \param[in] nr trunk number
+ * \param[in] ttype trunk type
+ * \returns pointer to allocated trunk, NULL on failure */
+struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
+{
+ struct mgcp_trunk *trunk;
+
+ trunk = talloc_zero(cfg, struct mgcp_trunk);
+ if (!trunk) {
+ LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
+ return NULL;
+ }
+
+ trunk->cfg = cfg;
+ trunk->trunk_type = ttype;
+ trunk->trunk_nr = nr;
+
+ trunk->audio_send_ptime = 1;
+ trunk->audio_send_name = 1;
+ trunk->vty_number_endpoints = 33;
+ trunk->omit_rtcp = 0;
+
+ mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
+
+ /* Note: Trunk Nr.0 is reserved as "virtual trunk",
+ * it is not stored using a separate pointer and
+ * not in the trunk list. */
+ if (nr > 0)
+ llist_add_tail(&trunk->entry, &cfg->trunks);
+
+ mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
+
+ return trunk;
+}
+
+/*! allocate endpoints and set default values.
+ * (called once at startup by VTY)
+ * \param[in] trunk trunk configuration
+ * \returns 0 on success, -1 on failure */
+int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
+{
+ int i;
+ char ep_name_buf[MGCP_ENDPOINT_MAXLEN];
+ struct mgcp_endpoint *endp;
+
+ /* Make sure the amount of requested endpoints does not execeed
+ * sane limits. The VTY already limits the possible amount,
+ * however miss-initalation of the struct or memory corruption
+ * could still lead to an excessive allocation of endpoints, so
+ * better stop early if that is the case. */
+ OSMO_ASSERT(trunk->vty_number_endpoints < 65534);
+
+ /* This function is called once on startup by the VTY to allocate the
+ * endpoints. The number of endpoints must not change througout the
+ * runtime of the MGW */
+ OSMO_ASSERT(trunk->number_endpoints == 0);
+ OSMO_ASSERT(trunk->endpoints == NULL);
+
+ /* allocate pointer array for the endpoints */
+ trunk->endpoints = _talloc_zero_array(trunk->cfg,
+ sizeof(struct mgcp_endpoint *), trunk->vty_number_endpoints, "endpoints");
+ if (!trunk->endpoints)
+ return -1;
+
+ /* create endpoints */
+ for (i = 0; i < trunk->vty_number_endpoints; ++i) {
+ switch (trunk->trunk_type) {
+ case MGCP_TRUNK_VIRTUAL:
+ snprintf(ep_name_buf, sizeof(ep_name_buf), "%s%x@%s", MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, i,
+ trunk->cfg->domain);
+ break;
+ case MGCP_TRUNK_E1:
+ /* FIXME: E1 trunk implementation is work in progress, this endpoint
+ * name is incomplete (subslots) */
+ snprintf(ep_name_buf, sizeof(ep_name_buf), "%s-1/%x", MGCP_ENDPOINT_PREFIX_E1_TRUNK, i);
+ break;
+ default:
+ osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
+ trunk->trunk_type, __FILE__, __LINE__);
+ }
+
+ endp = mgcp_endp_alloc(trunk, ep_name_buf);
+ if (!endp) {
+ talloc_free(trunk->endpoints);
+ return -1;
+ }
+ trunk->endpoints[i] = endp;
+ }
+
+ /* make the endpoints we just created available to the MGW code */
+ trunk->number_endpoints = trunk->vty_number_endpoints;
+
+ return 0;
+}
+
+/*! get trunk configuration by trunk number (index).
+ * \param[in] cfg mgcp configuration
+ * \param[in] index trunk number
+ * \returns pointer to trunk configuration, NULL on error */
+struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, int index)
+{
+ struct mgcp_trunk *trunk;
+
+ llist_for_each_entry(trunk, &cfg->trunks, entry)
+ if (trunk->trunk_nr == index)
+ return trunk;
+
+ return NULL;
+}
+
+/*! Find a trunk by the trunk prefix in the endpoint name.
+ * \param[in] epname endpoint name with trunk prefix to look up.
+ * \param[in] cfg that contains the trunks where the endpoint is located.
+ * \returns trunk or NULL if trunk was not found. */
+struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
+{
+ size_t prefix_len;
+ char epname_lc[MGCP_ENDPOINT_MAXLEN];
+
+ osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
+ epname = epname_lc;
+
+ prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
+ if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
+ return cfg->virt_trunk;
+ }
+
+ /* E1 trunks are not implemented yet, so we deny any request for an
+ * e1 trunk for now. */
+ prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
+ if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) == 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "endpoint name \"%s\" suggests an E1 trunk, but E1 trunks are not implemented in this version of osmo-mgw!\n", epname);
+ return NULL;
+ }
+
+ /* Earlier versions of osmo-mgw were accepting endpoint names
+ * without trunk prefix. This is normally not allowed, each MGCP
+ * request should supply an endpoint name with trunk prefix.
+ * However in order to stay compatible with old versions of
+ * osmo-bsc and osmo-msc we still accept endpoint names without
+ * trunk prefix and just assume that the virtual trunk should
+ * be selected. There is even a TTCN3 test for this, see also:
+ * MGCP_Test.TC_crcx_noprefix */
+ if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
+ LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
+ MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
+ return cfg->virt_trunk;
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
+ return NULL;
+}
diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c
index 7278c1c..54b139a 100644
--- a/src/libosmo-mgcp/mgcp_vty.c
+++ b/src/libosmo-mgcp/mgcp_vty.c
@@ -29,6 +29,7 @@
#include <osmocom/mgcp/vty.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/mgcp/mgcp_trunk.h>
#include <string.h>
#include <inttypes.h>
@@ -49,7 +50,7 @@
if (nr == 0)
trunk = cfg->virt_trunk;
else
- trunk = mgcp_trunk_num(cfg, nr);
+ trunk = mgcp_trunk_by_num(cfg, nr);
return trunk;
}
@@ -208,15 +209,13 @@
end->force_output_ptime, VTY_NEWLINE);
}
-static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp, int epidx,
+static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
int trunk_nr, enum mgcp_trunk_type trunk_type, int show_stats)
{
struct mgcp_conn *conn;
- vty_out(vty, "%s trunk %d endpoint %s%.2x:%s",
- trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1", trunk_nr,
- trunk_type == MGCP_TRUNK_VIRTUAL ? MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK : "",
- epidx, VTY_NEWLINE);
+ vty_out(vty, "%s trunk %d endpoint %s:%s",
+ trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1", trunk_nr, endp->name, VTY_NEWLINE);
if (llist_empty(&endp->conns)) {
vty_out(vty, " No active connections%s", VTY_NEWLINE);
@@ -244,50 +243,84 @@
}
}
-static void dump_trunk(struct vty *vty, struct mgcp_trunk *cfg, int show_stats)
+static void dump_ratectr_global(struct vty *vty, struct mgcp_ratectr_global *ratectr)
+{
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "Rate counters (global):%s", VTY_NEWLINE);
+
+ if (ratectr->mgcp_general_ctr_group) {
+ vty_out(vty, " %s:%s",
+ ratectr->mgcp_general_ctr_group->desc->
+ group_description, VTY_NEWLINE);
+ vty_out_rate_ctr_group_fmt(vty,
+ " %25n: %10c (%S/s %M/m %H/h %D/d) %d",
+ ratectr->mgcp_general_ctr_group);
+ }
+}
+
+static void dump_ratectr_trunk(struct vty *vty, struct mgcp_ratectr_trunk *ratectr)
+{
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "Rate counters (trunk):%s", VTY_NEWLINE);
+
+ if (ratectr->mgcp_crcx_ctr_group) {
+ vty_out(vty, " %s:%s",
+ ratectr->mgcp_crcx_ctr_group->desc->group_description,
+ VTY_NEWLINE);
+ vty_out_rate_ctr_group_fmt(vty,
+ " %25n: %10c (%S/s %M/m %H/h %D/d) %d",
+ ratectr->mgcp_crcx_ctr_group);
+ }
+ if (ratectr->mgcp_dlcx_ctr_group) {
+ vty_out(vty, " %s:%s",
+ ratectr->mgcp_dlcx_ctr_group->desc->group_description,
+ VTY_NEWLINE);
+ vty_out_rate_ctr_group_fmt(vty,
+ " %25n: %10c (%S/s %M/m %H/h %D/d) %d",
+ ratectr->mgcp_dlcx_ctr_group);
+ }
+ if (ratectr->mgcp_mdcx_ctr_group) {
+ vty_out(vty, " %s:%s",
+ ratectr->mgcp_mdcx_ctr_group->desc->group_description,
+ VTY_NEWLINE);
+ vty_out_rate_ctr_group_fmt(vty,
+ " %25n: %10c (%S/s %M/m %H/h %D/d) %d",
+ ratectr->mgcp_mdcx_ctr_group);
+ }
+ if (ratectr->all_rtp_conn_stats) {
+ vty_out(vty, " %s:%s",
+ ratectr->all_rtp_conn_stats->desc->group_description,
+ VTY_NEWLINE);
+ vty_out_rate_ctr_group_fmt(vty,
+ " %25n: %10c (%S/s %M/m %H/h %D/d) %d",
+ ratectr->all_rtp_conn_stats);
+ }
+}
+
+
+static void dump_trunk(struct vty *vty, struct mgcp_trunk *trunk, int show_stats)
{
int i;
vty_out(vty, "%s trunk %d with %d endpoints:%s",
- cfg->trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1",
- cfg->trunk_nr, cfg->number_endpoints - 1, VTY_NEWLINE);
+ trunk->trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1",
+ trunk->trunk_nr, trunk->number_endpoints - 1, VTY_NEWLINE);
- if (!cfg->endpoints) {
+ if (!trunk->endpoints) {
vty_out(vty, "No endpoints allocated yet.%s", VTY_NEWLINE);
return;
}
- for (i = 0; i < cfg->number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &cfg->endpoints[i];
- dump_endpoint(vty, endp, i, cfg->trunk_nr, cfg->trunk_type, show_stats);
- if (i < cfg->number_endpoints - 1)
+ for (i = 0; i < trunk->number_endpoints; ++i) {
+ struct mgcp_endpoint *endp = trunk->endpoints[i];
+ dump_endpoint(vty, endp, trunk->trunk_nr, trunk->trunk_type,
+ show_stats);
+ if (i < trunk->number_endpoints - 1)
vty_out(vty, "%s", VTY_NEWLINE);
}
- if (show_stats) {
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, "Rate counters:%s", VTY_NEWLINE);
- }
- if (show_stats && cfg->mgcp_general_ctr_group) {
- vty_out(vty, " %s:%s", cfg->mgcp_general_ctr_group->desc->group_description, VTY_NEWLINE);
- vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->mgcp_general_ctr_group);
- }
- if (show_stats && cfg->mgcp_crcx_ctr_group) {
- vty_out(vty, " %s:%s", cfg->mgcp_crcx_ctr_group->desc->group_description, VTY_NEWLINE);
- vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->mgcp_crcx_ctr_group);
- }
- if (show_stats && cfg->mgcp_dlcx_ctr_group) {
- vty_out(vty, " %s:%s", cfg->mgcp_dlcx_ctr_group->desc->group_description, VTY_NEWLINE);
- vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->mgcp_dlcx_ctr_group);
- }
- if (show_stats && cfg->mgcp_mdcx_ctr_group) {
- vty_out(vty, " %s:%s", cfg->mgcp_mdcx_ctr_group->desc->group_description, VTY_NEWLINE);
- vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->mgcp_mdcx_ctr_group);
- }
- if (show_stats && cfg->all_rtp_conn_stats) {
- vty_out(vty, " %s:%s", cfg->all_rtp_conn_stats->desc->group_description, VTY_NEWLINE);
- vty_out_rate_ctr_group_fmt(vty, " %25n: %10c (%S/s %M/m %H/h %D/d) %d", cfg->all_rtp_conn_stats);
- }
+ if (show_stats)
+ dump_ratectr_trunk(vty, &trunk->ratectr);
}
#define SHOW_MGCP_STR "Display information about the MGCP Media Gateway\n"
@@ -304,44 +337,41 @@
dump_trunk(vty, g_cfg->virt_trunk, show_stats);
llist_for_each_entry(trunk, &g_cfg->trunks, entry)
- dump_trunk(vty, trunk, show_stats);
+ dump_trunk(vty, trunk, show_stats);
if (g_cfg->osmux)
vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
VTY_NEWLINE);
+ if (show_stats)
+ dump_ratectr_global(vty, &g_cfg->ratectr);
+
return CMD_SUCCESS;
}
static void
dump_mgcp_endpoint(struct vty *vty, struct mgcp_trunk *trunk, const char *epname)
{
- const size_t virt_prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
- unsigned long epidx;
- char *endp;
- int i;
+ struct mgcp_endpoint *endp;
- if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, virt_prefix_len) == 0)
- epname += virt_prefix_len;
- errno = 0;
- epidx = strtoul(epname, &endp, 16);
- if (epname[0] == '\0' || *endp != '\0') {
- vty_out(vty, "endpoint name '%s' is not a hex number%s", epname, VTY_NEWLINE);
- return;
- }
- if ((errno == ERANGE && epidx == ULONG_MAX) /* parsed value out of range */
- || epidx >= trunk->number_endpoints) {
- vty_out(vty, "endpoint %.2lx not configured on trunk %d%s", epidx, trunk->trunk_nr, VTY_NEWLINE);
- return;
- }
-
- for (i = 0; i < trunk->number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &trunk->endpoints[i];
- if (i == epidx) {
- dump_endpoint(vty, endp, i, trunk->trunk_nr, trunk->trunk_type, true);
- break;
+ if (trunk) {
+ /* If a trunk is given, search on that specific trunk only */
+ endp = mgcp_endp_by_name_trunk(NULL, epname, trunk);
+ if (!endp) {
+ vty_out(vty, "endpoint %s not configured on trunk %d%s", epname, trunk->trunk_nr, VTY_NEWLINE);
+ return;
+ }
+ } else {
+ /* If no trunk is given, search on all possible trunks */
+ endp = mgcp_endp_by_name(NULL, epname, g_cfg);
+ if (!endp) {
+ vty_out(vty, "endpoint %s not configured%s", epname, VTY_NEWLINE);
+ return;
}
}
+
+ trunk = endp->trunk;
+ dump_endpoint(vty, endp, trunk->trunk_nr, trunk->trunk_type, true);
}
DEFUN(show_mcgp_endpoint, show_mgcp_endpoint_cmd,
@@ -350,12 +380,7 @@
SHOW_MGCP_STR
"Display information about an endpoint\n" "The name of the endpoint\n")
{
- struct mgcp_trunk *trunk;
-
- dump_mgcp_endpoint(vty, g_cfg->virt_trunk, argv[0]);
- llist_for_each_entry(trunk, &g_cfg->trunks, entry)
- dump_mgcp_endpoint(vty, trunk, argv[0]);
-
+ dump_mgcp_endpoint(vty, NULL, argv[0]);
return CMD_SUCCESS;
}
@@ -810,7 +835,7 @@
struct mgcp_trunk *trunk;
int index = atoi(argv[0]);
- trunk = mgcp_trunk_num(g_cfg, index);
+ trunk = mgcp_trunk_by_num(g_cfg, index);
if (!trunk) {
trunk = mgcp_trunk_alloc(g_cfg, MGCP_TRUNK_E1, index);
if (!trunk) {
@@ -1138,7 +1163,7 @@
return CMD_WARNING;
}
- endp = &trunk->endpoints[endp_no];
+ endp = trunk->endpoints[endp_no];
int loop = atoi(argv[2]);
llist_for_each_entry(conn, &endp->conns, entry) {
if (conn->type == MGCP_CONN_TYPE_RTP)
@@ -1197,7 +1222,7 @@
return CMD_WARNING;
}
- endp = &trunk->endpoints[endp_no];
+ endp = trunk->endpoints[endp_no];
conn_id = argv[2];
conn = mgcp_conn_get_rtp(endp, conn_id);
@@ -1250,7 +1275,7 @@
return CMD_WARNING;
}
- endp = &trunk->endpoints[endp_no];
+ endp = trunk->endpoints[endp_no];
mgcp_endp_release(endp);
return CMD_SUCCESS;
}
@@ -1283,8 +1308,8 @@
return CMD_WARNING;
}
- endp = &trunk->endpoints[endp_no];
- rc = mgcp_send_reset_ep(endp, ENDPOINT_NUMBER(endp));
+ endp = trunk->endpoints[endp_no];
+ rc = mgcp_send_reset_ep(endp);
if (rc < 0) {
vty_out(vty, "Error %d sending reset.%s", rc, VTY_NEWLINE);
return CMD_WARNING;
@@ -1521,7 +1546,7 @@
return -1;
}
- if (mgcp_endpoints_allocate(g_cfg->virt_trunk) != 0) {
+ if (mgcp_trunk_alloc_endpts(g_cfg->virt_trunk) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Failed to initialize the virtual trunk (%d endpoints)\n",
g_cfg->virt_trunk->number_endpoints);
@@ -1529,7 +1554,7 @@
}
llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
- if (mgcp_endpoints_allocate(trunk) != 0) {
+ if (mgcp_trunk_alloc_endpts(trunk) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Failed to initialize trunk %d (%d endpoints)\n",
trunk->trunk_nr, trunk->number_endpoints);