<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">mgcp_client: allow to reset endpoints on startup<br><br>Depending on the usecase of osmo_mpcg_client it may be helpful to send a<br>DLCX to certain endpoints. Usually this would be a wildcarded endpoint<br>that resets the entire trunk to drop lingering RTP flows which may still<br>present after a restart/crash, but it might be also a group of specific<br>endpoints. The user may specify an arbitrary amount of endpoints where<br>the mgcp client will send a DLCX to. It does not matter if the endpoints<br>are wildcarded or not.<br><br>Change-Id: I47e7ff858d5067b46d52329be5f362ff61c0dff8<br>Related: SYS#5535<br>---<br>M include/osmocom/mgcp_client/mgcp_client.h<br>M src/libosmo-mgcp-client/mgcp_client.c<br>M src/libosmo-mgcp-client/mgcp_client_vty.c<br>3 files changed, 131 insertions(+), 19 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/08/25008/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>index 02996a7..95c25b1 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>@@ -17,6 +17,12 @@</span><br><span> struct vty;</span><br><span> struct mgcp_client;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Struct that holds one endpoint name */</span><br><span style="color: hsl(120, 100%, 40%);">+struct reset_ep {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct mgcp_client_conf {</span><br><span>       const char *local_addr;</span><br><span>      int local_port;</span><br><span>@@ -26,6 +32,12 @@</span><br><span>         /* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.</span><br><span>        * If this is nonempty, the contained name will be used instead of 'mgw'. */</span><br><span>         char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* The user may configure certain endpoint names that are reset via DLCX</span><br><span style="color: hsl(120, 100%, 40%);">+       * on startup. Usually this will be one wildcarded endpoint e.g.</span><br><span style="color: hsl(120, 100%, 40%);">+       * 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.</span><br><span style="color: hsl(120, 100%, 40%);">+         * 'ds/e1-0/s-3/su16-4' */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head reset_epnames;</span><br><span> };</span><br><span> </span><br><span> typedef unsigned int mgcp_trans_id_t;</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client.c b/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>index 9d60ee8..3320ad7 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client.c</span><br><span>@@ -201,6 +201,8 @@</span><br><span>           .remote_addr = NULL,</span><br><span>                 .remote_port = -1,</span><br><span>   };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&conf->reset_epnames);</span><br><span> }</span><br><span> </span><br><span> static void mgcp_client_handle_response(struct mgcp_client *mgcp,</span><br><span>@@ -754,6 +756,8 @@</span><br><span>                                 struct mgcp_client_conf *conf)</span><br><span> {</span><br><span>     struct mgcp_client *mgcp;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct reset_ep *actual_reset_ep;</span><br><span> </span><br><span>         mgcp = talloc_zero(ctx, struct mgcp_client);</span><br><span>         if (!mgcp)</span><br><span>@@ -784,6 +788,12 @@</span><br><span>    }</span><br><span>    LOGP(DLMGCP, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&mgcp->actual.reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           actual_reset_ep = talloc_memdup (ctx, reset_ep, sizeof(*reset_ep));</span><br><span style="color: hsl(120, 100%, 40%);">+           llist_add_tail(&actual_reset_ep->list, &mgcp->actual.reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  return mgcp;</span><br><span> }</span><br><span> </span><br><span>@@ -823,6 +833,42 @@</span><br><span>         return -EINVAL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   static char endpoint[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc > sizeof(endpoint) - 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     return endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */</span><br><span style="color: hsl(120, 100%, 40%);">+void _ignore_mgcp_response(struct mgcp_response *response, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Fromat DLCX message (fire and forget) and send it off to the MGW */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname) {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msgb_dlcx;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_msg mgcp_msg_dlcx = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .verb = MGCP_VERB_DLCX,</span><br><span style="color: hsl(120, 100%, 40%);">+               .presence = MGCP_MSG_PRESENCE_ENDPOINT,</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);</span><br><span style="color: hsl(120, 100%, 40%);">+   mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Initalize client connection (opens socket only, no request is sent yet)</span><br><span>  *  \param[in,out] mgcp MGCP client descriptor.</span><br><span>  *  \returns 0 on success, -EINVAL on error. */</span><br><span>@@ -830,6 +876,7 @@</span><br><span> {</span><br><span>      struct osmo_wqueue *wq;</span><br><span>      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct reset_ep *reset_ep;</span><br><span> </span><br><span>      if (!mgcp) {</span><br><span>                 LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");</span><br><span>@@ -852,9 +899,14 @@</span><br><span>               goto error_close_fd;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* If configured, send a DLCX message to the endpoints that are configured to</span><br><span style="color: hsl(120, 100%, 40%);">+  * be reset on startup. Usually this is a wildcarded endpoint. */</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(reset_ep, &mgcp->actual.reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLMGCP, LOGL_INFO, "MGCP GW sending DLCX to: %s\n", _mgcp_client_name_append_domain(mgcp, reset_ep->name));</span><br><span style="color: hsl(120, 100%, 40%);">+         _mgcp_client_send_dlcx(mgcp, _mgcp_client_name_append_domain(mgcp, reset_ep->name));</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span>    return 0;</span><br><span> error_close_fd:</span><br><span>         close(wq->bfd.fd);</span><br><span>@@ -894,24 +946,6 @@</span><br><span>         return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        static char endpoint[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(0, 100%, 40%);">-     int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(0, 100%, 40%);">-  if (rc > sizeof(endpoint) - 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));</span><br><span style="color: hsl(0, 100%, 40%);">-            return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rc < 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");</span><br><span style="color: hsl(0, 100%, 40%);">-              return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-       return endpoint;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! Compose endpoint name for a wildcarded request to the virtual trunk</span><br><span>  *  \param[in] mgcp MGCP client descriptor.</span><br><span>  *  \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client_vty.c b/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>index cc8db5d..cd12776 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>@@ -155,10 +155,71 @@</span><br><span>   return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mgw_reset_ep_name,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mgw_reset_ep_name_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "mgw reset-endpoint NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      MGW_STR "Set an eindpoint name that should be reset (DLCX) on startup, e.g. 'rtpbridge/*'\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* stop when the address is already in the list */</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strcmp(argv[0], reset_ep->name) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* the domain name is not part of the actual endpoint name */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < strlen(argv[0]); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (argv[0][i] == '@') {</span><br><span style="color: hsl(120, 100%, 40%);">+                      vty_out(vty, "%% the endpoint name must be given without domain name ('%s')%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                             argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                        return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   reset_ep = talloc_zero(global_mgcp_client_ctx, struct reset_ep);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(reset_ep);</span><br><span style="color: hsl(120, 100%, 40%);">+        reset_ep->name = talloc_strdup(reset_ep, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(reset_ep->name);</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_add_tail(&reset_ep->list, &global_mgcp_client_conf->reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mgw_no_reset_ep_name,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mgw_no_reset_ep_name_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no mgw reset-endpoint NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      MGW_STR "Do not reset (DLCX) endpoint on startup, e.g. 'rtpbridge/*'\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct reset_ep *reset_ep_del = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strcmp(argv[0], reset_ep->name) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  reset_ep_del = reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (reset_ep_del) {</span><br><span style="color: hsl(120, 100%, 40%);">+           llist_del(&reset_ep_del->list);</span><br><span style="color: hsl(120, 100%, 40%);">+                talloc_free(reset_ep_del);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int mgcp_client_config_write(struct vty *vty, const char *indent)</span><br><span> {</span><br><span>   const char *addr;</span><br><span>    int port;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct reset_ep *reset_ep;</span><br><span> </span><br><span>    addr = global_mgcp_client_conf->local_addr;</span><br><span>       if (addr)</span><br><span>@@ -182,6 +243,9 @@</span><br><span>              vty_out(vty, "%smgw endpoint-domain %s%s", indent,</span><br><span>                         global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list)</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -197,6 +261,8 @@</span><br><span>   install_lib_element(node, &cfg_mgw_endpoint_range_cmd);</span><br><span>  install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);</span><br><span>       install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);</span><br><span> </span><br><span>    /* deprecated 'mgcpgw' commands */</span><br><span>   install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008">change 25008</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-mgw/+/25008"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-mgw </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I47e7ff858d5067b46d52329be5f362ff61c0dff8 </div>
<div style="display:none"> Gerrit-Change-Number: 25008 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>