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