mgcp_client: allow to reset endpoints on startup
Depending on the usecase of osmo_mpcg_client it may be helpful to send a DLCX to certain endpoints. Usually this would be a wildcarded endpoint that resets the entire trunk to drop lingering RTP flows which may still present after a restart/crash, but it might be also a group of specific endpoints. The user may specify an arbitrary amount of endpoints where the mgcp client will send a DLCX to. It does not matter if the endpoints are wildcarded or not. Change-Id: I47e7ff858d5067b46d52329be5f362ff61c0dff8 Related: SYS#5535changes/08/25008/17
parent
38533ba9b3
commit
3f2c15f275
|
@ -25,3 +25,4 @@
|
|||
#
|
||||
#library what description / commit summary line
|
||||
update dependency to libosmocore > 1.5.1 for our use of osmo_sock_set_dscp()
|
||||
libosmo-mgcp-client struct mgcp_client_conf ABI breackage
|
|
@ -26,6 +26,12 @@ struct mgcp_client_conf {
|
|||
/* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.
|
||||
* If this is nonempty, the contained name will be used instead of 'mgw'. */
|
||||
char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];
|
||||
|
||||
/* The user may configure certain endpoint names that are reset via DLCX
|
||||
* on startup. Usually this will be one wildcarded endpoint e.g.
|
||||
* 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.
|
||||
* 'ds/e1-0/s-3/su16-4' */
|
||||
struct llist_head reset_epnames;
|
||||
};
|
||||
|
||||
typedef unsigned int mgcp_trans_id_t;
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
#define MSGB_CB_MGCP_TRANS_ID 0
|
||||
|
||||
/* Struct that holds one endpoint name */
|
||||
struct reset_ep {
|
||||
struct llist_head list;
|
||||
char name[MGCP_ENDPOINT_MAXLEN];
|
||||
};
|
||||
|
||||
struct mgcp_client {
|
||||
struct mgcp_client_conf actual;
|
||||
struct osmo_wqueue wq;
|
||||
|
|
|
@ -200,6 +200,8 @@ void mgcp_client_conf_init(struct mgcp_client_conf *conf)
|
|||
.remote_addr = NULL,
|
||||
.remote_port = -1,
|
||||
};
|
||||
|
||||
INIT_LLIST_HEAD(&conf->reset_epnames);
|
||||
}
|
||||
|
||||
static void mgcp_client_handle_response(struct mgcp_client *mgcp,
|
||||
|
@ -753,6 +755,8 @@ struct mgcp_client *mgcp_client_init(void *ctx,
|
|||
struct mgcp_client_conf *conf)
|
||||
{
|
||||
struct mgcp_client *mgcp;
|
||||
struct reset_ep *reset_ep;
|
||||
struct reset_ep *actual_reset_ep;
|
||||
|
||||
mgcp = talloc_zero(ctx, struct mgcp_client);
|
||||
if (!mgcp)
|
||||
|
@ -783,6 +787,12 @@ struct mgcp_client *mgcp_client_init(void *ctx,
|
|||
}
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));
|
||||
|
||||
INIT_LLIST_HEAD(&mgcp->actual.reset_epnames);
|
||||
llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
|
||||
actual_reset_ep = talloc_memdup(mgcp, reset_ep, sizeof(*reset_ep));
|
||||
llist_add_tail(&actual_reset_ep->list, &mgcp->actual.reset_epnames);
|
||||
}
|
||||
|
||||
return mgcp;
|
||||
}
|
||||
|
||||
|
@ -822,13 +832,49 @@ static int init_socket(struct mgcp_client *mgcp)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*! Initalize client connection (opens socket only, no request is sent yet)
|
||||
/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
|
||||
static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
|
||||
|
||||
/* Format DLCX message (fire and forget) and send it off to the MGW */
|
||||
static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
|
||||
{
|
||||
struct msgb *msgb_dlcx;
|
||||
struct mgcp_msg mgcp_msg_dlcx = {
|
||||
.verb = MGCP_VERB_DLCX,
|
||||
.presence = MGCP_MSG_PRESENCE_ENDPOINT,
|
||||
};
|
||||
osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
|
||||
msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
|
||||
mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
|
||||
}
|
||||
|
||||
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
|
||||
{
|
||||
static char endpoint[MGCP_ENDPOINT_MAXLEN];
|
||||
int rc;
|
||||
|
||||
rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
|
||||
if (rc > sizeof(endpoint) - 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
|
||||
sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
|
||||
return NULL;
|
||||
}
|
||||
if (rc < 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
|
||||
return NULL;
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*! Initialize client connection (opens socket)
|
||||
* \param[in,out] mgcp MGCP client descriptor.
|
||||
* \returns 0 on success, -EINVAL on error. */
|
||||
int mgcp_client_connect(struct mgcp_client *mgcp)
|
||||
{
|
||||
struct osmo_wqueue *wq;
|
||||
int rc;
|
||||
struct reset_ep *reset_ep;
|
||||
const char *epname;
|
||||
|
||||
if (!mgcp) {
|
||||
LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");
|
||||
|
@ -851,9 +897,15 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
|
|||
goto error_close_fd;
|
||||
}
|
||||
|
||||
|
||||
LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
|
||||
|
||||
/* If configured, send a DLCX message to the endpoints that are configured to
|
||||
* be reset on startup. Usually this is a wildcarded endpoint. */
|
||||
llist_for_each_entry(reset_ep, &mgcp->actual.reset_epnames, list) {
|
||||
epname = _mgcp_client_name_append_domain(mgcp, reset_ep->name);
|
||||
LOGP(DLMGCP, LOGL_INFO, "MGCP GW sending DLCX to: %s\n", epname);
|
||||
_mgcp_client_send_dlcx(mgcp, epname);
|
||||
}
|
||||
return 0;
|
||||
error_close_fd:
|
||||
close(wq->bfd.fd);
|
||||
|
@ -893,24 +945,6 @@ const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp)
|
|||
return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";
|
||||
}
|
||||
|
||||
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)
|
||||
{
|
||||
static char endpoint[MGCP_ENDPOINT_MAXLEN];
|
||||
int rc;
|
||||
|
||||
rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
|
||||
if (rc > sizeof(endpoint) - 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
|
||||
sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
|
||||
return NULL;
|
||||
}
|
||||
if (rc < 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
|
||||
return NULL;
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/*! Compose endpoint name for a wildcarded request to the virtual trunk
|
||||
* \param[in] mgcp MGCP client descriptor.
|
||||
* \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
|
||||
|
||||
#define MGW_STR MGCP_CLIENT_MGW_STR
|
||||
|
||||
|
@ -155,10 +156,72 @@ DEFUN(cfg_mgw_endpoint_domain_name,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgw_reset_ep_name,
|
||||
cfg_mgw_reset_ep_name_cmd,
|
||||
"mgw reset-endpoint NAME",
|
||||
MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
|
||||
"e.g. 'rtpbridge/*'\n"
|
||||
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
|
||||
{
|
||||
int rc;
|
||||
struct reset_ep *reset_ep;
|
||||
|
||||
/* stop when the address is already in the list */
|
||||
llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {
|
||||
if (strcmp(argv[0], reset_ep->name) == 0) {
|
||||
vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
/* the domain name is not part of the actual endpoint name */
|
||||
if (strchr(argv[0], '@')) {
|
||||
vty_out(vty, "%% the endpoint name must be given without domain name ('%s')%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
reset_ep = talloc_zero(global_mgcp_client_ctx, struct reset_ep);
|
||||
OSMO_ASSERT(reset_ep);
|
||||
|
||||
rc = osmo_strlcpy(reset_ep->name, argv[0], sizeof(reset_ep->name));
|
||||
if (rc >= sizeof(reset_ep->name)) {
|
||||
vty_out(vty, "%% Error: 'mgw reset-endpoint' name too long, max length is %zu: '%s'%s",
|
||||
sizeof(reset_ep->name) - 1, argv[0], VTY_NEWLINE);
|
||||
talloc_free(reset_ep);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
llist_add_tail(&reset_ep->list, &global_mgcp_client_conf->reset_epnames);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgw_no_reset_ep_name,
|
||||
cfg_mgw_no_reset_ep_name_cmd,
|
||||
"no mgw reset-endpoint NAME",
|
||||
MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
|
||||
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
|
||||
{
|
||||
struct reset_ep *reset_ep;
|
||||
|
||||
llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {
|
||||
if (strcmp(argv[0], reset_ep->name) == 0) {
|
||||
llist_del(&reset_ep->list);
|
||||
talloc_free(reset_ep);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
|
||||
{
|
||||
const char *addr;
|
||||
int port;
|
||||
struct reset_ep *reset_ep;
|
||||
|
||||
addr = global_mgcp_client_conf->local_addr;
|
||||
if (addr)
|
||||
|
@ -182,6 +245,9 @@ int mgcp_client_config_write(struct vty *vty, const char *indent)
|
|||
vty_out(vty, "%smgw endpoint-domain %s%s", indent,
|
||||
global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list)
|
||||
vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -197,6 +263,8 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
|
|||
install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
|
||||
install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
|
||||
|
||||
/* deprecated 'mgcpgw' commands */
|
||||
install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);
|
||||
|
|
Loading…
Reference in New Issue