<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-mgw/+/25120">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  osmith: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">libosmo-mgcp-client: extend the mgcp_client for MGW pooling<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, 592 insertions(+), 27 deletions(-)<br><br></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 e9fe0ae..4d162d0 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>@@ -136,6 +136,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 44b9022..73e3de2 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>@@ -16,6 +16,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..d0a6ff4</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_pool_alloc(void *talloc_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_pool_vty_init(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_pool_connect(struct mgcp_client_pool *pool);</span><br><span style="color: hsl(120, 100%, 40%);">+void mgcp_client_pool_register_single(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..c58ec02</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_pool_internal.h</span><br><span>@@ -0,0 +1,43 @@</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 pool from the VTY and to identify it in</span><br><span style="color: hsl(120, 100%, 40%);">+         * 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, when mgcp_client_init() is executed, a</span><br><span style="color: hsl(120, 100%, 40%);">+    * copy of this config is 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 mgcp_client_pool_connect() is called. (the MGCP</span><br><span style="color: hsl(120, 100%, 40%);">+        * client is connected 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 that the pool member may still work and serve</span><br><span style="color: hsl(120, 100%, 40%);">+        * ongoing calls, but it won't 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 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using</span><br><span style="color: hsl(120, 100%, 40%);">+      * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_client *mgcp_client_single;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* A list that manages the pool members (see above) */</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 style="color: hsl(120, 100%, 40%);">+     /* String to use for indentation when writing the configuration file to the VTY. This field is populated by</span><br><span style="color: hsl(120, 100%, 40%);">+    * mgcp_client_pool_vty_init() */</span><br><span style="color: hsl(120, 100%, 40%);">+     char *vty_indent;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct cmd_node *vty_node;</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 9b6c133..2bed90f 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>@@ -875,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>@@ -895,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, 99);</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>@@ -921,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..9311ac9</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_pool.c</span><br><span>@@ -0,0 +1,186 @@</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_pool_vty_init(). 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_pool_alloc(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%);">+/*! Initialize and connect an mcgp client 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 initialized pool members. */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int mgcp_client_pool_connect(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_initialized = 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%);">+               /* Initialize 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 initialization 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_initialized++;</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_initialized;</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 single 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_single(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. (The registration of</span><br><span style="color: hsl(120, 100%, 40%);">+         *  multiple singe mgcp_client instances is not possible.) */</span><br><span style="color: hsl(120, 100%, 40%);">+ pool->mgcp_client_single = 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 (increment 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%);">+ *  \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 an MGCP client is taken from the pool it is still available for other calls. In fact only a reference</span><br><span style="color: hsl(120, 100%, 40%);">+         *  counter is incremented to keep track on how many references to a specific MGCP client are currently used</span><br><span style="color: hsl(120, 100%, 40%);">+   *  by the application code. */</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 single MGCP client if it is registered. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (llist_empty(&pool->pool) && pool->mgcp_client_single) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return pool->mgcp_client_single;</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%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function is able to detect automatically 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%);">+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%);">+ 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 9b33eeb..68a3208 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>@@ -24,17 +24,36 @@</span><br><span> #include <stdlib.h></span><br><span> #include <talloc.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/vty.h></span><br><span> #include <osmocom/vty/command.h></span><br><span> #include <osmocom/vty/misc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span> </span><br><span> #include <osmocom/mgcp_client/mgcp_client.h></span><br><span> #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%);">+/* Only common (non-pooled) VTY connands will use this talloc context. All</span><br><span style="color: hsl(120, 100%, 40%);">+ * pooled VTY commands will use the pool (global_mgcp_client_pool) as</span><br><span style="color: hsl(120, 100%, 40%);">+ * talloc context. */</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* MGCP Client configuration used with mgcp_client_vty_init(). (This pointer</span><br><span style="color: hsl(120, 100%, 40%);">+ * points to user provided memory, so it cannot be used as talloc context.) */</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%);">+/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */</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%);">+struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)</span><br><span style="color: hsl(120, 100%, 40%);">+         return vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          return global_mgcp_client_conf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</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>@@ -42,8 +61,10 @@</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 = get_mgcp_client_config(vty);</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>@@ -57,7 +78,9 @@</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 = get_mgcp_client_config(vty);</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>@@ -71,9 +94,10 @@</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 = get_mgcp_client_config(vty);</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>@@ -86,7 +110,9 @@</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 = get_mgcp_client_config(vty);</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>@@ -136,11 +162,12 @@</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 = get_mgcp_client_config(vty);</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>@@ -155,9 +182,10 @@</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 = get_mgcp_client_config(vty);</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>@@ -182,7 +210,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 +222,9 @@</span><br><span>       "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")</span><br><span> {</span><br><span>       struct reset_ep *reset_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mgcp_client_conf *conf = get_mgcp_client_config(vty);</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>          if (strcmp(argv[0], reset_ep->name) == 0) {</span><br><span>                       llist_del(&reset_ep->list);</span><br><span>                   talloc_free(reset_ep);</span><br><span>@@ -207,44 +236,48 @@</span><br><span>       return CMD_WARNING;</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 style="color: hsl(120, 100%, 40%);">+{</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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void vty_init_common(void *talloc_ctx, int node)</span><br><span> {</span><br><span>        global_mgcp_client_ctx = talloc_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-    global_mgcp_client_conf = conf;</span><br><span> </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>@@ -256,6 +289,13 @@</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_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>@@ -264,5 +304,233 @@</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 *pool = global_mgcp_client_pool;</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(pool->vty_indent) + 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);</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%);">+         vty_out(vty, "%smgw %u%s", pool->vty_indent, 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_pool, 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_client_pool->vty_node->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\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_single) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%%  (pool is empty, single 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_pool_vty_init(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%);">+    /* Never allow this function to be called twice on the same pool */</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(!pool->vty_indent);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!pool->vty_node);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pool->vty_indent = talloc_strdup(pool, indent);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(pool->vty_indent);</span><br><span style="color: hsl(120, 100%, 40%);">+     pool->vty_node = talloc_zero(pool, struct cmd_node);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(pool->vty_node);</span><br><span style="color: hsl(120, 100%, 40%);">+       pool->vty_node->node = mgw_node;</span><br><span style="color: hsl(120, 100%, 40%);">+        pool->vty_node->vtysh = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      pool->vty_node->prompt = talloc_strdup(pool->vty_node, "%s(config-mgw)# ");</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      install_node(pool->vty_node, config_write_pool);</span><br><span style="color: hsl(120, 100%, 40%);">+   vty_init_common(pool, 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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  global_mgcp_client_pool = pool;</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: 15 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>