This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
dexter gerrit-no-reply at lists.osmocom.orgdexter has submitted this change. ( https://gerrit.osmocom.org/c/osmo-mgw/+/18644 ) Change subject: osmo-mgw: refactor endpoint and trunk handling ...................................................................... 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 --- M include/osmocom/mgcp/Makefile.am M include/osmocom/mgcp/mgcp.h M include/osmocom/mgcp/mgcp_common.h M include/osmocom/mgcp/mgcp_endp.h M include/osmocom/mgcp/mgcp_internal.h A include/osmocom/mgcp/mgcp_ratectr.h A include/osmocom/mgcp/mgcp_trunk.h M src/libosmo-mgcp/Makefile.am M src/libosmo-mgcp/mgcp_codec.c M src/libosmo-mgcp/mgcp_conn.c M src/libosmo-mgcp/mgcp_endp.c M src/libosmo-mgcp/mgcp_msg.c M src/libosmo-mgcp/mgcp_network.c M src/libosmo-mgcp/mgcp_osmux.c M src/libosmo-mgcp/mgcp_protocol.c A src/libosmo-mgcp/mgcp_ratectr.c M src/libosmo-mgcp/mgcp_sdp.c A src/libosmo-mgcp/mgcp_trunk.c M src/libosmo-mgcp/mgcp_vty.c M src/osmo-mgw/mgw_main.c M tests/mgcp/mgcp_test.c 21 files changed, 938 insertions(+), 628 deletions(-) Approvals: Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve laforge: Looks good to me, approved neels: Looks good to me, approved diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am index 036b4ca..fb7654f 100644 --- a/include/osmocom/mgcp/Makefile.am +++ b/include/osmocom/mgcp/Makefile.am @@ -7,5 +7,7 @@ mgcp_sdp.h \ mgcp_codec.h \ mgcp_ctrl.h \ + mgcp_trunk.h \ debug.h \ + mgcp_ratectr.h \ $(NULL) diff --git a/include/osmocom/mgcp/mgcp.h b/include/osmocom/mgcp/mgcp.h index 538c907..3811991 100644 --- a/include/osmocom/mgcp/mgcp.h +++ b/include/osmocom/mgcp/mgcp.h @@ -34,6 +34,8 @@ #include <sys/socket.h> #include <netinet/in.h> +#include "mgcp_ratectr.h" + #define RTP_PORT_DEFAULT_RANGE_START 16002 #define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64 @@ -59,8 +61,8 @@ #define MGCP_POLICY_REJECT 5 #define MGCP_POLICY_DEFER 6 -typedef int (*mgcp_change)(struct mgcp_trunk *cfg, int endpoint, int state); -typedef int (*mgcp_policy)(struct mgcp_trunk *cfg, int endpoint, int state, const char *transactio_id); +typedef int (*mgcp_change)(struct mgcp_endpoint *endp, int state); +typedef int (*mgcp_policy)(struct mgcp_endpoint *endp, int state, const char *transaction_id); typedef int (*mgcp_reset)(struct mgcp_trunk *cfg); typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone); @@ -177,57 +179,6 @@ MGCP_DLCX_DEFERRED_BY_POLICY, }; -struct mgcp_trunk { - struct llist_head entry; - - struct mgcp_config *cfg; - - int trunk_nr; - int trunk_type; - - char *audio_fmtp_extra; - char *audio_name; - int audio_payload; - int audio_send_ptime; - int audio_send_name; - int audio_loop; - - int no_audio_transcoding; - - int omit_rtcp; - int keepalive_interval; - - /* RTP patching */ - int force_constant_ssrc; /* 0: don't, 1: once */ - int force_aligned_timing; - bool rfc5993_hr_convert; - - /* spec handling */ - int force_realloc; - - /* timer */ - struct osmo_timer_list keepalive_timer; - - /* When set, incoming RTP packets are not filtered - * when ports and ip-address do not match (debug) */ - int rtp_accept_all; - - unsigned int number_endpoints; - int vty_number_endpoints; - struct mgcp_endpoint *endpoints; - - /* Rate counter group which contains stats for generic MGCP events. */ - struct rate_ctr_group *mgcp_general_ctr_group; - /* Rate counter group which contains stats for processed CRCX commands. */ - struct rate_ctr_group *mgcp_crcx_ctr_group; - /* Rate counter group which contains stats for processed MDCX commands. */ - struct rate_ctr_group *mgcp_mdcx_ctr_group; - /* Rate counter group which contains stats for processed DLCX commands. */ - struct rate_ctr_group *mgcp_dlcx_ctr_group; - /* Rate counter group which aggregates stats of individual RTP connections. */ - struct rate_ctr_group *all_rtp_conn_stats; -}; - enum mgcp_role { MGCP_BSC = 0, MGCP_BSC_NAT, @@ -295,6 +246,10 @@ /* osmocom CTRL interface */ struct ctrl_handle *ctrl; + + /* global rate counters to measure the MGWs overall performance and + * health */ + struct mgcp_ratectr_global ratectr; }; /* config management */ @@ -302,7 +257,6 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg, enum mgcp_role role); int mgcp_vty_init(void); -int mgcp_endpoints_allocate(struct mgcp_trunk *cfg); void mgcp_trunk_set_keepalive(struct mgcp_trunk *trunk, int interval); /* @@ -311,7 +265,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg); -int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint); +int mgcp_send_reset_ep(struct mgcp_endpoint *endp); int mgcp_send_reset_all(struct mgcp_config *cfg); diff --git a/include/osmocom/mgcp/mgcp_common.h b/include/osmocom/mgcp/mgcp_common.h index a1bbb19..07d8d37 100644 --- a/include/osmocom/mgcp/mgcp_common.h +++ b/include/osmocom/mgcp/mgcp_common.h @@ -100,6 +100,10 @@ /* A prefix to denote the virtual trunk (RTP on both ends) */ #define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/" +/* A prefix to denote the e1 trunk + * (see also RFC3435 section E.2) */ +#define MGCP_ENDPOINT_PREFIX_E1_TRUNK "ds/e1-" + /* Maximal number of payload types / codecs that can be negotiated via SDP at * at once. */ #define MGCP_MAX_CODECS 10 diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h index 8fa8390..5737cd2 100644 --- a/include/osmocom/mgcp/mgcp_endp.h +++ b/include/osmocom/mgcp/mgcp_endp.h @@ -28,8 +28,8 @@ struct mgcp_endpoint; #define LOGPENDP(endp, cat, level, fmt, args...) \ -LOGP(cat, level, "endpoint:0x%x " fmt, \ - endp ? ENDPOINT_NUMBER(endp) : -1, \ +LOGP(cat, level, "endpoint:%s " fmt, \ + endp ? endp->name : "none", \ ## args) /* Callback type for RTP dispatcher functions @@ -68,6 +68,9 @@ /*! MGCP endpoint model */ struct mgcp_endpoint { + /*! Unique endpoint name, used for addressing via MGCP */ + char *name; + /*! Call identifier string (as supplied by the call agant) */ char *callid; @@ -80,7 +83,7 @@ /*! Backpointer to the MGW configuration */ struct mgcp_config *cfg; - /*! Backpointer to the Trunk specific configuration */ + /*! Backpointer to the trunk this endpoint belongs to */ struct mgcp_trunk *trunk; /*! Endpoint properties (see above) */ @@ -100,7 +103,9 @@ uint32_t x_osmo_ign; }; -/*! Extract endpoint number for a given endpoint */ -#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->trunk->endpoints)) - +struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, char *name); void mgcp_endp_release(struct mgcp_endpoint *endp); +struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname, + const struct mgcp_trunk *trunk); +struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname, + struct mgcp_config *cfg); diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h index b2e2210..174bfd9 100644 --- a/include/osmocom/mgcp/mgcp_internal.h +++ b/include/osmocom/mgcp/mgcp_internal.h @@ -282,9 +282,6 @@ return endpoint + 60; } -struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int index); -struct mgcp_trunk *mgcp_trunk_num(struct mgcp_config *cfg, int index); - char *get_lco_identifier(const char *options); int check_local_cx_options(void *ctx, const char *options); void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, diff --git a/include/osmocom/mgcp/mgcp_ratectr.h b/include/osmocom/mgcp/mgcp_ratectr.h new file mode 100644 index 0000000..e05b70c --- /dev/null +++ b/include/osmocom/mgcp/mgcp_ratectr.h @@ -0,0 +1,22 @@ +#pragma once + +/* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */ + +struct mgcp_ratectr_global { + /* Rate counter group which contains stats for generic MGCP events. */ + struct rate_ctr_group *mgcp_general_ctr_group; +}; + +struct mgcp_ratectr_trunk { + /* Rate counter group which contains stats for processed CRCX commands. */ + struct rate_ctr_group *mgcp_crcx_ctr_group; + /* Rate counter group which contains stats for processed MDCX commands. */ + struct rate_ctr_group *mgcp_mdcx_ctr_group; + /* Rate counter group which contains stats for processed DLCX commands. */ + struct rate_ctr_group *mgcp_dlcx_ctr_group; + /* Rate counter group which aggregates stats of individual RTP connections. */ + struct rate_ctr_group *all_rtp_conn_stats; +}; + +int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr); +int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr); diff --git a/include/osmocom/mgcp/mgcp_trunk.h b/include/osmocom/mgcp/mgcp_trunk.h new file mode 100644 index 0000000..436e39a --- /dev/null +++ b/include/osmocom/mgcp/mgcp_trunk.h @@ -0,0 +1,49 @@ +#pragma once + +struct mgcp_trunk { + struct llist_head entry; + + struct mgcp_config *cfg; + + int trunk_nr; + int trunk_type; + + char *audio_fmtp_extra; + char *audio_name; + int audio_payload; + int audio_send_ptime; + int audio_send_name; + int audio_loop; + + int no_audio_transcoding; + + int omit_rtcp; + int keepalive_interval; + + /* RTP patching */ + int force_constant_ssrc; /* 0: don't, 1: once */ + int force_aligned_timing; + bool rfc5993_hr_convert; + + /* spec handling */ + int force_realloc; + + /* timer */ + struct osmo_timer_list keepalive_timer; + + /* When set, incoming RTP packets are not filtered + * when ports and ip-address do not match (debug) */ + int rtp_accept_all; + + unsigned int number_endpoints; + unsigned int vty_number_endpoints; + struct mgcp_endpoint **endpoints; + + /* global rate counters to measure the trunks overall performance and health */ + struct mgcp_ratectr_trunk ratectr; +}; + +struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr); +int mgcp_trunk_alloc_endpts(struct mgcp_trunk *tcfg); +struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, int index); +struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname); 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 at sysmocom.de> + * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info at 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 at selfish.org> + * (C) 2009-2012 by On-Waves + * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info at 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 at selfish.org> + * (C) 2009-2012 by On-Waves + * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info at 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); diff --git a/src/osmo-mgw/mgw_main.c b/src/osmo-mgw/mgw_main.c index 22f2ab8..99e2499 100644 --- a/src/osmo-mgw/mgw_main.c +++ b/src/osmo-mgw/mgw_main.c @@ -38,6 +38,7 @@ #include <osmocom/mgcp/vty.h> #include <osmocom/mgcp/debug.h> #include <osmocom/mgcp/mgcp_endp.h> +#include <osmocom/mgcp/mgcp_trunk.h> #include <osmocom/mgcp/mgcp_ctrl.h> #include <osmocom/core/application.h> @@ -203,7 +204,7 @@ /* Walk over all endpoints and trigger a release, this will release all * endpoints, possible open connections are forcefully dropped */ for (i = 1; i < reset_trunk->number_endpoints; ++i) - mgcp_endp_release(&reset_trunk->endpoints[i]); + mgcp_endp_release(reset_trunk->endpoints[i]); } return 0; diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c index fa38296..ed0fda0 100644 --- a/tests/mgcp/mgcp_test.c +++ b/tests/mgcp/mgcp_test.c @@ -26,6 +26,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> @@ -70,7 +71,7 @@ } #define AUEP1 "AUEP 158663169 ds/e1-1/2 at mgw MGCP 1.0\r\n" -#define AUEP1_RET "200 158663169 OK\r\n" +#define AUEP1_RET "500 158663169 FAIL\r\n" #define AUEP2 "AUEP 18983213 ds/e1-2/1 at mgw MGCP 1.0\r\n" #define AUEP2_RET "500 18983213 FAIL\r\n" #define EMPTY "\r\n" @@ -81,7 +82,7 @@ #define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1 at mgw MGCP 1.0\r\n" #define MDCX_ERR_RET "500 18983213 FAIL\r\n" #define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2 at mgw MGCP 1.0\r\n" -#define MDCX_RET "400 18983214 FAIL\r\n" +#define MDCX_RET "500 18983214 FAIL\r\n" #define MDCX3 \ "MDCX 18983215 1 at mgw MGCP 1.0\r\n" \ @@ -593,12 +594,22 @@ static int last_endpoint = -1; -static int mgcp_test_policy_cb(struct mgcp_trunk *cfg, int endpoint, - int state, const char *transactio_id) +static int mgcp_test_policy_cb(struct mgcp_endpoint *endp, + int state, const char *transaction_id) { - fprintf(stderr, "Policy CB got state %d on endpoint 0x%x\n", - state, endpoint); - last_endpoint = endpoint; + unsigned int i; + struct mgcp_trunk *trunk; + + fprintf(stderr, "Policy CB got state %d on endpoint %s\n", + state, endp->name); + + trunk = endp->trunk; + last_endpoint = -1; + for (i = 0; i < trunk->vty_number_endpoints; i++) { + if (strcmp(endp->name, trunk->endpoints[i]->name) == 0) + last_endpoint = i; + } + return MGCP_POLICY_CONT; } @@ -645,7 +656,7 @@ { int i; for (i = 1; i < trunk->number_endpoints; i++) - mgcp_endp_release(&trunk->endpoints[i]); + mgcp_endp_release(trunk->endpoints[i]); } #define CONN_UNMODIFIED (0x1000) @@ -758,13 +769,13 @@ cfg = mgcp_config_alloc(); cfg->virt_trunk->vty_number_endpoints = 64; - mgcp_endpoints_allocate(cfg->virt_trunk); + mgcp_trunk_alloc_endpts(cfg->virt_trunk); cfg->policy_cb = mgcp_test_policy_cb; memset(last_conn_id, 0, sizeof(last_conn_id)); trunk2 = mgcp_trunk_alloc(cfg, MGCP_TRUNK_E1, 1); - mgcp_endpoints_allocate(trunk2); + mgcp_trunk_alloc_endpts(trunk2); for (i = 0; i < ARRAY_SIZE(tests); i++) { const struct mgcp_test *t = &tests[i]; @@ -810,7 +821,7 @@ printf("Dummy packets: %d\n", dummy_packets); if (last_endpoint != -1) { - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, "1"); if (conn) { @@ -866,7 +877,7 @@ /* Check detected payload type */ if (conn && t->ptype != PTYPE_IGNORE) { OSMO_ASSERT(last_endpoint != -1); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; fprintf(stderr, "endpoint 0x%x: " "payload type %d (expected %d)\n", @@ -898,12 +909,12 @@ cfg = mgcp_config_alloc(); cfg->virt_trunk->vty_number_endpoints = 64; - mgcp_endpoints_allocate(cfg->virt_trunk); + mgcp_trunk_alloc_endpts(cfg->virt_trunk); memset(last_conn_id, 0, sizeof(last_conn_id)); trunk2 = mgcp_trunk_alloc(cfg, MGCP_TRUNK_E1, 1); - mgcp_endpoints_allocate(trunk2); + mgcp_trunk_alloc_endpts(trunk2); for (i = 0; i < ARRAY_SIZE(retransmit); i++) { const struct mgcp_test *t = &retransmit[i]; @@ -966,10 +977,10 @@ cfg->rqnt_cb = rqnt_cb; cfg->virt_trunk->vty_number_endpoints = 64; - mgcp_endpoints_allocate(cfg->virt_trunk); + mgcp_trunk_alloc_endpts(cfg->virt_trunk); trunk2 = mgcp_trunk_alloc(cfg, MGCP_TRUNK_E1, 1); - mgcp_endpoints_allocate(trunk2); + mgcp_trunk_alloc_endpts(trunk2); inp = create_msg(CRCX, NULL); msg = mgcp_handle_message(cfg, inp); @@ -1035,6 +1046,7 @@ { int i; struct mgcp_endpoint endp; + struct mgcp_endpoint *endpoints[1]; struct mgcp_config cfg = {0}; struct mgcp_trunk trunk; @@ -1046,7 +1058,8 @@ endp.cfg = &cfg; endp.type = &ep_typeset.rtp; trunk.vty_number_endpoints = 1; - trunk.endpoints = &endp; + trunk.endpoints = endpoints; + trunk.endpoints[0] = &endp; endp.trunk = &trunk; INIT_LLIST_HEAD(&endp.conns); @@ -1264,6 +1277,7 @@ struct mgcp_trunk trunk; struct mgcp_endpoint endp; + struct mgcp_endpoint *endpoints[1]; struct mgcp_config cfg = {0}; struct mgcp_rtp_state state; struct mgcp_rtp_end *rtp; @@ -1296,7 +1310,8 @@ endp.type = &ep_typeset.rtp; trunk.vty_number_endpoints = 1; - trunk.endpoints = &endp; + trunk.endpoints = endpoints; + trunk.endpoints[0] = &endp; trunk.force_constant_ssrc = patch_ssrc; trunk.force_aligned_timing = patch_ts; @@ -1372,11 +1387,11 @@ cfg = mgcp_config_alloc(); cfg->virt_trunk->vty_number_endpoints = 64; - mgcp_endpoints_allocate(cfg->virt_trunk); + mgcp_trunk_alloc_endpts(cfg->virt_trunk); cfg->policy_cb = mgcp_test_policy_cb; trunk2 = mgcp_trunk_alloc(cfg, MGCP_TRUNK_E1, 1); - mgcp_endpoints_allocate(trunk2); + mgcp_trunk_alloc_endpts(trunk2); /* Allocate endpoint 1 at mgw with two codecs */ last_endpoint = -1; @@ -1388,7 +1403,7 @@ msgb_free(resp); OSMO_ASSERT(last_endpoint == 1); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 18); @@ -1403,7 +1418,7 @@ msgb_free(resp); OSMO_ASSERT(last_endpoint == 2); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 18); @@ -1423,7 +1438,7 @@ msgb_free(resp); OSMO_ASSERT(last_endpoint == 3); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 0); @@ -1438,7 +1453,7 @@ msgb_free(resp); OSMO_ASSERT(last_endpoint == 4); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 18); @@ -1456,7 +1471,7 @@ msgb_free(resp); OSMO_ASSERT(last_endpoint == 5); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 3); @@ -1467,7 +1482,7 @@ msgb_free(inp); msgb_free(resp); OSMO_ASSERT(last_endpoint == 5); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 3); @@ -1497,7 +1512,7 @@ msgb_free(resp); OSMO_ASSERT(last_endpoint == 5); - endp = &cfg->virt_trunk->endpoints[last_endpoint]; + endp = cfg->virt_trunk->endpoints[last_endpoint]; conn = mgcp_conn_get_rtp(endp, conn_id); OSMO_ASSERT(conn); OSMO_ASSERT(conn->end.codec->payload_type == 0); @@ -1518,9 +1533,9 @@ cfg = mgcp_config_alloc(); cfg->virt_trunk->vty_number_endpoints = 64; - mgcp_endpoints_allocate(cfg->virt_trunk); + mgcp_trunk_alloc_endpts(cfg->virt_trunk); - endp = &cfg->virt_trunk->endpoints[1]; + endp = cfg->virt_trunk->endpoints[1]; _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, "test-connection"); @@ -1567,12 +1582,12 @@ cfg->virt_trunk->vty_number_endpoints = 64; cfg->virt_trunk->audio_send_name = 0; - mgcp_endpoints_allocate(cfg->virt_trunk); + mgcp_trunk_alloc_endpts(cfg->virt_trunk); cfg->policy_cb = mgcp_test_policy_cb; trunk2 = mgcp_trunk_alloc(cfg, MGCP_TRUNK_E1, 1); - mgcp_endpoints_allocate(trunk2); + mgcp_trunk_alloc_endpts(trunk2); inp = create_msg(CRCX, NULL); msg = mgcp_handle_message(cfg, inp); -- To view, visit https://gerrit.osmocom.org/c/osmo-mgw/+/18644 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-mgw Gerrit-Branch: master Gerrit-Change-Id: Ia8cf4d6caf05a4e13f1f507dc68cbabb7e6239aa Gerrit-Change-Number: 18644 Gerrit-PatchSet: 7 Gerrit-Owner: dexter <pmaier at sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier at sysmocom.de> Gerrit-Reviewer: laforge <laforge at osmocom.org> Gerrit-Reviewer: neels <nhofmeyr at sysmocom.de> Gerrit-Reviewer: pespin <pespin at sysmocom.de> Gerrit-MessageType: merged -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200615/02587b54/attachment.htm>