<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25120">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">libosmo-mgcp-client: extend the mgcp_client for MGW poolig<br><br>At the moment the MGCP Client only supports one MGW per application.<br>Depending on the requirements of the application one MGW might not offer<br>the performance needed. Lets add support for an MGCP Client pool that is<br>backward compatible to existing applications.<br><br>Change-Id: Icaaba0e470e916eefddfee750b83f5f65291a6b0<br>Related: SYS#5091<br>---<br>M include/Makefile.am<br>M include/osmocom/mgcp_client/Makefile.am<br>M include/osmocom/mgcp_client/mgcp_client.h<br>M include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h<br>M include/osmocom/mgcp_client/mgcp_client_fsm.h<br>M include/osmocom/mgcp_client/mgcp_client_internal.h<br>A include/osmocom/mgcp_client/mgcp_client_pool.h<br>A include/osmocom/mgcp_client/mgcp_client_pool_internal.h<br>M src/libosmo-mgcp-client/Makefile.am<br>M src/libosmo-mgcp-client/mgcp_client.c<br>M src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c<br>M src/libosmo-mgcp-client/mgcp_client_fsm.c<br>A src/libosmo-mgcp-client/mgcp_client_pool.c<br>M src/libosmo-mgcp-client/mgcp_client_vty.c<br>14 files changed, 598 insertions(+), 39 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/20/25120/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 457ac3f..eb262a6 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -6,6 +6,7 @@</span><br><span>  osmocom/mgcp_client/mgcp_client.h \</span><br><span>  osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \</span><br><span>     osmocom/mgcp_client/mgcp_client_fsm.h \</span><br><span style="color: hsl(120, 100%, 40%);">+       osmocom/mgcp_client/mgcp_client_pool.h \</span><br><span>     osmocom/mgcp/mgcp.h \</span><br><span>        osmocom/mgcp/mgcp_common.h \</span><br><span>         osmocom/mgcp/osmux.h \</span><br><span>diff --git a/include/osmocom/mgcp_client/Makefile.am b/include/osmocom/mgcp_client/Makefile.am</span><br><span>index d303ddf..90b1bd7 100644</span><br><span>--- a/include/osmocom/mgcp_client/Makefile.am</span><br><span>+++ b/include/osmocom/mgcp_client/Makefile.am</span><br><span>@@ -4,6 +4,7 @@</span><br><span> </span><br><span> noinst_HEADERS = \</span><br><span>  mgcp_client_internal.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      mgcp_client_pool_internal.h \</span><br><span>        $(NULL)</span><br><span> </span><br><span> mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h</span><br><span>index 5d79b48..d84adf4 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>@@ -142,6 +142,8 @@</span><br><span> struct mgcp_client *mgcp_client_init(void *ctx,</span><br><span>                                  struct mgcp_client_conf *conf);</span><br><span> int mgcp_client_connect(struct mgcp_client *mgcp);</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_disconnect(struct mgcp_client *mgcp);</span><br><span> </span><br><span> const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);</span><br><span> uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h b/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h</span><br><span>index 78e3a41..f21f40e 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h</span><br><span>@@ -47,6 +47,7 @@</span><br><span> const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);</span><br><span> const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);</span><br><span> const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);</span><br><span> </span><br><span> extern const struct value_string osmo_mgcp_verb_names[];</span><br><span> static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client_fsm.h b/include/osmocom/mgcp_client/mgcp_client_fsm.h</span><br><span>index e315753..ade4f49 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client_fsm.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_fsm.h</span><br><span>@@ -69,5 +69,6 @@</span><br><span> void mgcp_conn_delete(struct osmo_fsm_inst *fi);</span><br><span> </span><br><span> const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);</span><br><span> </span><br><span> const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client_internal.h b/include/osmocom/mgcp_client/mgcp_client_internal.h</span><br><span>index b4b3b02..42960d0 100644</span><br><span>--- a/include/osmocom/mgcp_client/mgcp_client_internal.h</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_internal.h</span><br><span>@@ -10,6 +10,7 @@</span><br><span>      mgcp_trans_id_t next_trans_id;</span><br><span>       struct llist_head responses_pending;</span><br><span>         struct llist_head inuse_endpoints;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_client_pool *pool;</span><br><span> };</span><br><span> </span><br><span> struct mgcp_inuse_endpoint {</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client_pool.h b/include/osmocom/mgcp_client/mgcp_client_pool.h</span><br><span>new file mode 100644</span><br><span>index 0000000..18cbe42</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_pool.h</span><br><span>@@ -0,0 +1,11 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client;</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client_pool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client_pool *mgcp_client_alloc_pool(void *talloc_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_vty_init_pool(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int mgcp_client_connect_pool(struct mgcp_client_pool *pool);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_pool_register_legacy(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_pool_put(struct mgcp_client *mgcp_client);</span><br><span>diff --git a/include/osmocom/mgcp_client/mgcp_client_pool_internal.h b/include/osmocom/mgcp_client/mgcp_client_pool_internal.h</span><br><span>new file mode 100644</span><br><span>index 0000000..bb696f4</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_pool_internal.h</span><br><span>@@ -0,0 +1,35 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Struct to handle a member of a pool of MGWs. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client_pool_member {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Reference number assinged by VTY. This number is used to manage the</span><br><span style="color: hsl(120, 100%, 40%);">+         * pool from the VTY and to identify it in the log. */</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int nr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* MGCP client configuration, this is not the running configuration,</span><br><span style="color: hsl(120, 100%, 40%);">+   * when mgcp_client_init() is executed, a copy of this config is</span><br><span style="color: hsl(120, 100%, 40%);">+       * created. */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mgcp_client_conf conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* MGCP client descriptor, will be automatically allocated when</span><br><span style="color: hsl(120, 100%, 40%);">+        * mgcp_client_connect_pool() is called. (the MGCP client is connected</span><br><span style="color: hsl(120, 100%, 40%);">+         * when this pointer is populated) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_client *client;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* A pool member may be set as 'blocked' from the VTY, this means thet</span><br><span style="color: hsl(120, 100%, 40%);">+         * the pool member may still work and serve ongoing calls, but it won't</span><br><span style="color: hsl(120, 100%, 40%);">+    * be picked from the pool anymore. */</span><br><span style="color: hsl(120, 100%, 40%);">+        bool blocked;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Reference counter to count how often this pool member is currently</span><br><span style="color: hsl(120, 100%, 40%);">+  * picked. */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int refcount;</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%);">+/* Struct to handle a pool of MGWs. (Use _pool functions) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client_pool {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_client *mgcp_client_legacy;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head pool;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/src/libosmo-mgcp-client/Makefile.am b/src/libosmo-mgcp-client/Makefile.am</span><br><span>index 4f17e53..c472ec1 100644</span><br><span>--- a/src/libosmo-mgcp-client/Makefile.am</span><br><span>+++ b/src/libosmo-mgcp-client/Makefile.am</span><br><span>@@ -32,6 +32,7 @@</span><br><span>     mgcp_client_vty.c \</span><br><span>  mgcp_client_fsm.c \</span><br><span>  mgcp_client_endpoint_fsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  mgcp_client_pool.c \</span><br><span>         $(NULL)</span><br><span> </span><br><span> libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)</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 66dac21..72ee1bb 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>@@ -796,40 +796,46 @@</span><br><span>       return mgcp;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int init_socket(struct mgcp_client *mgcp)</span><br><span style="color: hsl(120, 100%, 40%);">+static int init_socket(struct mgcp_client *mgcp, unsigned int retry_n_ports)</span><br><span> {</span><br><span>     int rc;</span><br><span>      struct osmo_wqueue *wq;</span><br><span style="color: hsl(0, 100%, 40%);">- int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int i;</span><br><span> </span><br><span>  wq = &mgcp->wq;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      for (i = 0; i < 100; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < retry_n_ports + 1; i++) {</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                /* Initalize socket with the currently configured port</span><br><span style="color: hsl(0, 100%, 40%);">-           * number */</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Initialize socket with the currently configured port number */</span><br><span>            rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,</span><br><span>                                     mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,</span><br><span>                                        OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);</span><br><span>            if (rc > 0)</span><br><span>                       return rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-          /* If there is a different port than the default port</span><br><span style="color: hsl(0, 100%, 40%);">-            * configured then we assume that the user has choosen</span><br><span style="color: hsl(0, 100%, 40%);">-           * that port conciously and we will not try to resolve</span><br><span style="color: hsl(0, 100%, 40%);">-           * this by silently choosing a different port. */</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If there is a different port than the default port configured then we assume that the user has</span><br><span style="color: hsl(120, 100%, 40%);">+              * choosen that port conciously and we will not try to resolve this by silently choosing a different</span><br><span style="color: hsl(120, 100%, 40%);">+           * port. */</span><br><span>          if (mgcp->actual.local_port != MGCP_CLIENT_LOCAL_PORT_DEFAULT && i == 0)</span><br><span>                  return -EINVAL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+           /* Last try failed */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (i == retry_n_ports) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGP(DLMGCP, LOGL_NOTICE, "MGCPGW failed to bind to %s:%u -- check configuration!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (retry_n_ports == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          /* Choose a new port number to try next */</span><br><span>           LOGP(DLMGCP, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                    "MGCPGW failed to bind to %s:%u, retrying with port %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  "MGCPGW failed to bind to %s:%u, retrying with port %u -- check configuration!\n",</span><br><span>                 mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,</span><br><span>                     mgcp->actual.local_port + 1);</span><br><span>                mgcp->actual.local_port++;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   LOGP(DLMGCP, LOGL_FATAL, "MGCPGW failed to find a port to bind on %i times.\n", i);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLMGCP, LOGL_FATAL, "MGCPGW failed to find a port to bind on %i times -- check configuration!\n", i);</span><br><span>         return -EINVAL;</span><br><span> }</span><br><span> </span><br><span>@@ -869,8 +875,9 @@</span><br><span> </span><br><span> /*! Initialize client connection (opens socket)</span><br><span>  *  \param[in,out] mgcp MGCP client descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] retry_n_ports number of consecutive local ports that should be used to retry on failure.</span><br><span>  *  \returns 0 on success, -EINVAL on error. */</span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_client_connect(struct mgcp_client *mgcp)</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)</span><br><span> {</span><br><span>   struct osmo_wqueue *wq;</span><br><span>      int rc;</span><br><span>@@ -889,7 +896,7 @@</span><br><span> </span><br><span>    osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      rc = init_socket(mgcp);</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = init_socket(mgcp, retry_n_ports);</span><br><span>       if (rc < 0) {</span><br><span>             LOGP(DLMGCP, LOGL_FATAL,</span><br><span>                  "Failed to initialize socket %s:%u -> %s:%u for MGCP GW: %s\n",</span><br><span>@@ -915,6 +922,35 @@</span><br><span>     return rc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Initialize client connection (opens socket)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in,out] mgcp MGCP client descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -EINVAL on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_client_connect(struct mgcp_client *mgcp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return mgcp_client_connect2(mgcp, 99);</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%);">+/*! Terminate client connection</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in,out] mgcp MGCP client descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, -EINVAL on error. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_disconnect(struct mgcp_client *mgcp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_wqueue *wq;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!mgcp) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");</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%);">+   wq = &mgcp->wq;</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_wqueue_clear(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));</span><br><span style="color: hsl(120, 100%, 40%);">+ close(wq->bfd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_fd_is_registered(&wq->bfd))</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fd_unregister(&wq->bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Get the IP-Aaddress of the associated MGW as string.</span><br><span>  *  \param[in] mgcp MGCP client descriptor.</span><br><span>  *  \returns a pointer to the address string. */</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c b/src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c</span><br><span>index 0613e17..ea4c378 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c</span><br><span>@@ -216,6 +216,13 @@</span><br><span>         return ci->mgcp_ci_str;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!ep)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return ep->mgcp_client;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};</span><br><span> </span><br><span> static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client_fsm.c b/src/libosmo-mgcp-client/mgcp_client_fsm.c</span><br><span>index 3f33dc7..1a2b6d8 100644</span><br><span>--- a/src/libosmo-mgcp-client/mgcp_client_fsm.c</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_fsm.c</span><br><span>@@ -252,6 +252,18 @@</span><br><span>     return mgcp_ctx->conn_id;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Get the mgcp_client that is used with this mgcp_client_fsm instance */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_ctx *mgcp_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!fi)</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%);">+        mgcp_ctx = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+       return mgcp_ctx->mgcp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)</span><br><span> {</span><br><span>     struct osmo_fsm_inst *fi = priv;</span><br><span>diff --git a/src/libosmo-mgcp-client/mgcp_client_pool.c b/src/libosmo-mgcp-client/mgcp_client_pool.c</span><br><span>new file mode 100644</span><br><span>index 0000000..10485fb</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_pool.c</span><br><span>@@ -0,0 +1,181 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Philipp Maier</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <osmocom/mgcp_client/mgcp_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_internal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_pool_internal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_pool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stddef.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with</span><br><span style="color: hsl(120, 100%, 40%);">+ *  mgcp_client_vty_init_pool(). Since the pool is linked with the VTY it must exist througout the entire runtime.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] talloc_ctx talloc context. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client_pool *mgcp_client_alloc_pool(void *talloc_ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_client_pool *pool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      pool = talloc_zero(talloc_ctx, struct mgcp_client_pool);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!pool)</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%);">+        INIT_LLIST_HEAD(&pool->pool);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return pool;</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%);">+/*! Initalize and connect an mcgp clien pool.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in,out] mgcp MGCP client pool descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns number of successfully initalized pool members. */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int mgcp_client_connect_pool(struct mgcp_client_pool *pool)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int pool_members_initalized = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(pool_member, &pool->pool, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Initalize client */</span><br><span style="color: hsl(120, 100%, 40%);">+                pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!pool_member->client) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLMGCP, LOGL_ERROR, "MGW %u initalization failed\n", pool_member->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</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%);">+           /* Set backpointer so that we can detect later that this MGCP client is managed</span><br><span style="color: hsl(120, 100%, 40%);">+                * by this pool. */</span><br><span style="color: hsl(120, 100%, 40%);">+           pool_member->client->pool = pool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Connect client */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (mgcp_client_connect2(pool_member->client, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLMGCP, LOGL_ERROR, "MGW %u connect failed at (%s:%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           pool_member->nr, pool_member->conf.remote_addr, pool_member->conf.remote_port);</span><br><span style="color: hsl(120, 100%, 40%);">+                 talloc_free(pool_member->client);</span><br><span style="color: hsl(120, 100%, 40%);">+                  pool_member->client = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</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%);">+           pool_members_initalized++;</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 pool_members_initalized;</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%);">+/*! register a legacy mgcp_client instance to the pool.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] pool MGCP client pool descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] mgcp MGCP client descriptor. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_pool_register_legacy(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Some applications still support the non-pooled MGW VTY configuration variant provided by</span><br><span style="color: hsl(120, 100%, 40%);">+   *  mgcp_client_vty_init(). If this is the case the mgcp_client instance created by mgcp_client_init()</span><br><span style="color: hsl(120, 100%, 40%);">+         *  can be registered here so that it will appear as if it were part of the pool. When the user actively</span><br><span style="color: hsl(120, 100%, 40%);">+       *  configures MGW pool members, the MGCP client registered here will be ignored. */</span><br><span style="color: hsl(120, 100%, 40%);">+  pool->mgcp_client_legacy = mgcp_client;</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%);">+/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a</span><br><span style="color: hsl(120, 100%, 40%);">+ * pool member that is suitable (has a client, is not blocked, has a low load). */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_client_pool_member *pool_member_picked = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int n_pool_members = llist_count(&pool->pool);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(pool_member, &pool->pool, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (pool_member->blocked == false && pool_member->client) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!pool_member_picked) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            pool_member_picked = pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (pool_member_picked->refcount > pool_member->refcount)</span><br><span style="color: hsl(120, 100%, 40%);">+                             pool_member_picked = pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DLMGCP, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,</span><br><span style="color: hsl(120, 100%, 40%);">+                      pool_member->nr);</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%);">+   if (pool_member_picked) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLMGCP, LOGL_DEBUG, "MGW pool has %u members -- using MGW %u (active calls: %u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 n_pool_members, pool_member_picked->nr, pool_member_picked->refcount);</span><br><span style="color: hsl(120, 100%, 40%);">+             return pool_member_picked;</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%);">+   LOGP(DLMGCP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+           "MGW pool has %u members, but no functional MGW pool member found -- check configuration!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+       n_pool_members);</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! get an MGCP client from the pool.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in,out] pool MGCP client pool descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns MGCP client descriptor, NULL if no member was found (empty pool). */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* When the pool is empty, return a legacy MGCP client if it is registered. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (llist_empty(&pool->pool) && pool->mgcp_client_legacy) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (legacy) MGW\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return pool->mgcp_client_legacy;</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%);">+   /* Abort when the pool is empty */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (llist_empty(&pool->pool)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Pick a suitable pool member */</span><br><span style="color: hsl(120, 100%, 40%);">+     pool_member = mgcp_client_pool_pick(pool);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (pool_member) {</span><br><span style="color: hsl(120, 100%, 40%);">+            pool_member->refcount++;</span><br><span style="color: hsl(120, 100%, 40%);">+           return pool_member->client;</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 NULL;</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%);">+/*! put an MGCP client back into the pool (decrement reference counter).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in,out] pool MGCP client pool descriptor.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] mgcp MGCP client descriptor. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_pool_put(struct mgcp_client *mgcp_client)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! This function is able to detect atomatically to which pool the mgcp_client belongs. If the mgcp_client does</span><br><span style="color: hsl(120, 100%, 40%);">+        *  not belong to a pool at all, the function call will have no effect. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_client_pool *pool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!mgcp_client)</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%);">+     if (mgcp_client->pool)</span><br><span style="color: hsl(120, 100%, 40%);">+             pool = mgcp_client->pool;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</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%);">+     llist_for_each_entry(pool_member, &pool->pool, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (pool_member->client == mgcp_client) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (pool_member->refcount == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          LOGP(DLMGCP, LOGL_ERROR, "MGW %u has invalid refcount\n", pool_member->nr);</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%);">+                     pool_member->refcount--;</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>diff --git a/src/libosmo-mgcp-client/mgcp_client_vty.c b/src/libosmo-mgcp-client/mgcp_client_vty.c</span><br><span>index 6ef336b..fc4cf68 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>@@ -29,11 +29,25 @@</span><br><span> #include <osmocom/core/utils.h></span><br><span> </span><br><span> #include <osmocom/mgcp_client/mgcp_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_internal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_pool_internal.h></span><br><span> </span><br><span> #define MGW_STR MGCP_CLIENT_MGW_STR</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void *global_mgcp_client_ctx = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-struct mgcp_client_conf *global_mgcp_client_conf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+static void *global_mgcp_client_ctx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct mgcp_client_conf *global_mgcp_client_conf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct cmd_node global_mgcp_mgw_node_pool;</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *global_mgcp_client_indent_pool = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct mgcp_client_pool *global_mgcp_client_pool = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GET_MGCP_CLIENT_CONFIG_PTR() \</span><br><span style="color: hsl(120, 100%, 40%);">+do { \</span><br><span style="color: hsl(120, 100%, 40%);">+     if (vty->node == global_mgcp_mgw_node_pool.node) \</span><br><span style="color: hsl(120, 100%, 40%);">+         conf = vty->index; \</span><br><span style="color: hsl(120, 100%, 40%);">+       else \</span><br><span style="color: hsl(120, 100%, 40%);">+                conf = global_mgcp_client_conf; \</span><br><span style="color: hsl(120, 100%, 40%);">+} while (0) \</span><br><span> </span><br><span> DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,</span><br><span>       "mgw local-ip " VTY_IPV46_CMD,</span><br><span>@@ -41,8 +55,12 @@</span><br><span>       "local bind IPv4 address\n"</span><br><span>       "local bind IPv6 address\n")</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct mgcp_client_conf *conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      osmo_talloc_replace_string(global_mgcp_client_ctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 (char**)&global_mgcp_client_conf->local_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  (char**)&conf->local_addr,</span><br><span>                                    argv[0]);</span><br><span>         return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -56,7 +74,11 @@</span><br><span>       MGW_STR "local port to connect to MGW from\n"</span><br><span>       "local bind port\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     global_mgcp_client_conf->local_port = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_client_conf *conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       conf->local_port = atoi(argv[0]);</span><br><span>         return CMD_SUCCESS;</span><br><span> }</span><br><span> ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,</span><br><span>@@ -70,9 +92,12 @@</span><br><span>       "remote IPv4 address\n"</span><br><span>       "remote IPv6 address\n")</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_client_conf *conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      osmo_talloc_replace_string(global_mgcp_client_ctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 (char**)&global_mgcp_client_conf->remote_addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+                             (char**)&conf->remote_addr, argv[0]);</span><br><span>      return CMD_SUCCESS;</span><br><span> }</span><br><span> ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,</span><br><span>@@ -85,7 +110,11 @@</span><br><span>       MGW_STR "remote port to reach the MGW at\n"</span><br><span>       "remote port\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- global_mgcp_client_conf->remote_port = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct mgcp_client_conf *conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       conf->remote_port = atoi(argv[0]);</span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span> ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,</span><br><span>@@ -135,11 +164,14 @@</span><br><span>       MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"</span><br><span>       "Domain name, should be alphanumeric.\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  if (osmo_strlcpy(global_mgcp_client_conf->endpoint_domain_name, argv[0],</span><br><span style="color: hsl(0, 100%, 40%);">-                      sizeof(global_mgcp_client_conf->endpoint_domain_name))</span><br><span style="color: hsl(0, 100%, 40%);">-          >= sizeof(global_mgcp_client_conf->endpoint_domain_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_client_conf *conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (osmo_strlcpy(conf->endpoint_domain_name, argv[0], sizeof(conf->endpoint_domain_name))</span><br><span style="color: hsl(120, 100%, 40%);">+           >= sizeof(conf->endpoint_domain_name)) {</span><br><span>           vty_out(vty, "%% Error: 'mgw endpoint-domain' name too long, max length is %zu: '%s'%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                      sizeof(global_mgcp_client_conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                  sizeof(conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);</span><br><span>            return CMD_WARNING;</span><br><span>  }</span><br><span>    return CMD_SUCCESS;</span><br><span>@@ -154,9 +186,12 @@</span><br><span> {</span><br><span>      int rc;</span><br><span>      struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_client_conf *conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span> </span><br><span>    /* stop when the address is already in the list */</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {</span><br><span>          if (strcmp(argv[0], reset_ep->name) == 0) {</span><br><span>                       vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);</span><br><span>                      return CMD_WARNING;</span><br><span>@@ -181,7 +216,7 @@</span><br><span>            return CMD_WARNING;</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   llist_add_tail(&reset_ep->list, &global_mgcp_client_conf->reset_epnames);</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_add_tail(&reset_ep->list, &conf->reset_epnames);</span><br><span> </span><br><span>     return CMD_SUCCESS;</span><br><span> }</span><br><span>@@ -194,8 +229,11 @@</span><br><span> {</span><br><span>         struct reset_ep *reset_ep;</span><br><span>   struct reset_ep *reset_ep_del = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_client_conf *conf;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+        GET_MGCP_CLIENT_CONFIG_PTR();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {</span><br><span>          if (strcmp(argv[0], reset_ep->name) == 0) {</span><br><span>                       reset_ep_del = reset_ep;</span><br><span>                     break;</span><br><span>@@ -213,45 +251,47 @@</span><br><span>       return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int mgcp_client_config_write(struct vty *vty, const char *indent)</span><br><span style="color: hsl(120, 100%, 40%);">+static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)</span><br><span> {</span><br><span>      const char *addr;</span><br><span>    int port;</span><br><span>    struct reset_ep *reset_ep;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  addr = global_mgcp_client_conf->local_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+        addr = conf->local_addr;</span><br><span>  if (addr)</span><br><span>            vty_out(vty, "%smgw local-ip %s%s", indent, addr,</span><br><span>                  VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   port = global_mgcp_client_conf->local_port;</span><br><span style="color: hsl(120, 100%, 40%);">+        port = conf->local_port;</span><br><span>  if (port >= 0)</span><br><span>            vty_out(vty, "%smgw local-port %u%s", indent,</span><br><span>                      (uint16_t)port, VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       addr = global_mgcp_client_conf->remote_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+       addr = conf->remote_addr;</span><br><span>         if (addr)</span><br><span>            vty_out(vty, "%smgw remote-ip %s%s", indent, addr,</span><br><span>                         VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-   port = global_mgcp_client_conf->remote_port;</span><br><span style="color: hsl(120, 100%, 40%);">+       port = conf->remote_port;</span><br><span>         if (port >= 0)</span><br><span>            vty_out(vty, "%smgw remote-port %u%s", indent,</span><br><span>                     (uint16_t)port, VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       if (global_mgcp_client_conf->endpoint_domain_name[0])</span><br><span style="color: hsl(120, 100%, 40%);">+      if (conf->endpoint_domain_name[0])</span><br><span>                vty_out(vty, "%smgw endpoint-domain %s%s", indent,</span><br><span style="color: hsl(0, 100%, 40%);">-                    global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                       conf->endpoint_domain_name, VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        llist_for_each_entry(reset_ep, &global_mgcp_client_conf->reset_epnames, list)</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(reset_ep, &conf->reset_epnames, list)</span><br><span>            vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);</span><br><span> </span><br><span>     return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)</span><br><span style="color: hsl(120, 100%, 40%);">+int mgcp_client_config_write(struct vty *vty, const char *indent)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        global_mgcp_client_ctx = talloc_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-    global_mgcp_client_conf = conf;</span><br><span style="color: hsl(120, 100%, 40%);">+       return config_write(vty, indent, global_mgcp_client_conf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void vty_init_common(void *talloc_ctx, int node)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span>        install_lib_element(node, &cfg_mgw_local_ip_cmd);</span><br><span>        install_lib_element(node, &cfg_mgw_local_port_cmd);</span><br><span>      install_lib_element(node, &cfg_mgw_remote_ip_cmd);</span><br><span>@@ -262,6 +302,14 @@</span><br><span>        install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);</span><br><span>   install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_vty_add_cmds();</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%);">+void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        global_mgcp_client_ctx = talloc_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+  global_mgcp_client_conf = conf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    /* deprecated 'mgcpgw' commands */</span><br><span>   install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);</span><br><span>     install_lib_element(node, &cfg_mgcpgw_local_port_cmd);</span><br><span>@@ -270,5 +318,226 @@</span><br><span>   install_lib_element(node, &cfg_mgcpgw_endpoint_range_cmd);</span><br><span>       install_lib_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   osmo_fsm_vty_add_cmds();</span><br><span style="color: hsl(120, 100%, 40%);">+      vty_init_common(talloc_ctx, node);</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%);">+static int config_write_pool(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int indent_buf_len = strlen(global_mgcp_client_indent_pool) + 1 + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *indent = talloc_zero_size(vty, indent_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(indent, indent_buf_len, "%s ", global_mgcp_client_indent_pool);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%smgw %u%s", global_mgcp_client_indent_pool, pool_member->nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                config_write(vty, indent, &pool_member->conf);</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%);">+   talloc_free(indent);</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%);">+/* Lookup the selected MGCP client config by its reference number */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_client_pool_member *pool_member = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_client_pool_member *pool_member_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (pool_member_tmp->nr == nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   pool_member = pool_member_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</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%);">+   return pool_member;</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_ATTR(cfg_mgw,</span><br><span style="color: hsl(120, 100%, 40%);">+    cfg_mgw_cmd, "mgw <0-255>", "Select a MGCP client config to setup\n" "reference number", CMD_ATTR_IMMEDIATE)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int nr = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        pool_member = pool_member_by_nr(nr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!pool_member) {</span><br><span style="color: hsl(120, 100%, 40%);">+           pool_member = talloc_zero(global_mgcp_client_ctx, struct mgcp_client_pool_member);</span><br><span style="color: hsl(120, 100%, 40%);">+            OSMO_ASSERT(pool_member);</span><br><span style="color: hsl(120, 100%, 40%);">+             mgcp_client_conf_init(&pool_member->conf);</span><br><span style="color: hsl(120, 100%, 40%);">+             pool_member->nr = nr;</span><br><span style="color: hsl(120, 100%, 40%);">+              llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);</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%);">+   vty->index = &pool_member->conf;</span><br><span style="color: hsl(120, 100%, 40%);">+    vty->index_sub = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     vty->node = global_mgcp_mgw_node_pool.node;</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_ATTR(cfg_no_mgw,</span><br><span style="color: hsl(120, 100%, 40%);">+         cfg_no_mgw_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "no mgw <0-255>", "Select a MGCP client config to remove\n" "reference number", CMD_ATTR_IMMEDIATE)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int nr = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        pool_member = pool_member_by_nr(nr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!pool_member) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% no such MGCP client 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%);">+   /* Make sure that there are no ongoing calls */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (pool_member->refcount > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, "%% MGCP client (MGW %u) is still serving ongoing calls -- can't remove it now!%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        pool_member->nr, 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%);">+   llist_del(&pool_member->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pool_member->client) {</span><br><span style="color: hsl(120, 100%, 40%);">+         mgcp_client_disconnect(pool_member->client);</span><br><span style="color: hsl(120, 100%, 40%);">+               talloc_free(pool_member->client);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     talloc_free(pool_member);</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_ATTR(mgw_reconnect, mgw_reconnect_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+           "mgw <0-255> reconnect",</span><br><span style="color: hsl(120, 100%, 40%);">+      MGW_STR "reconfigure and reconnect MGCP client (will drop ongoing calls)\n", CMD_ATTR_IMMEDIATE)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int nr = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_client_pool_member *pool_member = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pool_member = pool_member_by_nr(nr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!pool_member) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% no such MGCP client 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%);">+   /* Make sure that there are no ongoing calls */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (pool_member->refcount > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, "%% MGCP client (MGW %u) is still serving ongoing calls -- can't reconnect it now!%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     pool_member->nr, 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%);">+   /* Get rid of a possibly existing old MGCP client instance first */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (pool_member->client) {</span><br><span style="color: hsl(120, 100%, 40%);">+         mgcp_client_disconnect(pool_member->client);</span><br><span style="color: hsl(120, 100%, 40%);">+               talloc_free(pool_member->client);</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%);">+   /* Create a new MGCP client instance with the current config */</span><br><span style="color: hsl(120, 100%, 40%);">+       pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!pool_member->client) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %u initalization failed\n", pool_member->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "%% MGCP client initalization failed ('%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%);">+   /* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */</span><br><span style="color: hsl(120, 100%, 40%);">+      pool_member->client->pool = global_mgcp_client_pool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Connect client */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (mgcp_client_connect(pool_member->client)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %u connect failed at (%s:%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  pool_member->nr, pool_member->conf.remote_addr, pool_member->conf.remote_port);</span><br><span style="color: hsl(120, 100%, 40%);">+         talloc_free(pool_member->client);</span><br><span style="color: hsl(120, 100%, 40%);">+          pool_member->client = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, "%% MGCP client initalization failed ('%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 style="color: hsl(120, 100%, 40%);">+DEFUN_ATTR(mgw_block, mgw_block_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+           "mgw <0-255> block",</span><br><span style="color: hsl(120, 100%, 40%);">+          MGW_STR "block MGCP client so that it won't be used for new calls\n", CMD_ATTR_IMMEDIATE)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int nr = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_client_pool_member *pool_member = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pool_member = pool_member_by_nr(nr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!pool_member) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% no such MGCP client 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%);">+   pool_member->blocked = true;</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_ATTR(mgw_unblock, mgw_unblock_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "mgw <0-255> unblock",</span><br><span style="color: hsl(120, 100%, 40%);">+        MGW_STR "unblock MGCP client so that it will be available for new calls\n", CMD_ATTR_IMMEDIATE)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int nr = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mgcp_client_pool_member *pool_member = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pool_member = pool_member_by_nr(nr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!pool_member) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% no such MGCP client 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%);">+   pool_member->blocked = false;</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(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mgcp_client_pool_member *pool_member;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_legacy) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%%  (pool is empty, legacy MGCP client will be used)%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (llist_empty(&global_mgcp_client_pool->pool)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);</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%);">+   llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%%  MGW %u%s", pool_member->nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",</span><br><span style="color: hsl(120, 100%, 40%);">+                 VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "%%   service:       %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%%   ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);</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%);">+/*! Set up MGCP client VTY (pooled)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  (called once at startup by the application process).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] parent_node identifier of the parent node on which the mgw node appears.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] mgw_node identifier that should be used with the newly installed MGW node.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] indent indentation string to match the indentation in the VTY config</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_vty_init_pool(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    global_mgcp_mgw_node_pool = (struct cmd_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+               .node = mgw_node,</span><br><span style="color: hsl(120, 100%, 40%);">+             .prompt = "%s(config-mgw)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+               .vtysh = 1,</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%);">+  global_mgcp_client_ctx = pool;</span><br><span style="color: hsl(120, 100%, 40%);">+        global_mgcp_client_pool = pool;</span><br><span style="color: hsl(120, 100%, 40%);">+       global_mgcp_client_indent_pool = indent;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    install_lib_element(parent_node, &cfg_mgw_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_lib_element(parent_node, &cfg_no_mgw_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_node(&global_mgcp_mgw_node_pool, config_write_pool);</span><br><span style="color: hsl(120, 100%, 40%);">+      vty_init_common(global_mgcp_client_ctx, mgw_node);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  install_lib_element(ENABLE_NODE, &mgw_reconnect_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_lib_element(ENABLE_NODE, &mgw_block_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     install_lib_element_ve(&mgw_snow_cmd);</span><br><span> }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25120">change 25120</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/+/25120"/><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: Icaaba0e470e916eefddfee750b83f5f65291a6b0 </div>
<div style="display:none"> Gerrit-Change-Number: 25120 </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>