<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13590">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">move MGW endpoint FSM from osmo-bsc to here<br><br>Move mgw_endpoint_fsm from osmo-bsc here as osmo_mgcpc_ep_fsm. Apply various<br>renames for consistency. Use osmo_tdef from libosmocore instead of osmo-bsc's<br>(so far) local T_defs API.<br><br>Change T23042 to T2427001, which is a slightly less arbitrary number and<br>slightly more extendable in the future (2427 corresponds to the default MGCP<br>port at osmo-mgw, 001 is the first MGCP timer and so far the only one).<br><br>Change-Id: I9a3effd38e72841529df6c135c077116981dea36<br>---<br>M include/Makefile.am<br>A include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h<br>M include/osmocom/mgcp_client/mgcp_client_fsm.h<br>M src/libosmo-mgcp-client/Makefile.am<br>A src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c<br>M src/libosmo-mgcp-client/mgcp_client_fsm.c<br>6 files changed, 866 insertions(+), 0 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 c34553a..2daaf20 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -4,6 +4,7 @@</span><br><span> </span><br><span> nobase_include_HEADERS = \</span><br><span>     osmocom/mgcp_client/mgcp_client.h \</span><br><span style="color: hsl(120, 100%, 40%);">+   osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \</span><br><span>     osmocom/mgcp_client/mgcp_client_fsm.h \</span><br><span>      osmocom/mgcp_client/mgcp_common.h \</span><br><span>  osmocom/mgcp/mgcp.h \</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>new file mode 100644</span><br><span>index 0000000..73de292</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h</span><br><span>@@ -0,0 +1,47 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* FSM to manage multiple connections of an MGW endpoint */</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%);">+#include <osmocom/mgcp_client/mgcp_client_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_MGCPC_EP(ep, level, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGPFSML(ep->fi, level, "%s " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_mgcpc_ep_name(ep), ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+  } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep_ci;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_tdef;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep *osmo_mgcpc_ep_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         struct mgcp_client *mgcp_client,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const struct osmo_tdef *T_defs,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const char *fsm_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   const char *endpoint_str_fmt, ...);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_add(struct osmo_mgcpc_ep *ep, const char *label_fmt, ...);</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci);</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,</span><br><span style="color: hsl(120, 100%, 40%);">+                             enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct osmo_fsm_inst *notify,</span><br><span style="color: hsl(120, 100%, 40%);">+                         uint32_t event_success, uint32_t event_failure,</span><br><span style="color: hsl(120, 100%, 40%);">+                       void *notify_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Dispatch a DLCX for the given connection.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ci  Connection identifier as obtained from osmo_mgcpc_ep_ci_add().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_mgcpc_ep_ci_request(ci, MGCP_VERB_DLCX, NULL, NULL, 0, 0, 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%);">+void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string osmo_mgcp_verb_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)</span><br><span style="color: hsl(120, 100%, 40%);">+{ return get_value_string(osmo_mgcp_verb_names, 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 dabfcca..e170a25 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>@@ -64,3 +64,5 @@</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);</span><br><span>diff --git a/src/libosmo-mgcp-client/Makefile.am b/src/libosmo-mgcp-client/Makefile.am</span><br><span>index e59da2f..1529853 100644</span><br><span>--- a/src/libosmo-mgcp-client/Makefile.am</span><br><span>+++ b/src/libosmo-mgcp-client/Makefile.am</span><br><span>@@ -30,6 +30,7 @@</span><br><span>     mgcp_client.c \</span><br><span>      mgcp_client_vty.c \</span><br><span>  mgcp_client_fsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+   mgcp_client_endpoint_fsm.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_endpoint_fsm.c b/src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..76552fb</span><br><span>--- /dev/null</span><br><span>+++ b/src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c</span><br><span>@@ -0,0 +1,793 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* FSM to manage multiple connections of an MGW endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2018-2019 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: Neels Hofmeyr <neels@hofmeyr.de></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 Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 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 Affero 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 Affero 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 <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/byteswap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_CI(ci, level, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ci || !ci->ep) \</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLGLOBAL, level, "(unknown MGW endpoint) " fmt, ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+    else \</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_MGCPC_EP(ci->ep, level, "CI[%d] %s%s%s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                     (int)(ci - ci->ep->ci), \</span><br><span style="color: hsl(120, 100%, 40%);">+                       ci->label ? : "-", \</span><br><span style="color: hsl(120, 100%, 40%);">+                     ci->mgcp_ci_str[0] ? " CI=" : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                    ci->mgcp_ci_str[0] ? ci->mgcp_ci_str : "", \</span><br><span style="color: hsl(120, 100%, 40%);">+                  ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+   } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_CI_VERB(ci, level, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ci->verb_info.addr[0]) \</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_CI(ci, level, "%s %s:%u: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_mgcp_verb_name(ci->verb), ci->verb_info.addr, ci->verb_info.port, \</span><br><span style="color: hsl(120, 100%, 40%);">+                     ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+   else \</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_CI(ci, level, "%s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_mgcp_verb_name(ci->verb), \</span><br><span style="color: hsl(120, 100%, 40%);">+                   ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+   } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum osmo_mgcpc_ep_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_MGCPC_EP_ST_UNUSED = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_MGCPC_EP_ST_IN_USE,</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%);">+enum osmo_mgcpc_ep_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+        _OSMO_MGCPC_EP_EV_LAST = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+   /* and MGW response events are allocated dynamically */</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%);">+#define FIRST_CI_EVENT (_OSMO_MGCPC_EP_EV_LAST + (_OSMO_MGCPC_EP_EV_LAST & 1)) /* rounded up to even nr */</span><br><span style="color: hsl(120, 100%, 40%);">+#define USABLE_CI ((32 - FIRST_CI_EVENT)/2)</span><br><span style="color: hsl(120, 100%, 40%);">+#define EV_TO_CI_IDX(event) ((event - FIRST_CI_EVENT) / 2)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CI_EV_SUCCESS(ci) (FIRST_CI_EVENT + (((ci) - ci->ep->ci) * 2))</span><br><span style="color: hsl(120, 100%, 40%);">+#define CI_EV_FAILURE(ci) (CI_EV_SUCCESS(ci) + 1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm osmo_mgcpc_ep_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! One connection on an endpoint, corresponding to a connection identifier (CI) as returned by the MGW.</span><br><span style="color: hsl(120, 100%, 40%);">+ * An endpoint has a fixed number of slots of these, which may or may not be in use.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep_ci {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_mgcpc_ep *ep;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bool occupied;</span><br><span style="color: hsl(120, 100%, 40%);">+        char label[64];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fsm_inst *mgcp_client_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       bool pending;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool sent;</span><br><span style="color: hsl(120, 100%, 40%);">+    enum mgcp_verb verb;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mgcp_conn_peer verb_info;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *notify;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t notify_success;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t notify_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+      void *notify_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  bool got_port_info;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mgcp_conn_peer rtp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+       char mgcp_ci_str[MGCP_CONN_ID_LENGTH];</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%);">+/*! An MGW endpoint with N connections, like "rtpbridge/23@mgw". */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep {</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! MGCP client connection to the MGW. */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct mgcp_client *mgcp_client;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Endpoint string; at first this might be a wildcard, and upon the first CRCX OK response, this will reflect</span><br><span style="color: hsl(120, 100%, 40%);">+         * the endpoint name returned by the MGW. */</span><br><span style="color: hsl(120, 100%, 40%);">+  char endpoint[MGCP_ENDPOINT_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Timeout definitions used for this endpoint, see osmo_mgcpc_ep_fsm_timeouts. */</span><br><span style="color: hsl(120, 100%, 40%);">+    const struct osmo_tdef *T_defs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Endpoint connection slots. Note that each connection has its own set of FSM event numbers to signal success</span><br><span style="color: hsl(120, 100%, 40%);">+        * and failure, depending on its index within this array. See CI_EV_SUCCESS and CI_EV_FAILURE. */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mgcpc_ep_ci ci[USABLE_CI];</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%);">+const struct value_string osmo_mgcp_verb_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    { MGCP_VERB_CRCX, "CRCX" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { MGCP_VERB_MDCX, "MDCX" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { MGCP_VERB_DLCX, "DLCX" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { MGCP_VERB_AUEP, "AUEP" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { MGCP_VERB_RSIP, "RSIP" },</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%);">+static struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_check_ci(struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!ci)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ci->ep)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ci < ci->ep->ci || ci >= &ci->ep->ci[USABLE_CI])</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return ci;</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 struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_for_event(struct osmo_mgcpc_ep *ep, uint32_t event)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int idx;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (event < FIRST_CI_EVENT)</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  idx = EV_TO_CI_IDX(event);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (idx >= sizeof(ep->ci))</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_mgcpc_ep_check_ci(&ep->ci[idx]);</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%);">+const char *osmo_mgcpc_ep_name(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%);">+      if (ep->endpoint[0])</span><br><span style="color: hsl(120, 100%, 40%);">+               return ep->endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+       return osmo_fsm_inst_name(ep->fi);</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%);">+const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     /* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if</span><br><span style="color: hsl(120, 100%, 40%);">+   * this buffer is too small. */</span><br><span style="color: hsl(120, 100%, 40%);">+       static char buf[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!info)</span><br><span style="color: hsl(120, 100%, 40%);">+            return "NULL";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (info->endpoint[0]</span><br><span style="color: hsl(120, 100%, 40%);">+          && info->addr[0])</span><br><span style="color: hsl(120, 100%, 40%);">+              snprintf(buf, sizeof(buf), "%s:%s:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                       info->endpoint, info->addr, info->port);</span><br><span style="color: hsl(120, 100%, 40%);">+    else if (info->endpoint[0])</span><br><span style="color: hsl(120, 100%, 40%);">+                snprintf(buf, sizeof(buf), "%s", info->endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (info->addr[0])</span><br><span style="color: hsl(120, 100%, 40%);">+            snprintf(buf, sizeof(buf), "%s:%u", info->addr, info->port);</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          return "empty";</span><br><span style="color: hsl(120, 100%, 40%);">+     return buf;</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%);">+const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct mgcp_conn_peer *rtp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!ci)</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%);">+    rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rtp_info)</span><br><span style="color: hsl(120, 100%, 40%);">+         return mgcp_conn_peer_name(rtp_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_mgcpc_ep_name(ci->ep);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ci || !ci->mgcp_ci_str[0])</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return ci->mgcp_ci_str;</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 struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void fill_event_names()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (i < _OSMO_MGCPC_EP_EV_LAST)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (i < FIRST_CI_EVENT || EV_TO_CI_IDX(i) > USABLE_CI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_mgcpc_ep_fsm_event_names[i] = (struct value_string){i, "Unused"};</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%);">+             snprintf(osmo_mgcpc_ep_fsm_event_name_bufs[i], sizeof(osmo_mgcpc_ep_fsm_event_name_bufs[i]),</span><br><span style="color: hsl(120, 100%, 40%);">+                   "MGW Response for CI #%d", EV_TO_CI_IDX(i));</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_mgcpc_ep_fsm_event_names[i] = (struct value_string){i, osmo_mgcpc_ep_fsm_event_name_bufs[i]};</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%);">+/* T_defs is used to obtain an (Osmocom specific) T2427001: timeout for an MGCP response (note, 2427 corresponds to the</span><br><span style="color: hsl(120, 100%, 40%);">+ * default MGCP port in osmo-mgw). */</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  fill_event_names();</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 osmo_mgcpc_ep *osmo_mgcpc_ep_fi_mgwep(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(fi->fsm == &osmo_mgcpc_ep_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(fi->priv);</span><br><span style="color: hsl(120, 100%, 40%);">+     return fi->priv;</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%);">+/*! Allocate an osmo_mgcpc_ep FSM.</span><br><span style="color: hsl(120, 100%, 40%);">+ * MGCP messages to set up the endpoint will be sent on the given mgcp_client, as soon as the first</span><br><span style="color: hsl(120, 100%, 40%);">+ * osmo_mgcpc_ep_ci_request() is invoked.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * A typical sequence of events would be:</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *    ep = osmo_mgcpc_ep_alloc(..., mgcp_client_rtpbridge_wildcard(client));</span><br><span style="color: hsl(120, 100%, 40%);">+ *    ci_to_ran = osmo_mgcpc_ep_ci_add(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+ *    osmo_mgcpc_ep_ci_request(ci_to_ran, MGCP_VERB_CRCX, verb_info,</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             my_call_fsm, MY_EVENT_MGCP_OK, MY_EVENT_MGCP_FAIL);</span><br><span style="color: hsl(120, 100%, 40%);">+ *    ci_to_cn = osmo_mgcpc_ep_ci_add(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+ *    osmo_mgcpc_ep_ci_request(ci_to_cn, MGCP_VERB_CRCX, verb_info,</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             my_call_fsm, MY_EVENT_MGCP_OK, MY_EVENT_MGCP_FAIL);</span><br><span style="color: hsl(120, 100%, 40%);">+ *    ...</span><br><span style="color: hsl(120, 100%, 40%);">+ *    osmo_mgcpc_ep_ci_request(ci_to_ran, MGCP_VERB_MDCX, ...);</span><br><span style="color: hsl(120, 100%, 40%);">+ *    ...</span><br><span style="color: hsl(120, 100%, 40%);">+ *    osmo_mgcpc_ep_clear(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+ *    ep = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param parent  Parent FSM.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param parent_term_event  Event to dispatch to the parent on termination of this FSM instance.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mgcp_client  Connection to the MGW.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param T_defs  Timeout definitions to be used for FSM states, see osmo_mgcpc_ep_fsm_timeouts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param fsm_id  FSM instance ID.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param endpoint_str_fmt  The endpoint string format to send to the MGW upon the first CRCX.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                          See mgcp_client_rtpbridge_wildcard() for "rtpbridge" endpoints.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep *osmo_mgcpc_ep_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          struct mgcp_client *mgcp_client,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const struct osmo_tdef *T_defs,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const char *fsm_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   const char *endpoint_str_fmt, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       va_list ap;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mgcpc_ep *ep;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!mgcp_client)</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%);">+        fi = osmo_fsm_inst_alloc_child(&osmo_mgcpc_ep_fsm, parent, parent_term_event);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fsm_inst_update_id(fi, fsm_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ep = talloc_zero(fi, struct osmo_mgcpc_ep);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    *ep = (struct osmo_mgcpc_ep){</span><br><span style="color: hsl(120, 100%, 40%);">+         .mgcp_client = mgcp_client,</span><br><span style="color: hsl(120, 100%, 40%);">+           .fi = fi,</span><br><span style="color: hsl(120, 100%, 40%);">+             .T_defs = T_defs,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+    fi->priv = ep;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   va_start(ap, endpoint_str_fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = vsnprintf(ep->endpoint, sizeof(ep->endpoint), endpoint_str_fmt ? : "", ap);</span><br><span style="color: hsl(120, 100%, 40%);">+      va_end(ap);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc <= 0 || rc >= sizeof(ep->endpoint)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_MGCPC_EP(ep, LOGL_ERROR, "Endpoint name too long or too short: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ep->endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_term(ep->fi, OSMO_FSM_TERM_ERROR, 0);</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%);">+   return ep;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Add a connection to an endpoint.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Allocate a connection identifier slot in the osmo_mgcpc_ep instance, do not yet dispatch a CRCX.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The CRCX is dispatched only upon the first osmo_mgcpc_ep_ci_request().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ep  Parent endpoint instance.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param label_fmt  Label for logging.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_add(struct osmo_mgcpc_ep *ep,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const char *label_fmt, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  va_list ap;</span><br><span style="color: hsl(120, 100%, 40%);">+   int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_mgcpc_ep_ci *ci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < USABLE_CI; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ci = &ep->ci[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ci->occupied || ci->mgcp_client_fi)</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%);">+           *ci = (struct osmo_mgcpc_ep_ci){</span><br><span style="color: hsl(120, 100%, 40%);">+                      .ep = ep,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .occupied = true,</span><br><span style="color: hsl(120, 100%, 40%);">+             };</span><br><span style="color: hsl(120, 100%, 40%);">+            if (label_fmt) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      va_start(ap, label_fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+                      vsnprintf(ci->label, sizeof(ci->label), label_fmt, ap);</span><br><span style="color: hsl(120, 100%, 40%);">+                 va_end(ap);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             return ci;</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%);">+   LOG_MGCPC_EP(ep, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+            "Cannot allocate another endpoint, all "</span><br><span style="color: hsl(120, 100%, 40%);">+            OSMO_STRINGIFY_VAL(USABLE_CI) " are in use\n");</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%);">+static bool osmo_mgcpc_ep_fsm_check_state_chg_after_response(struct osmo_fsm_inst *fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void on_failure(struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fsm_inst *notify = ci->notify;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t notify_failure = ci->notify_failure;</span><br><span style="color: hsl(120, 100%, 40%);">+      void *notify_data = ci->notify_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ci->occupied)</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%);">+     *ci = (struct osmo_mgcpc_ep_ci){</span><br><span style="color: hsl(120, 100%, 40%);">+              .ep = ci->ep,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* If this check has terminated the FSM instance, don't fire any more events to prevent use-after-free problems.</span><br><span style="color: hsl(120, 100%, 40%);">+   * The endpoint FSM does dispatch a term event to its parent, and everything should be cleaned like that. */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi))</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 (notify)</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(notify, notify_failure, notify_data);</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 on_success(struct osmo_mgcpc_ep_ci *ci, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mgcp_conn_peer *rtp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ci->occupied)</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%);">+     ci->pending = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (ci->verb) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case MGCP_VERB_CRCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* If we sent a wildcarded endpoint name on CRCX, we need to store the resulting endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+              * name here. Also, we receive the MGW's RTP port information. */</span><br><span style="color: hsl(120, 100%, 40%);">+         rtp_info = data;</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(rtp_info);</span><br><span style="color: hsl(120, 100%, 40%);">+                ci->got_port_info = true;</span><br><span style="color: hsl(120, 100%, 40%);">+          ci->rtp_info = *rtp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_strlcpy(ci->mgcp_ci_str, mgcp_conn_get_ci(ci->mgcp_client_fi),</span><br><span style="color: hsl(120, 100%, 40%);">+                     sizeof(ci->mgcp_ci_str));</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rtp_info->endpoint[0]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = osmo_strlcpy(ci->ep->endpoint, rtp_info->endpoint,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        sizeof(ci->ep->endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (rc <= 0 || rc >= sizeof(ci->ep->endpoint)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          LOG_CI(ci, LOGL_ERROR, "Unable to copy endpoint name '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      rtp_info->endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+                                osmo_mgcpc_ep_ci_dlcx(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+                            on_failure(ci);</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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</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%);">+   LOG_CI(ci, LOGL_DEBUG, "received successful response to %s: RTP=%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_mgcp_verb_name(ci->verb),</span><br><span style="color: hsl(120, 100%, 40%);">+             mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+               ci->notify ? "" : " (not sending a notification)");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ci->notify)</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_dispatch(ci->notify, ci->notify_success, ci->notify_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);</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 the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ci)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ci->got_port_info)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return &ci->rtp_info;</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 the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct mgcp_conn_peer *rtp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct sockaddr_in *sin;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!rtp_info)</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        sin = (struct sockaddr_in *)dest;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        sin->sin_family = AF_INET;</span><br><span style="color: hsl(120, 100%, 40%);">+        sin->sin_addr.s_addr = inet_addr(rtp_info->addr);</span><br><span style="color: hsl(120, 100%, 40%);">+        sin->sin_port = osmo_ntohs(rtp_info->port);</span><br><span style="color: hsl(120, 100%, 40%);">+       return true;</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%);">+static const struct osmo_tdef_state_timeout osmo_mgcpc_ep_fsm_timeouts[32] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   [OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = { .T=2427001 },</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%);">+/* Transition to a state, using the T timer defined in assignment_fsm_timeouts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The actual timeout value is in turn obtained from osmo_mgcpc_ep.T_defs.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Assumes local variable fi exists. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define osmo_mgcpc_ep_fsm_state_chg(state) \</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_tdef_fsm_inst_state_chg(fi, state, osmo_mgcpc_ep_fsm_timeouts, \</span><br><span style="color: hsl(120, 100%, 40%);">+                              ((struct osmo_mgcpc_ep*)fi->priv)->T_defs, 5)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Dispatch an actual CRCX/MDCX/DLCX message for this connection.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ci  Connection identifier as obtained from osmo_mgcpc_ep_ci_add().</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param verb  MGCP operation to dispatch.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param verb_info  Parameters for the MGCP operation.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param notify  Peer FSM instance to notify of completed/failed operation.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param event_success  Which event to dispatch to 'notify' upon OK response.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param event_failure  Which event to dispatch to 'notify' upon failure response.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param notify_data  Data pointer to pass to the event dispatch for both success and failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,</span><br><span style="color: hsl(120, 100%, 40%);">+                             enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct osmo_fsm_inst *notify,</span><br><span style="color: hsl(120, 100%, 40%);">+                         uint32_t event_success, uint32_t event_failure,</span><br><span style="color: hsl(120, 100%, 40%);">+                       void *notify_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_mgcpc_ep *ep;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mgcpc_ep_ci cleared_ci;</span><br><span style="color: hsl(120, 100%, 40%);">+   ci = osmo_mgcpc_ep_check_ci(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ci) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLGLOBAL, LOGL_ERROR, "Invalid MGW endpoint request: no ci\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                goto dispatch_error;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!verb_info && verb != MGCP_VERB_DLCX) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_CI(ci, LOGL_ERROR, "Invalid MGW endpoint request: missing verb details for %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_mgcp_verb_name(verb));</span><br><span style="color: hsl(120, 100%, 40%);">+            goto dispatch_error;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((verb < 0) || (verb > MGCP_VERB_RSIP)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOG_CI(ci, LOGL_ERROR, "Invalid MGW endpoint request: unknown verb: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_mgcp_verb_name(verb));</span><br><span style="color: hsl(120, 100%, 40%);">+            goto dispatch_error;</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%);">+   ep = ci->ep;</span><br><span style="color: hsl(120, 100%, 40%);">+       fi = ep->fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Clear volatile state by explicitly keeping those that should remain. Because we can't assign</span><br><span style="color: hsl(120, 100%, 40%);">+    * the char[] directly, dance through cleared_ci and copy back. */</span><br><span style="color: hsl(120, 100%, 40%);">+    cleared_ci = (struct osmo_mgcpc_ep_ci){</span><br><span style="color: hsl(120, 100%, 40%);">+               .ep = ep,</span><br><span style="color: hsl(120, 100%, 40%);">+             .mgcp_client_fi = ci->mgcp_client_fi,</span><br><span style="color: hsl(120, 100%, 40%);">+              .got_port_info = ci->got_port_info,</span><br><span style="color: hsl(120, 100%, 40%);">+                .rtp_info = ci->rtp_info,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                .occupied = true,</span><br><span style="color: hsl(120, 100%, 40%);">+             /* .pending = true follows below */</span><br><span style="color: hsl(120, 100%, 40%);">+           .verb = verb,</span><br><span style="color: hsl(120, 100%, 40%);">+         .notify = notify,</span><br><span style="color: hsl(120, 100%, 40%);">+             .notify_success = event_success,</span><br><span style="color: hsl(120, 100%, 40%);">+              .notify_failure = event_failure,</span><br><span style="color: hsl(120, 100%, 40%);">+              .notify_data = notify_data,</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_strlcpy(cleared_ci.label, ci->label, sizeof(cleared_ci.label));</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));</span><br><span style="color: hsl(120, 100%, 40%);">+     *ci = cleared_ci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (verb_info)</span><br><span style="color: hsl(120, 100%, 40%);">+                ci->verb_info = *verb_info;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ep->endpoint[0]) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_CI(ci, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "Warning: Requested %s on endpoint %s, but this CI is on endpoint %s."</span><br><span style="color: hsl(120, 100%, 40%);">+                              " Using the proper endpoint instead.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            osmo_mgcp_verb_name(verb), ci->verb_info.endpoint, ep->endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_strlcpy(ci->verb_info.endpoint, ep->endpoint, sizeof(ci->verb_info.endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (ci->verb) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case MGCP_VERB_CRCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ci->mgcp_client_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_CI(ci, LOGL_ERROR, "CRCX can be called only once per MGW endpoint CI\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       on_failure(ci);</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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case MGCP_VERB_MDCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!ci->mgcp_client_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOG_CI_VERB(ci, LOGL_ERROR, "The first verb on an unused MGW endpoint CI must be CRCX, not %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_mgcp_verb_name(ci->verb));</span><br><span style="color: hsl(120, 100%, 40%);">+                        on_failure(ci);</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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case MGCP_VERB_DLCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!ci->mgcp_client_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOG_CI_VERB(ci, LOGL_DEBUG, "Ignoring DLCX on unused MGW endpoint CI\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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_CI(ci, LOGL_ERROR, "This verb is not supported: %s\n", osmo_mgcp_verb_name(ci->verb));</span><br><span style="color: hsl(120, 100%, 40%);">+               on_failure(ci);</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%);">+   ci->pending = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOG_CI_VERB(ci, LOGL_DEBUG, "Scheduling\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ep->fi->state != OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_mgcpc_ep_fsm_state_chg(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return;</span><br><span style="color: hsl(120, 100%, 40%);">+dispatch_error:</span><br><span style="color: hsl(120, 100%, 40%);">+      if (notify)</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(notify, event_failure, notify_data);</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 send_verb(struct osmo_mgcpc_ep_ci *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_mgcpc_ep *ep = ci->ep;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ci->occupied || !ci->pending || ci->sent)</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (ci->verb) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case MGCP_VERB_CRCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(!ci->mgcp_client_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_CI_VERB(ci, LOGL_DEBUG, "Sending\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           ci->mgcp_client_fi = mgcp_conn_create(ep->mgcp_client, ep->fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     CI_EV_FAILURE(ci), CI_EV_SUCCESS(ci),</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 &ci->verb_info);</span><br><span style="color: hsl(120, 100%, 40%);">+         ci->sent = true;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ci->mgcp_client_fi){</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_CI_VERB(ci, LOGL_ERROR, "Cannot send\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       on_failure(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_update_id(ci->mgcp_client_fi, ci->label);</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%);">+      case MGCP_VERB_MDCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(ci->mgcp_client_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_CI_VERB(ci, LOGL_DEBUG, "Sending\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = mgcp_conn_modify(ci->mgcp_client_fi, CI_EV_SUCCESS(ci), &ci->verb_info);</span><br><span style="color: hsl(120, 100%, 40%);">+               ci->sent = true;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOG_CI_VERB(ci, LOGL_ERROR, "Cannot send (rc=%d %s)\n", rc, strerror(-rc));</span><br><span style="color: hsl(120, 100%, 40%);">+                 on_failure(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</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%);">+      case MGCP_VERB_DLCX:</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_CI(ci, LOGL_DEBUG, "Sending MGCP: %s %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_mgcp_verb_name(ci->verb), ci->mgcp_ci_str);</span><br><span style="color: hsl(120, 100%, 40%);">+         /* The way this is designed, we actually need to forget all about the ci right away. */</span><br><span style="color: hsl(120, 100%, 40%);">+               mgcp_conn_delete(ci->mgcp_client_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ci->notify)</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_fsm_inst_dispatch(ci->notify, ci->notify_success, ci->notify_data);</span><br><span style="color: hsl(120, 100%, 40%);">+             *ci = (struct osmo_mgcpc_ep_ci){</span><br><span style="color: hsl(120, 100%, 40%);">+                      .ep = ep,</span><br><span style="color: hsl(120, 100%, 40%);">+             };</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%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</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 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%);">+/*! DLCX all connections, terminate the endpoint FSM and free. */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mgcpc_ep_clear(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;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_fsm_inst_term(ep->fi, OSMO_FSM_TERM_REGULAR, 0);</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 osmo_mgcpc_ep_count(struct osmo_mgcpc_ep *ep, int *occupied, int *pending_not_sent,</span><br><span style="color: hsl(120, 100%, 40%);">+                                int *waiting_for_response)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (occupied)</span><br><span style="color: hsl(120, 100%, 40%);">+         *occupied = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (pending_not_sent)</span><br><span style="color: hsl(120, 100%, 40%);">+         *pending_not_sent = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (waiting_for_response)</span><br><span style="color: hsl(120, 100%, 40%);">+             *waiting_for_response = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ci->occupied) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (occupied)</span><br><span style="color: hsl(120, 100%, 40%);">+                         (*occupied)++;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else</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%);">+           if (ci->pending)</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOG_CI_VERB(ci, LOGL_DEBUG, "%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             ci->sent ? "waiting for response" : "waiting to be sent");</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_CI_VERB(ci, LOGL_DEBUG, "done (%s)\n", mgcp_conn_peer_name(osmo_mgcpc_ep_ci_get_rtp_info(ci)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ci->pending && ci->sent)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (waiting_for_response)</span><br><span style="color: hsl(120, 100%, 40%);">+                             (*waiting_for_response)++;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (ci->pending && !ci->sent)</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (pending_not_sent)</span><br><span style="color: hsl(120, 100%, 40%);">+                         (*pending_not_sent)++;</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%);">+static bool osmo_mgcpc_ep_fsm_check_state_chg_after_response(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int waiting_for_response;</span><br><span style="color: hsl(120, 100%, 40%);">+     int occupied;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_mgcpc_ep_count(ep, &occupied, NULL, &waiting_for_response);</span><br><span style="color: hsl(120, 100%, 40%);">+      LOG_MGCPC_EP(ep, LOGL_DEBUG, "CI in use: %d, waiting for response: %d\n", occupied, waiting_for_response);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!occupied)  {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* All CI have been released. The endpoint no longer exists. Notify the parent FSM, by</span><br><span style="color: hsl(120, 100%, 40%);">+                 * terminating. */</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</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 (!waiting_for_response) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (fi->state != OSMO_MGCPC_EP_ST_IN_USE)</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_mgcpc_ep_fsm_state_chg(OSMO_MGCPC_EP_ST_IN_USE);</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 true;</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 osmo_mgcpc_ep_fsm_wait_mgw_response_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              count += send_verb(&ep->ci[i]);</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%);">+   LOG_MGCPC_EP(ep, LOGL_DEBUG, "Sent messages: %d\n", count);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_mgcpc_ep_fsm_check_state_chg_after_response(fi);</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 osmo_mgcpc_ep_fsm_handle_ci_events(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_mgcpc_ep_ci *ci;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+        ci = osmo_mgcpc_ep_ci_for_event(ep, event);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ci) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (event == CI_EV_SUCCESS(ci))</span><br><span style="color: hsl(120, 100%, 40%);">+                       on_success(ci, data);</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  on_failure(ci);</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%);">+static void osmo_mgcpc_ep_fsm_in_use_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int pending_not_sent;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_mgcpc_ep_count(ep, NULL, &pending_not_sent, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (pending_not_sent)</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_mgcpc_ep_fsm_state_chg(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE);</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%);">+#define S(x)     (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_fsm_state osmo_mgcpc_ep_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [OSMO_MGCPC_EP_ST_UNUSED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "UNUSED",</span><br><span style="color: hsl(120, 100%, 40%);">+           .in_event_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+           .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE)</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%);">+    [OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .name = "WAIT_MGW_RESPONSE",</span><br><span style="color: hsl(120, 100%, 40%);">+                .onenter = osmo_mgcpc_ep_fsm_wait_mgw_response_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+               .action = osmo_mgcpc_ep_fsm_handle_ci_events,</span><br><span style="color: hsl(120, 100%, 40%);">+         .in_event_mask = 0xffffffff,</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(OSMO_MGCPC_EP_ST_IN_USE)</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%);">+    [OSMO_MGCPC_EP_ST_IN_USE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "IN_USE",</span><br><span style="color: hsl(120, 100%, 40%);">+           .onenter = osmo_mgcpc_ep_fsm_in_use_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+          .action = osmo_mgcpc_ep_fsm_handle_ci_events,</span><br><span style="color: hsl(120, 100%, 40%);">+         .in_event_mask = 0xffffffff, /* mgcp_client_fsm may send parent term anytime */</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE)</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (fi->T) {</span><br><span style="color: hsl(120, 100%, 40%);">+   default:</span><br><span style="color: hsl(120, 100%, 40%);">+              for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!ci->occupied)</span><br><span style="color: hsl(120, 100%, 40%);">+                         continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!(ci->pending && ci->sent))</span><br><span style="color: hsl(120, 100%, 40%);">+                         continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     on_failure(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</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 0;</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 struct osmo_fsm osmo_mgcpc_ep_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .name = "mgw-endpoint",</span><br><span style="color: hsl(120, 100%, 40%);">+     .states = osmo_mgcpc_ep_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+   .num_states = ARRAY_SIZE(osmo_mgcpc_ep_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+   .log_subsys = DLMGCP,</span><br><span style="color: hsl(120, 100%, 40%);">+ .event_names = osmo_mgcpc_ep_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+ .timer_cb = osmo_mgcpc_ep_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+       /* The FSM termination will automatically trigger any mgcp_client_fsm instances to DLCX. */</span><br><span style="color: hsl(120, 100%, 40%);">+};</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 71f4310..75d583b 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>@@ -700,3 +700,25 @@</span><br><span>      }</span><br><span>    osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    /* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if</span><br><span style="color: hsl(120, 100%, 40%);">+   * this buffer is too small. */</span><br><span style="color: hsl(120, 100%, 40%);">+       static char buf[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!info)</span><br><span style="color: hsl(120, 100%, 40%);">+            return "NULL";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (info->endpoint[0]</span><br><span style="color: hsl(120, 100%, 40%);">+          && info->addr[0])</span><br><span style="color: hsl(120, 100%, 40%);">+              snprintf(buf, sizeof(buf), "%s:%s:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                       info->endpoint, info->addr, info->port);</span><br><span style="color: hsl(120, 100%, 40%);">+    else if (info->endpoint[0])</span><br><span style="color: hsl(120, 100%, 40%);">+                snprintf(buf, sizeof(buf), "%s", info->endpoint);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (info->addr[0])</span><br><span style="color: hsl(120, 100%, 40%);">+            snprintf(buf, sizeof(buf), "%s:%u", info->addr, info->port);</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          return "empty";</span><br><span style="color: hsl(120, 100%, 40%);">+     return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13590">change 13590</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/13590"/><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-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I9a3effd38e72841529df6c135c077116981dea36 </div>
<div style="display:none"> Gerrit-Change-Number: 13590 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>