<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16762">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">proxy routing refactor<br><br>Change-Id: I43ad27f6d768df02abb3459ac4c43bb80cc1cbeb<br>---<br>M include/osmocom/hlr/dgsm.h<br>M include/osmocom/hlr/gsup_server.h<br>M include/osmocom/hlr/mslookup_server.h<br>M include/osmocom/hlr/proxy.h<br>M include/osmocom/hlr/remote_hlr.h<br>M src/dgsm.c<br>M src/dgsm_vty.c<br>M src/gsup_server.c<br>M src/hlr.c<br>M src/mslookup_server.c<br>M src/proxy.c<br>M src/remote_hlr.c<br>M tests/gsup_server/Makefile.am<br>13 files changed, 297 insertions(+), 208 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-hlr refs/changes/62/16762/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/hlr/dgsm.h b/include/osmocom/hlr/dgsm.h</span><br><span>index f06e381..b3d73e9 100644</span><br><span>--- a/include/osmocom/hlr/dgsm.h</span><br><span>+++ b/include/osmocom/hlr/dgsm.h</span><br><span>@@ -21,6 +21,7 @@</span><br><span> </span><br><span> #include <osmocom/mslookup/mslookup.h></span><br><span> #include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span> #include <osmocom/gsupclient/gsup_peer_id.h></span><br><span> #include <osmocom/gsupclient/gsup_req.h></span><br><span> </span><br><span>diff --git a/include/osmocom/hlr/gsup_server.h b/include/osmocom/hlr/gsup_server.h</span><br><span>index b7cfb89..22c9a10 100644</span><br><span>--- a/include/osmocom/hlr/gsup_server.h</span><br><span>+++ b/include/osmocom/hlr/gsup_server.h</span><br><span>@@ -74,3 +74,5 @@</span><br><span>                                            uint8_t *msisdn_enc, size_t msisdn_enc_size,</span><br><span>                                         uint8_t *apn_buf, size_t apn_buf_size,</span><br><span>                                       enum osmo_gsup_cn_domain cn_domain);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_gsup_peer_id *to_peer,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);</span><br><span>diff --git a/include/osmocom/hlr/mslookup_server.h b/include/osmocom/hlr/mslookup_server.h</span><br><span>index f76e92f..aed7ad0 100644</span><br><span>--- a/include/osmocom/hlr/mslookup_server.h</span><br><span>+++ b/include/osmocom/hlr/mslookup_server.h</span><br><span>@@ -63,6 +63,10 @@</span><br><span> extern const struct osmo_ipa_name mslookup_server_msc_wildcard;</span><br><span> struct mslookup_server_msc_cfg *mslookup_server_msc_get(const struct osmo_ipa_name *msc_name, bool create);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct mslookup_service_host *mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mslookup_service_host *mslookup_server_get_local_gsup_addr();</span><br><span> void mslookup_server_rx(const struct osmo_mslookup_query *query,</span><br><span>                          struct osmo_mslookup_result *result);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                uint32_t *lu_age_p, struct osmo_ipa_name *local_msc_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                             char *ret_imsi, size_t ret_imsi_len);</span><br><span>diff --git a/include/osmocom/hlr/proxy.h b/include/osmocom/hlr/proxy.h</span><br><span>index 8412dd2..92ed30a 100644</span><br><span>--- a/include/osmocom/hlr/proxy.h</span><br><span>+++ b/include/osmocom/hlr/proxy.h</span><br><span>@@ -28,12 +28,6 @@</span><br><span> struct osmo_gsup_req;</span><br><span> struct remote_hlr;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct proxy_pending_gsup_req {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct llist_head entry;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct osmo_gsup_req *req;</span><br><span style="color: hsl(0, 100%, 40%);">-      timestamp_t received_at;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct proxy {</span><br><span>         struct llist_head subscr_list;</span><br><span>       struct llist_head pending_gsup_reqs;</span><br><span>@@ -87,8 +81,8 @@</span><br><span> int proxy_subscr_create_or_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr);</span><br><span> int proxy_subscr_del(struct proxy *proxy, const char *imsi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    struct osmo_gsup_req *req);</span><br><span> void proxy_subscr_forward_to_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span>                                                  struct remote_hlr *remote_hlr, struct osmo_gsup_req *req);</span><br><span> </span><br><span>@@ -96,6 +90,6 @@</span><br><span>                          const struct osmo_gsup_message *gsup, struct remote_hlr *from_remote_hlr);</span><br><span> </span><br><span> void proxy_subscr_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 struct remote_hlr *remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+                               const struct osmo_sockaddr_str *remote_hlr_addr);</span><br><span> void proxy_subscr_remote_hlr_up(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span>                             struct remote_hlr *remote_hlr);</span><br><span>diff --git a/include/osmocom/hlr/remote_hlr.h b/include/osmocom/hlr/remote_hlr.h</span><br><span>index 4f9f939..6a4e8a1 100644</span><br><span>--- a/include/osmocom/hlr/remote_hlr.h</span><br><span>+++ b/include/osmocom/hlr/remote_hlr.h</span><br><span>@@ -40,9 +40,20 @@</span><br><span>    struct llist_head entry;</span><br><span>     struct osmo_sockaddr_str addr;</span><br><span>       struct osmo_gsup_client *gsupc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head pending_up_callbacks;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool create);</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Receive a remote_hlr address when connecting succeeded, or remote_hlr == NULL on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param addr  GSUP IP address and port for which the connection was requested.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param remote_hlr  The connected remote_hlr ready for sending, or NULL if connecting failed.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param data  Same a passed to remote_hlr_get_or_connect(). */</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*remote_hlr_connect_result_cb_t)(const struct osmo_sockaddr_str *addr, struct remote_hlr *remote_hlr, void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr *remote_hlr_get_or_connect(const struct osmo_sockaddr_str *addr, bool connect,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             remote_hlr_connect_result_cb_t connect_result_cb, void *data);</span><br><span> void remote_hlr_destroy(struct remote_hlr *remote_hlr);</span><br><span> int remote_hlr_msgb_send(struct remote_hlr *remote_hlr, struct msgb *msg);</span><br><span style="color: hsl(0, 100%, 40%);">-void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct osmo_gsup_req *req,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          struct osmo_gsup_message *modified_gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool remote_hlr_is_up(struct remote_hlr *remote_hlr);</span><br><span>diff --git a/src/dgsm.c b/src/dgsm.c</span><br><span>index 647e2ee..57012c8 100644</span><br><span>--- a/src/dgsm.c</span><br><span>+++ b/src/dgsm.c</span><br><span>@@ -44,8 +44,7 @@</span><br><span> {</span><br><span>  struct proxy *proxy = g_hlr->gs->proxy;</span><br><span>        struct proxy_subscr proxy_subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-       const struct osmo_sockaddr_str *use_addr;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct remote_hlr *remote_hlr;</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct osmo_sockaddr_str *remote_hlr_addr;</span><br><span> </span><br><span>         /* A remote HLR is answering back, indicating that it is the home HLR for a given IMSI.</span><br><span>       * There should be a mostly empty proxy entry for that IMSI.</span><br><span>@@ -64,9 +63,9 @@</span><br><span>     }</span><br><span> </span><br><span>        if (osmo_sockaddr_str_is_nonzero(&result->host_v4))</span><br><span style="color: hsl(0, 100%, 40%);">-              use_addr = &result->host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+           remote_hlr_addr = &result->host_v4;</span><br><span>   else if (osmo_sockaddr_str_is_nonzero(&result->host_v6))</span><br><span style="color: hsl(0, 100%, 40%);">-         use_addr = &result->host_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+           remote_hlr_addr = &result->host_v6;</span><br><span>   else {</span><br><span>               LOG_DGSM(query->id.imsi, LOGL_ERROR, "Invalid address for remote HLR: %s\n",</span><br><span>                     osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span>@@ -74,30 +73,13 @@</span><br><span>              return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   remote_hlr = remote_hlr_get(use_addr, true);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!remote_hlr) {</span><br><span style="color: hsl(0, 100%, 40%);">-              proxy_subscr_del(proxy, query->id.imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-             return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, query->id.imsi)) {</span><br><span>                 LOG_DGSM(query->id.imsi, LOGL_ERROR, "No proxy entry for mslookup result: %s\n",</span><br><span>                         osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span>            return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* The remote HLR already exists and is connected. Messages for this IMSI were spooled because we did not know</span><br><span style="color: hsl(0, 100%, 40%);">-   * which remote HLR was responsible. Now we know, send this IMSI's messages now. */</span><br><span style="color: hsl(0, 100%, 40%);">- LOG_DGSM(query->id.imsi, LOGL_DEBUG, "Resolved remote HLR, sending spooled GSUP messages: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       proxy_subscr_remote_hlr_resolved(proxy, &proxy_subscr, remote_hlr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOG_REMOTE_HLR(remote_hlr, LOGL_DEBUG, "Waiting for link-up\n");</span><br><span style="color: hsl(0, 100%, 40%);">-              return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       proxy_subscr_remote_hlr_up(proxy, &proxy_subscr, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_subscr_remote_hlr_resolved(proxy, &proxy_subscr, remote_hlr_addr);</span><br><span> }</span><br><span> </span><br><span> /* Return true when the message has been handled by D-GSM. */</span><br><span>@@ -114,8 +96,10 @@</span><br><span>                 return false;</span><br><span> </span><br><span>    /* Are we already forwarding this IMSI to a remote HLR? */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, req->gsup.imsi) == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-         goto yes_we_are_proxying;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, req->gsup.imsi) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+            return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> </span><br><span>        /* The IMSI is not known locally, so we want to proxy to a remote HLR, but no proxy entry exists yet. We need to</span><br><span>      * look up the subscriber in remote HLRs via D-GSM mslookup, forward GSUP and reply once a result is back from</span><br><span>@@ -125,40 +109,41 @@</span><br><span>       proxy_subscr = (struct proxy_subscr){};</span><br><span>      OSMO_STRLCPY_ARRAY(proxy_subscr.imsi, req->gsup.imsi);</span><br><span>    if (proxy_subscr_create_or_update(proxy, &proxy_subscr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Failed to create proxy entry\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Failed to create proxy entry\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               return true;</span><br><span>         }</span><br><span> </span><br><span>        /* Is a fixed gateway proxy configured? */</span><br><span>   if (osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.client.gsup_gateway_proxy)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          struct remote_hlr *gsup_gateway_proxy = remote_hlr_get(&g_hlr->mslookup.client.gsup_gateway_proxy, true);</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!gsup_gateway_proxy) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      LOG_DGSM(req->gsup.imsi, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                          "Failed to set up fixed gateway proxy " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                 OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.client.gsup_gateway_proxy));</span><br><span style="color: hsl(0, 100%, 40%);">-                        return false;</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(120, 100%, 40%);">+             proxy_subscr_remote_hlr_resolved(proxy, &proxy_subscr, &g_hlr->mslookup.client.gsup_gateway_proxy);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              proxy_subscr_remote_hlr_resolved(proxy, &proxy_subscr, gsup_gateway_proxy);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         /* Update info */</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Proxy database modified, update info */</span><br><span>           if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, req->gsup.imsi)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Proxy entry disappeared\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                 return false;</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Internal proxy error\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       return true;</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               goto yes_we_are_proxying;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+            return true;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Kick off an mslookup for the remote HLR. */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!g_hlr->mslookup.client.client) {</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Kick off an mslookup for the remote HLR?  This check could be up first on the top, but do it only now so that</span><br><span style="color: hsl(120, 100%, 40%);">+       * if the mslookup client disconnected, we still continue to service open proxy entries. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!osmo_mslookup_client_active(g_hlr->mslookup.client.client)) {</span><br><span>                LOG_GSUP_REQ(req, LOGL_DEBUG, "mslookup client not running, cannot query remote home HLR\n");</span><br><span>              return false;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* First spool message, then kick off mslookup. If the proxy denies this message type, then don't do anything. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* If the proxy denied forwarding, an error response was already generated. */</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>  query = (struct osmo_mslookup_query){</span><br><span>                .id = {</span><br><span>                      .type = OSMO_MSLOOKUP_ID_IMSI,</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(120, 100%, 40%);">+             },</span><br><span>   };</span><br><span>   OSMO_STRLCPY_ARRAY(query.id.imsi, req->gsup.imsi);</span><br><span>        OSMO_STRLCPY_ARRAY(query.service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);</span><br><span>@@ -171,14 +156,10 @@</span><br><span>           LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Error dispatching mslookup query for home HLR: %s\n",</span><br><span>                      osmo_mslookup_result_name_c(OTC_SELECT, &query, NULL));</span><br><span>                 proxy_subscr_del(proxy, req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           /* mslookup seems to not be working. Try handling it locally. */</span><br><span>             return false;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-yes_we_are_proxying:</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* If the remote HLR is already known, directly forward the GSUP message; otherwise, spool the GSUP message</span><br><span style="color: hsl(0, 100%, 40%);">-      * until the remote HLR will respond / until timeout aborts. */</span><br><span style="color: hsl(0, 100%, 40%);">- proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req);</span><br><span>   return true;</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/dgsm_vty.c b/src/dgsm_vty.c</span><br><span>index 62f07c7..88ea58a 100644</span><br><span>--- a/src/dgsm_vty.c</span><br><span>+++ b/src/dgsm_vty.c</span><br><span>@@ -516,7 +516,7 @@</span><br><span>       "List configured service addresses as sent to remote mslookup requests\n")</span><br><span> {</span><br><span>  struct mslookup_server_msc_cfg *msc;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct mslookup_service_host *local_hlr = mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct mslookup_service_host *local_hlr = mslookup_server_get_local_gsup_addr();</span><br><span> </span><br><span>   vty_out(vty, "Local GSUP HLR address returned in mslookup responses for local IMSIs:");</span><br><span>    if (osmo_sockaddr_str_is_nonzero(&local_hlr->host_v4))</span><br><span>diff --git a/src/gsup_server.c b/src/gsup_server.c</span><br><span>index 4819ea4..9a9a57b 100644</span><br><span>--- a/src/gsup_server.c</span><br><span>+++ b/src/gsup_server.c</span><br><span>@@ -503,3 +503,39 @@</span><br><span> </span><br><span>        return 0;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_gsup_peer_id *to_peer,</span><br><span style="color: hsl(120, 100%, 40%);">+                               struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup)</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%);">+       /* To forward to a remote entity (HLR, SMSC,...), we need to indicate the original source name in the Source</span><br><span style="color: hsl(120, 100%, 40%);">+   * Name IE to make sure the reply can be routed back. Store the sender in gsup->source_name -- the remote entity</span><br><span style="color: hsl(120, 100%, 40%);">+    * is required to return this as gsup->destination_name so that the reply gets routed to the original sender. */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gsup_message forward = *(modified_gsup? : &req->gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_gsup_peer_id_type_name(req->source_name.type));</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+                goto routing_error;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     forward.source_name = req->source_name.ipa_name.val;</span><br><span style="color: hsl(120, 100%, 40%);">+       forward.source_name_len = req->source_name.ipa_name.len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (to_peer->type != OSMO_GSUP_PEER_ID_IPA_NAME) {</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_gsup_peer_id_type_name(to_peer->type));</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+                goto routing_error;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to %s\n", osmo_gsup_peer_id_to_str(to_peer));</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = osmo_gsup_enc_send_to_ipa_name(server, &to_peer->ipa_name, &forward);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               goto routing_error;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_gsup_req_free(req);</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%);">+routing_error:</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);</span><br><span style="color: hsl(120, 100%, 40%);">+  return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/hlr.c b/src/hlr.c</span><br><span>index 0d8024f..79b50c2 100644</span><br><span>--- a/src/hlr.c</span><br><span>+++ b/src/hlr.c</span><br><span>@@ -507,6 +507,7 @@</span><br><span>                         return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* HLR related messages that are handled at this HLR instance */</span><br><span>     switch (req->gsup.message_type) {</span><br><span>         /* requests sent to us */</span><br><span>    case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:</span><br><span>diff --git a/src/mslookup_server.c b/src/mslookup_server.c</span><br><span>index 29768c8..72729b3 100644</span><br><span>--- a/src/mslookup_server.c</span><br><span>+++ b/src/mslookup_server.c</span><br><span>@@ -49,7 +49,7 @@</span><br><span>     result->age = age;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct mslookup_service_host *mslookup_server_get_local_gsup_addr()</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mslookup_service_host *mslookup_server_get_local_gsup_addr()</span><br><span> {</span><br><span>    static struct mslookup_service_host gsup_bind = {};</span><br><span>  struct mslookup_service_host *host;</span><br><span>@@ -190,7 +190,7 @@</span><br><span> static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,</span><br><span>                                        struct osmo_mslookup_result *result)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct mslookup_service_host *host;</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct mslookup_service_host *host;</span><br><span>    int rc;</span><br><span>      switch (query->id.type) {</span><br><span>         case OSMO_MSLOOKUP_ID_IMSI:</span><br><span>@@ -231,18 +231,21 @@</span><br><span>  * VLR, we will find a valid location updating with vlr_number, and no vlr_via_proxy entry. */</span><br><span> static bool subscriber_has_done_lu_here_hlr(const struct osmo_mslookup_query *query,</span><br><span>                                            uint32_t *lu_age,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       struct osmo_ipa_name *local_msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+                                         struct osmo_ipa_name *local_msc_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         struct hlr_subscriber *ret_subscr)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     struct hlr_subscriber subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hlr_subscriber _subscr;</span><br><span>       int rc;</span><br><span>      uint32_t age;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     struct hlr_subscriber *subscr = ret_subscr ? : &_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       switch (query->id.type) {</span><br><span>         case OSMO_MSLOOKUP_ID_IMSI:</span><br><span style="color: hsl(0, 100%, 40%);">-             rc = db_subscr_get_by_imsi(g_hlr->dbc, query->id.imsi, &subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = db_subscr_get_by_imsi(g_hlr->dbc, query->id.imsi, subscr);</span><br><span>                break;</span><br><span>       case OSMO_MSLOOKUP_ID_MSISDN:</span><br><span style="color: hsl(0, 100%, 40%);">-           rc = db_subscr_get_by_msisdn(g_hlr->dbc, query->id.msisdn, &subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = db_subscr_get_by_msisdn(g_hlr->dbc, query->id.msisdn, subscr);</span><br><span>            break;</span><br><span>       default:</span><br><span>             LOGP(DMSLOOKUP, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);</span><br><span>@@ -255,22 +258,22 @@</span><br><span>          return false;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!subscr.vlr_number[0]) {</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!subscr->vlr_number[0]) {</span><br><span>             LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: not attached (vlr_number unset)\n",</span><br><span>                    osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (subscr.vlr_via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+       if (subscr->vlr_via_proxy.len) {</span><br><span>          /* The VLR is behind a proxy, the subscriber is not attached to a local VLR but a remote one. That</span><br><span>            * remote proxy should instead respond to the service lookup request. */</span><br><span>             LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: last attach is not at local VLR, but at VLR '%s' via proxy %s\n",</span><br><span>                      osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(0, 100%, 40%);">-                   subscr.vlr_number,</span><br><span style="color: hsl(0, 100%, 40%);">-              osmo_ipa_name_to_str(&subscr.vlr_via_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+                     subscr->vlr_number,</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_ipa_name_to_str(&subscr->vlr_via_proxy));</span><br><span>           return false;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!timestamp_age(&subscr.last_lu_seen, &age)) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!timestamp_age(&subscr->last_lu_seen, &age)) {</span><br><span>                LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: Invalid last_lu_seen timestamp for subscriber\n",</span><br><span>                      osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span>          return false;</span><br><span>@@ -283,7 +286,7 @@</span><br><span>  }</span><br><span> </span><br><span>        *lu_age = age;</span><br><span style="color: hsl(0, 100%, 40%);">-  osmo_ipa_name_set_str(local_msc_name, subscr.vlr_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_ipa_name_set_str(local_msc_name, subscr->vlr_number);</span><br><span>        LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: attached %u seconds ago at local VLR %s\n",</span><br><span>            osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span>        age, osmo_ipa_name_to_str(local_msc_name));</span><br><span>@@ -297,7 +300,8 @@</span><br><span>  */</span><br><span> static bool subscriber_has_done_lu_here_proxy(const struct osmo_mslookup_query *query,</span><br><span>                                            uint32_t *lu_age,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       struct osmo_ipa_name *local_msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+                                         struct osmo_ipa_name *local_msc_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         struct proxy_subscr *ret_proxy_subscr)</span><br><span> {</span><br><span>    struct proxy_subscr proxy_subscr;</span><br><span>    uint32_t age;</span><br><span>@@ -350,12 +354,14 @@</span><br><span>             age, osmo_ipa_name_to_str(local_msc_name),</span><br><span>           OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr.remote_hlr_addr));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      if (ret_proxy_subscr)</span><br><span style="color: hsl(120, 100%, 40%);">+         *ret_proxy_subscr = proxy_subscr;</span><br><span>    return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   uint32_t *lu_age_p,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     struct osmo_ipa_name *local_msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                               uint32_t *lu_age_p, struct osmo_ipa_name *local_msc_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                             char *ret_imsi, size_t ret_imsi_len)</span><br><span> {</span><br><span>   bool attached_here;</span><br><span>  uint32_t lu_age = 0;</span><br><span>@@ -363,6 +369,9 @@</span><br><span>   bool attached_here_proxy;</span><br><span>    uint32_t proxy_lu_age = 0;</span><br><span>   struct osmo_ipa_name proxy_msc_name = {};</span><br><span style="color: hsl(120, 100%, 40%);">+     struct proxy_subscr proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hlr_subscriber db_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span>       /* First ask the local HLR db, but if the local proxy record indicates a more recent LU, use that instead.</span><br><span>    * For all usual cases, only one of these will reflect a LU, even if a subscriber had more than one home HLR:</span><br><span>@@ -372,14 +381,19 @@</span><br><span>         * the local HLR database, there might occur a situation where both reflect a LU. So, to be safe against all</span><br><span>          * situations, compare the two entries.</span><br><span>       */</span><br><span style="color: hsl(0, 100%, 40%);">-     attached_here = subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name);</span><br><span style="color: hsl(0, 100%, 40%);">-     attached_here_proxy = subscriber_has_done_lu_here_proxy(query, &proxy_lu_age, &proxy_msc_name);</span><br><span style="color: hsl(120, 100%, 40%);">+       attached_here = subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name, &db_subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+   attached_here_proxy = subscriber_has_done_lu_here_proxy(query, &proxy_lu_age, &proxy_msc_name, &proxy_subscr);</span><br><span> </span><br><span>       /* If proxy has a younger lu, replace. */</span><br><span>    if (attached_here_proxy && (!attached_here || (proxy_lu_age < lu_age))) {</span><br><span>                 attached_here = true;</span><br><span>                lu_age = proxy_lu_age;</span><br><span>               msc_name = proxy_msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (ret_imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_strlcpy(ret_imsi, proxy_subscr.imsi, ret_imsi_len);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (attached_here) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ret_imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_strlcpy(ret_imsi, db_subscr.imsi, ret_imsi_len);</span><br><span>        }</span><br><span> </span><br><span>        if (attached_here && !msc_name.len) {</span><br><span>@@ -403,7 +417,7 @@</span><br><span> </span><br><span> /* A remote entity is asking us whether we are providing the given service for the given subscriber. */</span><br><span> void mslookup_server_rx(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(0, 100%, 40%);">-                       struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_mslookup_result *result)</span><br><span> {</span><br><span>    const struct mslookup_service_host *service_host;</span><br><span>    uint32_t age;</span><br><span>@@ -417,7 +431,7 @@</span><br><span>  /* All other service types: answer when the subscriber has done a LU that is either listed in the local HLR or</span><br><span>        * in the GSUP proxy database: i.e. if the subscriber has done a Location Updating at an VLR belonging to this</span><br><span>        * HLR. Respond with whichever services are configured in the osmo-hlr.cfg. */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!subscriber_has_done_lu_here(query, &age, &msc_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!subscriber_has_done_lu_here(query, &age, &msc_name, NULL, 0)) {</span><br><span>                 *result = not_found;</span><br><span>                 return;</span><br><span>      }</span><br><span>diff --git a/src/proxy.c b/src/proxy.c</span><br><span>index 0d3fd13..b9cd313 100644</span><br><span>--- a/src/proxy.c</span><br><span>+++ b/src/proxy.c</span><br><span>@@ -47,7 +47,8 @@</span><br><span>                                     (gsup_msg) ? osmo_gsup_message_type_name((gsup_msg)->message_type) : "NULL", \</span><br><span>                                  ##args)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Why have a separate struct to add an llist_head entry?</span><br><span style="color: hsl(120, 100%, 40%);">+/* The proxy subscriber database.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Why have a separate struct to add an llist_head entry?</span><br><span>  * This is to keep the option open to store the proxy data in the database instead, without any visible effect outside</span><br><span>  * of proxy.c. */</span><br><span> struct proxy_subscr_listentry {</span><br><span>@@ -56,10 +57,16 @@</span><br><span>     struct proxy_subscr data;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct proxy_pending_gsup_req {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gsup_req *req;</span><br><span style="color: hsl(120, 100%, 40%);">+    timestamp_t received_at;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Defer a GSUP message until we know a remote HLR to proxy to.</span><br><span>  * Where to send this GSUP message is indicated by its IMSI: as soon as an MS lookup has yielded the IMSI's home HLR,</span><br><span>  * that's where the message should go. */</span><br><span style="color: hsl(0, 100%, 40%);">-static void proxy_defer_gsup_req(struct proxy *proxy, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_deferred_gsup_req_add(struct proxy *proxy, struct osmo_gsup_req *req)</span><br><span> {</span><br><span>        struct proxy_pending_gsup_req *m;</span><br><span> </span><br><span>@@ -70,49 +77,46 @@</span><br><span>  llist_add_tail(&m->entry, &proxy->pending_gsup_reqs);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Unable to resolve remote HLR for this IMSI, Answer with error back to the sender. */</span><br><span style="color: hsl(0, 100%, 40%);">-static void proxy_defer_gsup_message_err(struct proxy *proxy, struct proxy_pending_gsup_req *m)</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      osmo_gsup_req_respond_err(m->req, GMM_CAUSE_IMSI_UNKNOWN, "could not reach home HLR");</span><br><span style="color: hsl(0, 100%, 40%);">-     m->req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "Proxy: Failed to connect to home HLR");</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%);">+   remote_hlr_gsup_forward_to_remote_hlr(remote_hlr, req, NULL);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Forward spooled message for this IMSI to remote HLR. */</span><br><span style="color: hsl(0, 100%, 40%);">-static void proxy_defer_gsup_message_send(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   struct proxy_pending_gsup_req *m, struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+static bool proxy_deferred_gsup_req_waiting(struct proxy *proxy, const char *imsi)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     LOG_PROXY_SUBSCR_MSG(proxy_subscr, &m->req->gsup, LOGL_INFO, "Forwarding deferred message\n");</span><br><span style="color: hsl(0, 100%, 40%);">-      proxy_subscr_forward_to_remote_hlr_resolved(proxy, proxy_subscr, remote_hlr, m->req);</span><br><span style="color: hsl(0, 100%, 40%);">-        m->req = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Result of looking for remote HLR. If it failed, pass remote_hlr as NULL. On failure, the proxy_subscr and the</span><br><span style="color: hsl(0, 100%, 40%);">- * remote_hlr may be passed NULL. The IMSI then reflects who the error was for. */</span><br><span style="color: hsl(0, 100%, 40%);">-static void proxy_defer_gsup_message_pop(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       const char *imsi, struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      struct proxy_pending_gsup_req *m, *n;</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!imsi && proxy_subscr)</span><br><span style="color: hsl(0, 100%, 40%);">-              imsi = proxy_subscr->imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct proxy_pending_gsup_req *p;</span><br><span>    OSMO_ASSERT(imsi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (!remote_hlr)</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DDGSM, LOGL_ERROR, "IMSI-%s: No remote HLR found, dropping spooled GSUP messages\n", imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_for_each_entry_safe(m, n, &proxy->pending_gsup_reqs, entry) {</span><br><span style="color: hsl(0, 100%, 40%);">-              if (strcmp(m->req->gsup.imsi, imsi))</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(p, &proxy->pending_gsup_reqs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (strcmp(p->req->gsup.imsi, imsi))</span><br><span>                   continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!remote_hlr)</span><br><span style="color: hsl(0, 100%, 40%);">-                        proxy_defer_gsup_message_err(proxy, m);</span><br><span style="color: hsl(0, 100%, 40%);">-         else</span><br><span style="color: hsl(0, 100%, 40%);">-                    proxy_defer_gsup_message_send(proxy, proxy_subscr, m, remote_hlr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              llist_del(&m->entry);</span><br><span style="color: hsl(0, 100%, 40%);">-            talloc_free(m);</span><br><span style="color: hsl(120, 100%, 40%);">+               return true;</span><br><span>         }</span><br><span style="color: hsl(120, 100%, 40%);">+     return false;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Result of looking for remote HLR. If it failed, pass remote_hlr as NULL. On failure, the remote_hlr may be passed</span><br><span style="color: hsl(120, 100%, 40%);">+ * NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_deferred_gsup_req_pop(struct proxy *proxy, const char *imsi, struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct proxy_pending_gsup_req *p, *n;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry_safe(p, n, &proxy->pending_gsup_reqs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (strcmp(p->req->gsup.imsi, imsi))</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%);">+           proxy_pending_req_remote_hlr_connect_result(p->req, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+           p->req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_del(&p->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(p);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> static bool proxy_subscr_matches_imsi(const struct proxy_subscr *proxy_subscr, const char *imsi)</span><br><span> {</span><br><span>@@ -170,21 +174,6 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void proxy_subscrs_get_by_remote_hlr(struct proxy *proxy, const struct osmo_sockaddr_str *remote_hlr_addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 bool (*yield)(struct proxy *proxy, const struct proxy_subscr *subscr, void *data),</span><br><span style="color: hsl(0, 100%, 40%);">-                              void *data)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!proxy)</span><br><span style="color: hsl(0, 100%, 40%);">-             return;</span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(e, &proxy->subscr_list, entry) {</span><br><span style="color: hsl(0, 100%, 40%);">-            if (!osmo_sockaddr_str_cmp(remote_hlr_addr, &e->data.remote_hlr_addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (!yield(proxy, &e->data, data))</span><br><span style="color: hsl(0, 100%, 40%);">-                               return;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> int proxy_subscr_create_or_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr)</span><br><span> {</span><br><span>   struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, proxy_subscr->imsi);</span><br><span>@@ -207,7 +196,7 @@</span><br><span> int proxy_subscr_del(struct proxy *proxy, const char *imsi)</span><br><span> {</span><br><span>       struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(0, 100%, 40%);">-       proxy_defer_gsup_message_pop(proxy, NULL, imsi, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        proxy_deferred_gsup_req_pop(proxy, imsi, NULL);</span><br><span>      e = _proxy_get_by_imsi(proxy, imsi);</span><br><span>         if (!e)</span><br><span>              return -ENOENT;</span><br><span>@@ -264,42 +253,6 @@</span><br><span>       talloc_free(proxy);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void proxy_subscr_remote_hlr_up(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                               struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- proxy_defer_gsup_message_pop(proxy, proxy_subscr, proxy_subscr->imsi, remote_hlr);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void proxy_subscr_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct proxy_subscr proxy_subscr_new;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (osmo_sockaddr_str_is_nonzero(&proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              if (!osmo_sockaddr_str_cmp(&remote_hlr->addr, &proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* Already have this remote address */</span><br><span style="color: hsl(0, 100%, 40%);">-                  return;</span><br><span style="color: hsl(0, 100%, 40%);">-         } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOG_PROXY_SUBSCR(proxy_subscr, LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      "Remote HLR address changes to " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                        OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Store the address. Make a copy to modify. */</span><br><span style="color: hsl(0, 100%, 40%);">- proxy_subscr_new = *proxy_subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-       proxy_subscr_new.remote_hlr_addr = remote_hlr->addr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (proxy_subscr_create_or_update(proxy, &proxy_subscr_new)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              LOG_PROXY_SUBSCR(proxy_subscr, LOGL_ERROR, "Failed to store proxy entry for remote HLR\n");</span><br><span style="color: hsl(0, 100%, 40%);">-           /* If no remote HLR is known for the IMSI, the proxy entry is pointless. */</span><br><span style="color: hsl(0, 100%, 40%);">-             proxy_subscr_del(proxy, proxy_subscr_new.imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-         return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       proxy_subscr = &proxy_subscr_new;</span><br><span style="color: hsl(0, 100%, 40%);">-   LOG_PROXY_SUBSCR(proxy_subscr, LOGL_DEBUG, "Remote HLR resolved, stored address\n");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* All GSUP messages sent to the remote HLR pass through this function, to modify the subscriber state or disallow</span><br><span>  * sending the message. Return 0 to allow sending the message. */</span><br><span> static int proxy_acknowledge_gsup_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span>@@ -457,27 +410,77 @@</span><br><span>  return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void proxy_subscr_forward_to_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 struct remote_hlr *remote_hlr, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_remote_hlr_connect_result_cb(const struct osmo_sockaddr_str *addr, struct remote_hlr *remote_hlr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              void *data)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if (proxy_acknowledge_gsup_to_remote_hlr(proxy, proxy_subscr, req)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_gsup_req_respond_err(req, GMM_CAUSE_PROTO_ERR_UNSPEC, "Proxy does not allow this message");</span><br><span style="color: hsl(120, 100%, 40%);">+    struct proxy *proxy = data;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!proxy)</span><br><span>          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(e, &proxy->subscr_list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!osmo_sockaddr_str_cmp(addr, &e->data.remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  proxy_deferred_gsup_req_pop(proxy, e->data.imsi, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span>    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       remote_hlr_gsup_forward_to_remote_hlr(remote_hlr, req);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+/* Store the remote HLR's GSUP address for this proxy subscriber.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This can be set before the remote_hlr is connected, or after.</span><br><span style="color: hsl(120, 100%, 40%);">+ * And, this can be set before the gsup_req has been queued for this HLR, or after.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const struct osmo_sockaddr_str *remote_hlr_addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct proxy_subscr proxy_subscr_new;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (osmo_sockaddr_str_is_nonzero(&proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!osmo_sockaddr_str_cmp(remote_hlr_addr, &proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* Already have this remote address */</span><br><span style="color: hsl(120, 100%, 40%);">+                        return;</span><br><span style="color: hsl(120, 100%, 40%);">+               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOG_PROXY_SUBSCR(proxy_subscr, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    "Remote HLR address changes to " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCKADDR_STR_FMT_ARGS(remote_hlr_addr));</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%);">+   /* Store the address. Make a copy to modify. */</span><br><span style="color: hsl(120, 100%, 40%);">+       proxy_subscr_new = *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_subscr = &proxy_subscr_new;</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy_subscr_new.remote_hlr_addr = *remote_hlr_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (proxy_subscr_create_or_update(proxy, proxy_subscr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_PROXY_SUBSCR(proxy_subscr, LOGL_ERROR, "Failed to store proxy entry for remote HLR\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         /* If no remote HLR is known for the IMSI, the proxy entry is pointless. */</span><br><span style="color: hsl(120, 100%, 40%);">+           proxy_subscr_del(proxy, proxy_subscr->imsi);</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%);">+     LOG_PROXY_SUBSCR(proxy_subscr, LOGL_DEBUG, "Remote HLR resolved, stored address\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If any messages for this HLR are already spooled, connect now. Otherwise wait for</span><br><span style="color: hsl(120, 100%, 40%);">+   * proxy_subscr_forward_to_remote_hlr() to connect then. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (proxy_deferred_gsup_req_waiting(proxy, proxy_subscr->imsi))</span><br><span style="color: hsl(120, 100%, 40%);">+            remote_hlr_get_or_connect(&proxy_subscr->remote_hlr_addr, true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          proxy_remote_hlr_connect_result_cb, proxy);</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%);">+int proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr, struct osmo_gsup_req *req)</span><br><span> {</span><br><span>     struct remote_hlr *remote_hlr;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = proxy_acknowledge_gsup_to_remote_hlr(proxy, proxy_subscr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_gsup_req_respond_err(req, GMM_CAUSE_PROTO_ERR_UNSPEC, "Proxy does not allow this message");</span><br><span style="color: hsl(120, 100%, 40%);">+            return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span> </span><br><span>        if (!osmo_sockaddr_str_is_nonzero(&proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             /* We don't know the remote target yet. Still waiting for an MS lookup response. */</span><br><span style="color: hsl(120, 100%, 40%);">+               /* We don't know the remote target yet. Still waiting for an MS lookup response, which will end up</span><br><span style="color: hsl(120, 100%, 40%);">+                 * calling proxy_subscr_remote_hlr_resolved(). See dgsm.c. */</span><br><span>                LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_DEBUG, "deferring until remote HLR is known\n");</span><br><span style="color: hsl(0, 100%, 40%);">-           proxy_defer_gsup_req(proxy, req);</span><br><span style="color: hsl(0, 100%, 40%);">-               return;</span><br><span style="color: hsl(120, 100%, 40%);">+               proxy_deferred_gsup_req_add(proxy, req);</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span>    }</span><br><span> </span><br><span>        if (!osmo_gsup_peer_id_is_empty(&req->via_proxy)) {</span><br><span>@@ -489,23 +492,22 @@</span><br><span>                                osmo_gsup_peer_id_to_str(&req->source_name));</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   remote_hlr = remote_hlr_get(&proxy_subscr->remote_hlr_addr, true);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!remote_hlr) {</span><br><span style="color: hsl(0, 100%, 40%);">-              osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL,</span><br><span style="color: hsl(0, 100%, 40%);">-                                        "Proxy: Failed to establish connection to remote HLR " OSMO_SOCKADDR_STR_FMT,</span><br><span style="color: hsl(0, 100%, 40%);">-                                         OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr->remote_hlr_addr));</span><br><span style="color: hsl(0, 100%, 40%);">-           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* We could always store in the defer queue and empty the queue if the connection is already up.</span><br><span style="color: hsl(120, 100%, 40%);">+       * Slight optimisation: if the remote_hlr is already up and running, skip the defer queue.</span><br><span style="color: hsl(120, 100%, 40%);">+     * First ask for an existing remote_hlr. */</span><br><span style="color: hsl(120, 100%, 40%);">+   remote_hlr = remote_hlr_get_or_connect(&proxy_subscr->remote_hlr_addr, false, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (remote_hlr && remote_hlr_is_up(remote_hlr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             proxy_pending_req_remote_hlr_connect_result(req, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {</span><br><span style="color: hsl(0, 100%, 40%);">-          /* GSUP link is still busy establishing... */</span><br><span style="color: hsl(0, 100%, 40%);">-           LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    "deferring until link to remote HLR is up\n");</span><br><span style="color: hsl(0, 100%, 40%);">-           proxy_defer_gsup_req(proxy, req);</span><br><span style="color: hsl(0, 100%, 40%);">-               return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       proxy_subscr_forward_to_remote_hlr_resolved(proxy, proxy_subscr, remote_hlr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Not existing or not up. Defer req and ask to be notified when it is up.</span><br><span style="color: hsl(120, 100%, 40%);">+     * If the remote_hlr exists but is not connected yet, there should actually already be a pending</span><br><span style="color: hsl(120, 100%, 40%);">+       * proxy_remote_hlr_connect_result_cb queued, but it doesn't hurt to do that more often. */</span><br><span style="color: hsl(120, 100%, 40%);">+       proxy_deferred_gsup_req_add(proxy, req);</span><br><span style="color: hsl(120, 100%, 40%);">+      remote_hlr_get_or_connect(&proxy_subscr->remote_hlr_addr, true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  proxy_remote_hlr_connect_result_cb, proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span> }</span><br><span> </span><br><span> int proxy_subscr_forward_to_vlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span>diff --git a/src/remote_hlr.c b/src/remote_hlr.c</span><br><span>index 42bf700..e2e7d47 100644</span><br><span>--- a/src/remote_hlr.c</span><br><span>+++ b/src/remote_hlr.c</span><br><span>@@ -100,16 +100,16 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static bool remote_hlr_up_yield(struct proxy *proxy, const struct proxy_subscr *proxy_subscr, void *data)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct remote_hlr *remote_hlr = data;</span><br><span style="color: hsl(0, 100%, 40%);">-   proxy_subscr_remote_hlr_up(proxy, proxy_subscr, remote_hlr);</span><br><span style="color: hsl(0, 100%, 40%);">-    return true;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr_pending_up {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      remote_hlr_connect_result_cb_t connect_result_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+     void *data;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span> </span><br><span> static bool remote_hlr_up_down(struct osmo_gsup_client *gsupc, bool up)</span><br><span> {</span><br><span>  struct remote_hlr *remote_hlr = gsupc->data;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct remote_hlr_pending_up *p, *n;</span><br><span>         if (!up) {</span><br><span>           LOG_REMOTE_HLR(remote_hlr, LOGL_NOTICE, "link to remote HLR is down, removing GSUP client\n");</span><br><span>             remote_hlr_destroy(remote_hlr);</span><br><span>@@ -117,22 +117,41 @@</span><br><span>      }</span><br><span> </span><br><span>        LOG_REMOTE_HLR(remote_hlr, LOGL_NOTICE, "link up\n");</span><br><span style="color: hsl(0, 100%, 40%);">- proxy_subscrs_get_by_remote_hlr(g_hlr->gs->proxy, &remote_hlr->addr, remote_hlr_up_yield, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry_safe(p, n, &remote_hlr->pending_up_callbacks, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (p->connect_result_cb)</span><br><span style="color: hsl(120, 100%, 40%);">+                  p->connect_result_cb(&remote_hlr->addr, remote_hlr, p->data);</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_del(&p->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span>    return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool create)</span><br><span style="color: hsl(120, 100%, 40%);">+bool remote_hlr_is_up(struct remote_hlr *remote_hlr)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct remote_hlr *rh;</span><br><span style="color: hsl(120, 100%, 40%);">+        return remote_hlr && remote_hlr->gsupc && remote_hlr->gsupc->is_connected;</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 remote_hlr *remote_hlr_get_or_connect(const struct osmo_sockaddr_str *addr, bool connect,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         remote_hlr_connect_result_cb_t connect_result_cb, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct remote_hlr *rh = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct remote_hlr *rh_i;</span><br><span>     struct osmo_gsup_client_config cfg;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- llist_for_each_entry(rh, &remote_hlrs, entry) {</span><br><span style="color: hsl(0, 100%, 40%);">-             if (!osmo_sockaddr_str_cmp(&rh->addr, addr))</span><br><span style="color: hsl(0, 100%, 40%);">-                     return rh;</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(rh_i, &remote_hlrs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!osmo_sockaddr_str_cmp(&rh_i->addr, addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       rh = rh_i;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!create)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rh)</span><br><span style="color: hsl(120, 100%, 40%);">+               goto add_result_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!connect) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (connect_result_cb)</span><br><span style="color: hsl(120, 100%, 40%);">+                        connect_result_cb(addr, NULL, data);</span><br><span>                 return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> </span><br><span>        /* Doesn't exist yet, create a GSUP client to remote HLR. */</span><br><span>     cfg = (struct osmo_gsup_client_config){</span><br><span>@@ -150,15 +169,33 @@</span><br><span>              .addr = *addr,</span><br><span>               .gsupc = osmo_gsup_client_create3(rh, &cfg),</span><br><span>     };</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&rh->pending_up_callbacks);</span><br><span>   if (!rh->gsupc) {</span><br><span>                 LOGP(DDGSM, LOGL_ERROR,</span><br><span>                   "Failed to establish connection to remote HLR " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span>                      OSMO_SOCKADDR_STR_FMT_ARGS(addr));</span><br><span>              talloc_free(rh);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (connect_result_cb)</span><br><span style="color: hsl(120, 100%, 40%);">+                        connect_result_cb(addr, NULL, data);</span><br><span>                 return NULL;</span><br><span>         }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  rh->gsupc->data = rh;</span><br><span>  llist_add(&rh->entry, &remote_hlrs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+add_result_cb:</span><br><span style="color: hsl(120, 100%, 40%);">+     if (connect_result_cb) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (remote_hlr_is_up(rh)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   connect_result_cb(addr, rh, data);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct remote_hlr_pending_up *p;</span><br><span style="color: hsl(120, 100%, 40%);">+                      p = talloc_zero(rh, struct remote_hlr_pending_up);</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_ASSERT(p);</span><br><span style="color: hsl(120, 100%, 40%);">+                       p->connect_result_cb = connect_result_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+                  p->data = data;</span><br><span style="color: hsl(120, 100%, 40%);">+                    llist_add_tail(&p->entry, &rh->pending_up_callbacks);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span>    return rh;</span><br><span> }</span><br><span> </span><br><span>@@ -182,14 +219,19 @@</span><br><span> }</span><br><span> </span><br><span> /* A GSUP message was received from the MS/MSC side, forward it to the remote HLR. */</span><br><span style="color: hsl(0, 100%, 40%);">-void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct osmo_gsup_req *req,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          struct osmo_gsup_message *modified_gsup)</span><br><span> {</span><br><span>     int rc;</span><br><span>      struct msgb *msg;</span><br><span>    /* To forward to a remote HLR, we need to indicate the source MSC's name in the Source Name IE to make sure the</span><br><span>   * reply can be routed back. Store the sender MSC in gsup->source_name -- the remote HLR is required to return</span><br><span>     * this as gsup->destination_name so that the reply gets routed to the original MSC. */</span><br><span style="color: hsl(0, 100%, 40%);">-      struct osmo_gsup_message forward = req->gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gsup_message forward;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (modified_gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+            forward = *modified_gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          forward = req->gsup;</span><br><span> </span><br><span>  if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {</span><br><span>                osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",</span><br><span>diff --git a/tests/gsup_server/Makefile.am b/tests/gsup_server/Makefile.am</span><br><span>index 6df538f..0b18d61 100644</span><br><span>--- a/tests/gsup_server/Makefile.am</span><br><span>+++ b/tests/gsup_server/Makefile.am</span><br><span>@@ -31,6 +31,7 @@</span><br><span> gsup_server_test_LDADD = \</span><br><span>         $(top_srcdir)/src/gsup_server.c \</span><br><span>    $(top_srcdir)/src/gsup_router.c \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(top_srcdir)/src/gsup_send.c \</span><br><span>      $(top_srcdir)/src/gsupclient/gsup_peer_id.c \</span><br><span>        $(top_srcdir)/src/gsupclient/gsup_req.c \</span><br><span>    $(LIBOSMOCORE_LIBS) \</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16762">change 16762</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-hlr/+/16762"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-hlr </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I43ad27f6d768df02abb3459ac4c43bb80cc1cbeb </div>
<div style="display:none"> Gerrit-Change-Number: 16762 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>