libosmo-mgcp-client: extend the mgcp_client for MGW pooling

At the moment the MGCP Client only supports one MGW per application.
Depending on the requirements of the application one MGW might not offer
the performance needed. Lets add support for an MGCP Client pool that is
backward compatible to existing applications.

Change-Id: Icaaba0e470e916eefddfee750b83f5f65291a6b0
Related: SYS#5091
diff --git a/include/Makefile.am b/include/Makefile.am
index 457ac3f..eb262a6 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -6,6 +6,7 @@
 	osmocom/mgcp_client/mgcp_client.h \
 	osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 	osmocom/mgcp_client/mgcp_client_fsm.h \
+	osmocom/mgcp_client/mgcp_client_pool.h \
 	osmocom/mgcp/mgcp.h \
 	osmocom/mgcp/mgcp_common.h \
 	osmocom/mgcp/osmux.h \
diff --git a/include/osmocom/mgcp_client/Makefile.am b/include/osmocom/mgcp_client/Makefile.am
index d303ddf..90b1bd7 100644
--- a/include/osmocom/mgcp_client/Makefile.am
+++ b/include/osmocom/mgcp_client/Makefile.am
@@ -4,6 +4,7 @@
 
 noinst_HEADERS = \
 	mgcp_client_internal.h \
+	mgcp_client_pool_internal.h \
 	$(NULL)
 
 mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h
index e9fe0ae..4d162d0 100644
--- a/include/osmocom/mgcp_client/mgcp_client.h
+++ b/include/osmocom/mgcp_client/mgcp_client.h
@@ -136,6 +136,8 @@
 struct mgcp_client *mgcp_client_init(void *ctx,
 				     struct mgcp_client_conf *conf);
 int mgcp_client_connect(struct mgcp_client *mgcp);
+int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
+void mgcp_client_disconnect(struct mgcp_client *mgcp);
 
 const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
diff --git a/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h b/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
index 78e3a41..f21f40e 100644
--- a/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
+++ b/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
@@ -47,6 +47,7 @@
 const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
+struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
 
 extern const struct value_string osmo_mgcp_verb_names[];
 static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)
diff --git a/include/osmocom/mgcp_client/mgcp_client_fsm.h b/include/osmocom/mgcp_client/mgcp_client_fsm.h
index e315753..ade4f49 100644
--- a/include/osmocom/mgcp_client/mgcp_client_fsm.h
+++ b/include/osmocom/mgcp_client/mgcp_client_fsm.h
@@ -69,5 +69,6 @@
 void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 
 const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
+struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
 
 const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
diff --git a/include/osmocom/mgcp_client/mgcp_client_internal.h b/include/osmocom/mgcp_client/mgcp_client_internal.h
index 44b9022..73e3de2 100644
--- a/include/osmocom/mgcp_client/mgcp_client_internal.h
+++ b/include/osmocom/mgcp_client/mgcp_client_internal.h
@@ -16,6 +16,7 @@
 	mgcp_trans_id_t next_trans_id;
 	struct llist_head responses_pending;
 	struct llist_head inuse_endpoints;
+	struct mgcp_client_pool *pool;
 };
 
 struct mgcp_inuse_endpoint {
diff --git a/include/osmocom/mgcp_client/mgcp_client_pool.h b/include/osmocom/mgcp_client/mgcp_client_pool.h
new file mode 100644
index 0000000..d0a6ff4
--- /dev/null
+++ b/include/osmocom/mgcp_client/mgcp_client_pool.h
@@ -0,0 +1,11 @@
+#pragma once
+
+struct mgcp_client;
+struct mgcp_client_pool;
+
+struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
+void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
+unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
+void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
+struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
+void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
diff --git a/include/osmocom/mgcp_client/mgcp_client_pool_internal.h b/include/osmocom/mgcp_client/mgcp_client_pool_internal.h
new file mode 100644
index 0000000..c58ec02
--- /dev/null
+++ b/include/osmocom/mgcp_client/mgcp_client_pool_internal.h
@@ -0,0 +1,43 @@
+#pragma once
+
+/* Struct to handle a member of a pool of MGWs. */
+struct mgcp_client_pool_member {
+	struct llist_head list;
+
+	/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
+	 * the log. */
+	unsigned int nr;
+
+	/* MGCP client configuration, this is not the running configuration, when mgcp_client_init() is executed, a
+	 * copy of this config is created. */
+	struct mgcp_client_conf conf;
+
+	/* MGCP client descriptor, will be automatically allocated when mgcp_client_pool_connect() is called. (the MGCP
+	 * client is connected when this pointer is populated) */
+	struct mgcp_client *client;
+
+	/* A pool member may be set as 'blocked' from the VTY, this means that the pool member may still work and serve
+	 * ongoing calls, but it won't be picked from the pool anymore. */
+	bool blocked;
+
+	/* Reference counter to count how often this pool member is currently picked. */
+	unsigned int refcount;
+};
+
+/* Struct to handle a pool of MGWs. (Use _pool functions) */
+struct mgcp_client_pool {
+
+	/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
+	 * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
+	struct mgcp_client *mgcp_client_single;
+
+	/* A list that manages the pool members (see above) */
+	struct llist_head pool;
+
+	/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
+	 * mgcp_client_pool_vty_init() */
+	char *vty_indent;
+
+	/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
+	struct cmd_node *vty_node;
+};