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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">D-GSM 1/n: add mslookup server in osmo-hlr<br><br>Implement the mslookup server to service remote mslookup requests.<br><br>This patch merely adds the logic to answer incoming mslookup requests, an<br>actual method to receive requests (mDNS) follows in a subsequent patch.<br><br>- API to configure service names and addresses for the local site (per MSC).<br>- determine whether a subscriber is on a local MSC<br>  (checking the local proxy will be added in subsequent patch that adds proxy<br>  capability).<br>- VTY config follows in a subsequent patch.<br><br>For a detailed overview of the D-GSM and mslookup related files, please see the<br>elaborate comment at the top of mslookup.c (already added in an earlier patch).<br><br>Change-Id: Ife4a61d71926d08f310a1aeed9d9f1974f64178b<br>---<br>M include/osmocom/hlr/Makefile.am<br>M include/osmocom/hlr/hlr.h<br>A include/osmocom/hlr/mslookup_server.h<br>A include/osmocom/hlr/timestamp.h<br>M src/Makefile.am<br>M src/hlr.c<br>A src/mslookup_server.c<br>A src/timestamp.c<br>8 files changed, 537 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/hlr/Makefile.am b/include/osmocom/hlr/Makefile.am</span><br><span>index 532fa5d..5c96ec8 100644</span><br><span>--- a/include/osmocom/hlr/Makefile.am</span><br><span>+++ b/include/osmocom/hlr/Makefile.am</span><br><span>@@ -10,5 +10,7 @@</span><br><span>    hlr_vty_subscr.h \</span><br><span>   logging.h \</span><br><span>  lu_fsm.h \</span><br><span style="color: hsl(120, 100%, 40%);">+    mslookup_server.h \</span><br><span>  rand.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp.h \</span><br><span>        $(NULL)</span><br><span>diff --git a/include/osmocom/hlr/hlr.h b/include/osmocom/hlr/hlr.h</span><br><span>index 5885600..1269994 100644</span><br><span>--- a/include/osmocom/hlr/hlr.h</span><br><span>+++ b/include/osmocom/hlr/hlr.h</span><br><span>@@ -67,6 +67,13 @@</span><br><span>        /* Bitmask of DB_SUBSCR_FLAG_* */</span><br><span>    uint8_t subscr_create_on_demand_flags;</span><br><span>       unsigned int subscr_create_on_demand_rand_msisdn_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      uint32_t local_attach_max_age;</span><br><span style="color: hsl(120, 100%, 40%);">+                        struct llist_head local_site_services;</span><br><span style="color: hsl(120, 100%, 40%);">+                } server;</span><br><span style="color: hsl(120, 100%, 40%);">+     } mslookup;</span><br><span> };</span><br><span> </span><br><span> extern struct hlr *g_hlr;</span><br><span>diff --git a/include/osmocom/hlr/mslookup_server.h b/include/osmocom/hlr/mslookup_server.h</span><br><span>new file mode 100644</span><br><span>index 0000000..5425328</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/mslookup_server.h</span><br><span>@@ -0,0 +1,65 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</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%);">+ * 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%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_query;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! mslookup service name used for roaming/proxying between osmo-hlr instances. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_MSLOOKUP_SERVICE_HLR_GSUP "gsup.hlr"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! What addresses to return to mslookup queries when a subscriber is attached at the local site.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Mapping of service name to IP address and port. This corresponds to the VTY config for</span><br><span style="color: hsl(120, 100%, 40%);">+ * 'mslookup' / 'server' [/ 'msc MSC-1-2-3'] / 'service sip.voice at 1.2.3.4 1234'.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mslookup_service_host {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      char service[OSMO_MSLOOKUP_SERVICE_MAXLEN+1];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr_str host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr_str host_v6;</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%);">+/*! Sets of mslookup_service_host per connected MSC.</span><br><span style="color: hsl(120, 100%, 40%);">+ * When there are more than one MSC connected to this osmo-hlr, this allows keeping separate sets of service addresses</span><br><span style="color: hsl(120, 100%, 40%);">+ * for each MSC. The entry with mslookup_server_msc_wildcard as MSC name is used for all MSCs (if no match for that</span><br><span style="color: hsl(120, 100%, 40%);">+ * particular MSC is found). This corresponds to the VTY config for</span><br><span style="color: hsl(120, 100%, 40%);">+ * 'mslookup' / 'server' / 'msc MSC-1-2-3'.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct mslookup_server_msc_cfg {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_ipa_name name;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head service_hosts;</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 mslookup_service_host *mslookup_server_service_get(const struct osmo_ipa_name *msc_name, const char *service);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct mslookup_service_host *mslookup_server_msc_service_get(struct mslookup_server_msc_cfg *msc, const char *service,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                            bool create);</span><br><span style="color: hsl(120, 100%, 40%);">+int mslookup_server_msc_service_set(struct mslookup_server_msc_cfg *msc, const char *service,</span><br><span style="color: hsl(120, 100%, 40%);">+                                const struct osmo_sockaddr_str *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+int mslookup_server_msc_service_del(struct mslookup_server_msc_cfg *msc, const char *service,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 const struct osmo_sockaddr_str *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct osmo_ipa_name mslookup_server_msc_wildcard;</span><br><span style="color: hsl(120, 100%, 40%);">+struct mslookup_server_msc_cfg *mslookup_server_msc_get(const struct osmo_ipa_name *msc_name, bool create);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct mslookup_service_host *mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+void mslookup_server_rx(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct osmo_mslookup_result *result);</span><br><span>diff --git a/include/osmocom/hlr/timestamp.h b/include/osmocom/hlr/timestamp.h</span><br><span>new file mode 100644</span><br><span>index 0000000..9708985</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/timestamp.h</span><br><span>@@ -0,0 +1,28 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</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%);">+ * 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%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/time.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+typedef time_t timestamp_t;</span><br><span style="color: hsl(120, 100%, 40%);">+void timestamp_update(timestamp_t *timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+bool timestamp_age(const timestamp_t *timestamp, uint32_t *age);</span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index fec5275..571eaef 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -9,6 +9,7 @@</span><br><span>         $(LIBOSMOGSM_CFLAGS) \</span><br><span>       $(LIBOSMOVTY_CFLAGS) \</span><br><span>       $(LIBOSMOCTRL_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOMSLOOKUP_CFLAGS) \</span><br><span>  $(LIBOSMOABIS_CFLAGS) \</span><br><span>      $(SQLITE3_CFLAGS) \</span><br><span>  $(NULL)</span><br><span>@@ -53,14 +54,18 @@</span><br><span>        gsup_send.c \</span><br><span>        hlr_ussd.c \</span><br><span>         lu_fsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+    mslookup_server.c \</span><br><span style="color: hsl(120, 100%, 40%);">+   timestamp.c \</span><br><span>        $(NULL)</span><br><span> </span><br><span> osmo_hlr_LDADD = \</span><br><span>    $(top_builddir)/src/gsupclient/libosmo-gsup-client.la \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(top_builddir)/src/mslookup/libosmo-mslookup.la \</span><br><span>   $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOVTY_LIBS) \</span><br><span>         $(LIBOSMOCTRL_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOMSLOOKUP_LIBS) \</span><br><span>    $(LIBOSMOABIS_LIBS) \</span><br><span>        $(SQLITE3_LIBS) \</span><br><span>    $(NULL)</span><br><span>diff --git a/src/hlr.c b/src/hlr.c</span><br><span>index a33a68c..2cabab4 100644</span><br><span>--- a/src/hlr.c</span><br><span>+++ b/src/hlr.c</span><br><span>@@ -695,6 +695,7 @@</span><br><span>       INIT_LLIST_HEAD(&g_hlr->euse_list);</span><br><span>   INIT_LLIST_HEAD(&g_hlr->ss_sessions);</span><br><span>         INIT_LLIST_HEAD(&g_hlr->ussd_routes);</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);</span><br><span>         g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);</span><br><span> </span><br><span>         /* Init default (call independent) SS session guard timeout value */</span><br><span>diff --git a/src/mslookup_server.c b/src/mslookup_server.c</span><br><span>new file mode 100644</span><br><span>index 0000000..9c4dc58</span><br><span>--- /dev/null</span><br><span>+++ b/src/mslookup_server.c</span><br><span>@@ -0,0 +1,376 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</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%);">+ * 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 <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/db.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/timestamp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/mslookup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_mslookup_result not_found = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .rc = OSMO_MSLOOKUP_RC_NOT_FOUND,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_ipa_name mslookup_server_msc_wildcard = {};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void set_result(struct osmo_mslookup_result *result,</span><br><span style="color: hsl(120, 100%, 40%);">+                     const struct mslookup_service_host *service_host,</span><br><span style="color: hsl(120, 100%, 40%);">+                     uint32_t age)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!osmo_sockaddr_str_is_nonzero(&service_host->host_v4)</span><br><span style="color: hsl(120, 100%, 40%);">+          && !osmo_sockaddr_str_is_nonzero(&service_host->host_v6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                *result = not_found;</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%);">+     result->rc = OSMO_MSLOOKUP_RC_RESULT;</span><br><span style="color: hsl(120, 100%, 40%);">+      result->host_v4 = service_host->host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+        result->host_v6 = service_host->host_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+        result->age = age;</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 mslookup_service_host *mslookup_server_get_local_gsup_addr()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      static struct mslookup_service_host gsup_bind = {};</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mslookup_service_host *host;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Find a HLR/GSUP service set for the server (no VLR unit name) */</span><br><span style="color: hsl(120, 100%, 40%);">+   host = mslookup_server_service_get(&mslookup_server_msc_wildcard, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (host)</span><br><span style="color: hsl(120, 100%, 40%);">+             return host;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Try to use the locally configured GSUP bind address */</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_sockaddr_str_from_str(&gsup_bind.host_v4, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gsup_bind.host_v4.af == AF_INET6) {</span><br><span style="color: hsl(120, 100%, 40%);">+               gsup_bind.host_v6 = gsup_bind.host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+                gsup_bind.host_v4 = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return &gsup_bind;</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 mslookup_server_msc_cfg *mslookup_server_msc_get(const struct osmo_ipa_name *msc_name, bool create)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head *c = &g_hlr->mslookup.server.local_site_services;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mslookup_server_msc_cfg *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msc_name)</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%);">+        llist_for_each_entry(msc, c, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (osmo_ipa_name_cmp(&msc->name, msc_name))</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             return msc;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!create)</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%);">+        msc = talloc_zero(g_hlr, struct mslookup_server_msc_cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(msc);</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&msc->service_hosts);</span><br><span style="color: hsl(120, 100%, 40%);">+  msc->name = *msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_add_tail(&msc->entry, c);</span><br><span style="color: hsl(120, 100%, 40%);">+        return msc;</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 mslookup_service_host *mslookup_server_msc_service_get(struct mslookup_server_msc_cfg *msc, const char *service,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                           bool create)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mslookup_service_host *e;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msc)</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%);">+        llist_for_each_entry(e, &msc->service_hosts, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!strcmp(e->service, service))</span><br><span style="color: hsl(120, 100%, 40%);">+                  return e;</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 (!create)</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%);">+        e = talloc_zero(msc, struct mslookup_service_host);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(e);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_STRLCPY_ARRAY(e->service, service);</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_add_tail(&e->entry, &msc->service_hosts);</span><br><span style="color: hsl(120, 100%, 40%);">+ return e;</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 mslookup_service_host *mslookup_server_service_get(const struct osmo_ipa_name *msc_name, const char *service)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct mslookup_server_msc_cfg *msc = mslookup_server_msc_get(msc_name, false);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!msc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return mslookup_server_msc_service_get(msc, service, 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%);">+int mslookup_server_msc_service_set(struct mslookup_server_msc_cfg *msc, const char *service,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  const struct osmo_sockaddr_str *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mslookup_service_host *e;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!service || !service[0]</span><br><span style="color: hsl(120, 100%, 40%);">+       || strlen(service) > OSMO_MSLOOKUP_SERVICE_MAXLEN)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!addr || !osmo_sockaddr_str_is_nonzero(addr))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     e = mslookup_server_msc_service_get(msc, service, true);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!e)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (addr->af) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+         e->host_v4 = *addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->host_v6 = *addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     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%);">+int mslookup_server_msc_service_del(struct mslookup_server_msc_cfg *msc, const char *service,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const struct osmo_sockaddr_str *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct mslookup_service_host *e, *n;</span><br><span style="color: hsl(120, 100%, 40%);">+  int deleted = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOENT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry_safe(e, n, &msc->service_hosts, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (service && strcmp(service, e->service))</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 (addr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!osmo_sockaddr_str_cmp(addr, &e->host_v4)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               e->host_v4 = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+                         /* Removed one addr. If the other is still there, keep the entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (osmo_sockaddr_str_is_nonzero(&e->host_v6))</span><br><span style="color: hsl(120, 100%, 40%);">+                                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (!osmo_sockaddr_str_cmp(addr, &e->host_v6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                e->host_v6 = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+                         /* Removed one addr. If the other is still there, keep the entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (osmo_sockaddr_str_is_nonzero(&e->host_v4))</span><br><span style="color: hsl(120, 100%, 40%);">+                                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else</span><br><span style="color: hsl(120, 100%, 40%);">+                                /* No addr match, keep the entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* Addr matched and none is left. Delete. */</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_del(&e->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(e);</span><br><span style="color: hsl(120, 100%, 40%);">+               deleted++;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return deleted;</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%);">+/* A remote entity is asking us whether we are the home HLR of the given subscriber. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct mslookup_service_host *host;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (query->id.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_MSLOOKUP_ID_IMSI:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_MSLOOKUP_ID_MSISDN:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = db_subscr_exists_by_msisdn(g_hlr->dbc, query->id.msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMSLOOKUP, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = not_found;</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%);">+   if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: does not exist in local HLR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = not_found;</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%);">+   LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: found in local HLR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ host = mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       set_result(result, host, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DMSLOOKUP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                "Subscriber found, but error in service '" OSMO_MSLOOKUP_SERVICE_HLR_GSUP "' config:"</span><br><span style="color: hsl(120, 100%, 40%);">+                     " v4: " OSMO_SOCKADDR_STR_FMT "  v6: " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_SOCKADDR_STR_FMT_ARGS(&host->host_v4),</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_SOCKADDR_STR_FMT_ARGS(&host->host_v6));</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%);">+/* Look in the local HLR record: If the subscriber is "at home" in this HLR and is also currently located at a local</span><br><span style="color: hsl(120, 100%, 40%);">+ * VLR, we will find a valid location updating with vlr_number, and no vlr_via_proxy entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool subscriber_has_done_lu_here_hlr(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      uint32_t *lu_age,</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 style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hlr_subscriber _subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t age;</span><br><span style="color: hsl(120, 100%, 40%);">+</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 style="color: hsl(120, 100%, 40%);">+        switch (query->id.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_MSLOOKUP_ID_IMSI:</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 style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_MSLOOKUP_ID_MSISDN:</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 style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMSLOOKUP, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);</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 (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: does not exist in local HLR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</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 (!subscr->vlr_number[0]) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: not attached (vlr_number unset)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</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 (subscr->vlr_via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* The VLR is behind a proxy, the subscriber is not attached to a local VLR but a remote one. That</span><br><span style="color: hsl(120, 100%, 40%);">+             * remote proxy should instead respond to the service lookup request. */</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: last attach is not at local VLR, but at VLR '%s' via proxy %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</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 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 (!timestamp_age(&subscr->last_lu_seen, &age)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: Invalid last_lu_seen timestamp for subscriber\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</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%);">+     if (age > g_hlr->mslookup.server.local_attach_max_age) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: last attach was here, but too long ago: %us > %us\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 age, g_hlr->mslookup.server.local_attach_max_age);</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%);">+   *lu_age = age;</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_ipa_name_set_str(local_msc_name, subscr->vlr_number);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: attached %u seconds ago at local VLR %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+         age, osmo_ipa_name_to_str(local_msc_name));</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 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,</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%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      bool attached_here;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t lu_age = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_ipa_name msc_name = {};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* First ask the local HLR db, but if the local proxy record indicates a more recent LU, use that instead.</span><br><span style="color: hsl(120, 100%, 40%);">+     * 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 style="color: hsl(120, 100%, 40%);">+  *   - if the subscriber is known here, we will never proxy.</span><br><span style="color: hsl(120, 100%, 40%);">+   *   - if the subscriber is not known here, this local HLR db will never record a LU.</span><br><span style="color: hsl(120, 100%, 40%);">+  * However, if a subscriber was being proxied to a remote home HLR, and if then the subscriber was also added to</span><br><span style="color: hsl(120, 100%, 40%);">+       * the local HLR database, there might occur a situation where both reflect a LU. So, to be safe against all</span><br><span style="color: hsl(120, 100%, 40%);">+   * situations, compare the two entries.</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+   attached_here = subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Future: If proxy has a younger lu, replace. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (attached_here && !msc_name.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMSLOOKUP, LOGL_ERROR, "%s: attached here, but no VLR name known\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</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 (!attached_here) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Already logged "not attached" for both local-db and proxy attach */</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%);">+   LOGP(DMSLOOKUP, LOGL_INFO, "%s: attached here, at VLR %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_ipa_name_to_str(&msc_name));</span><br><span style="color: hsl(120, 100%, 40%);">+    *lu_age_p = lu_age;</span><br><span style="color: hsl(120, 100%, 40%);">+   *local_msc_name = msc_name;</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%);">+/* A remote entity is asking us whether we are providing the given service for the given subscriber. */</span><br><span style="color: hsl(120, 100%, 40%);">+void mslookup_server_rx(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct mslookup_service_host *service_host;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t age;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_ipa_name msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* A request for a home HLR: answer exactly if this is the subscriber's home HLR, i.e. the IMSI is listed in the</span><br><span style="color: hsl(120, 100%, 40%);">+   * HLR database. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (strcmp(query->service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return mslookup_server_rx_hlr_gsup(query, result);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* All other service types: answer when the subscriber has done a LU that is either listed in the local HLR or</span><br><span style="color: hsl(120, 100%, 40%);">+         * in the GSUP proxy database: i.e. if the subscriber has done a Location Updating at an VLR belonging to this</span><br><span style="color: hsl(120, 100%, 40%);">+         * HLR. Respond with whichever services are configured in the osmo-hlr.cfg. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!subscriber_has_done_lu_here(query, &age, &msc_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = not_found;</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%);">+   /* We've detected a LU here. The VLR where the LU happened is stored in msc_unit_name, and the LU age is stored</span><br><span style="color: hsl(120, 100%, 40%);">+    * in 'age'. Figure out the address configured for that VLR and service name. */</span><br><span style="color: hsl(120, 100%, 40%);">+      service_host = mslookup_server_service_get(&msc_name, query->service);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!service_host) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Find such service set globally (no VLR unit name) */</span><br><span style="color: hsl(120, 100%, 40%);">+               service_host = mslookup_server_service_get(&mslookup_server_msc_wildcard, query->service);</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 (!service_host) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DMSLOOKUP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                "%s: subscriber found, but no service %s configured, cannot service lookup request\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_quote_str_c(OTC_SELECT, query->service, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+            *result = not_found;</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%);">+   set_result(result, service_host, age);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/timestamp.c b/src/timestamp.c</span><br><span>new file mode 100644</span><br><span>index 0000000..002857d</span><br><span>--- /dev/null</span><br><span>+++ b/src/timestamp.c</span><br><span>@@ -0,0 +1,53 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</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%);">+ * 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 <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/timestamp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Central implementation to set a timestamp to the current time, in case we want to modify this in the future. */</span><br><span style="color: hsl(120, 100%, 40%);">+void timestamp_update(timestamp_t *timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct timeval tv;</span><br><span style="color: hsl(120, 100%, 40%);">+    time_t raw;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct tm utc;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The simpler way would be just time(&raw), but by using osmo_gettimeofday() we can also use</span><br><span style="color: hsl(120, 100%, 40%);">+      * osmo_gettimeofday_override for unit tests independent from real time. */</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_gettimeofday(&tv, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     raw = tv.tv_sec;</span><br><span style="color: hsl(120, 100%, 40%);">+      gmtime_r(&raw, &utc);</span><br><span style="color: hsl(120, 100%, 40%);">+ *timestamp = mktime(&utc);</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%);">+/* Calculate seconds since a given timestamp was taken. Return true for a valid age returned in age_p, return false if</span><br><span style="color: hsl(120, 100%, 40%);">+ * the timestamp is either in the future or the age surpasses uint32_t range. When false is returned, *age_p is set to</span><br><span style="color: hsl(120, 100%, 40%);">+ * UINT32_MAX. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool timestamp_age(const timestamp_t *timestamp, uint32_t *age_p)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int64_t age64;</span><br><span style="color: hsl(120, 100%, 40%);">+        timestamp_t now;</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp_update(&now);</span><br><span style="color: hsl(120, 100%, 40%);">+   age64 = (int64_t)now - (int64_t)(*timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (age64 < 0 || age64 > UINT32_MAX) {</span><br><span style="color: hsl(120, 100%, 40%);">+          *age_p = UINT32_MAX;</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%);">+     *age_p = (uint32_t)age64;</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></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16209">change 16209</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/+/16209"/><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: Ife4a61d71926d08f310a1aeed9d9f1974f64178b </div>
<div style="display:none"> Gerrit-Change-Number: 16209 </div>
<div style="display:none"> Gerrit-PatchSet: 34 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>