Commit 601e6e67ba for strongswan.org

commit 601e6e67ba5bc7e58c569ead796fd54c4d5d3ea0
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Fri Oct 16 12:46:30 2026 +0200

    android: Make sure we don't lose the delay before roam events

    The previous code ignored callback calls that arrived while a job was
    already queued.  So if multiple calls were triggered, there might not
    have been any delay after the last one and the network might not have
    been ready yet (should be less of an issue with the changes in the
    previous commit).  This change ensures we always trigger the roam event
    at least the given delay after the last callback (or `get_source_addr()`)
    call.  The default delay is also increased a bit to bunch more events
    together (in particular when switching from mobile to WiFi).

    The workaround for delayed IPv4 addresses is kept for compatibility with
    older Android versions.

diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_scheduler.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_scheduler.c
index c5cb18857b..69a2dbc76c 100644
--- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_scheduler.c
+++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_scheduler.c
@@ -24,7 +24,7 @@

 /**
  * Threshold in milliseconds up to which the default scheduler is used.
- * This includes the roaming events (100 ms) and initial retransmits.
+ * This includes the roaming events and initial retransmits.
  */
 #define DEFAULT_SCHEDULER_THRESHOLD 3000

diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c
index 27f75d2ba3..ab4ac0ea2f 100644
--- a/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c
+++ b/src/frontends/android/app/src/main/jni/libandroidbridge/kernel/android_net.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2023 Tobias Brunner
+ * Copyright (C) 2012-2026 Tobias Brunner
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -26,7 +26,7 @@
 #include <threading/mutex.h>

 /** delay before firing roam events (ms) */
-#define ROAM_DELAY 100
+#define ROAM_DELAY 500
 #define ROAM_DELAY_RECHECK 1000

 typedef struct private_android_net_t private_android_net_t;
@@ -48,6 +48,11 @@ struct private_android_net_t {
 	 */
 	timeval_t next_roam;

+	/**
+	 * Whether a roam event job is currently scheduled
+	 */
+	bool roam_scheduled;
+
 	/**
 	 * Mutex to check and update roam event time, and other private members
 	 */
@@ -67,8 +72,23 @@ struct private_android_net_t {
 /**
  * callback function that raises the delayed roam event
  */
-static job_requeue_t roam_event()
+CALLBACK(roam_event, job_requeue_t,
+	private_android_net_t *this)
 {
+	timeval_t now, diff;
+
+	time_monotonic(&now);
+	this->mutex->lock(this->mutex);
+	if (timercmp(&now, &this->next_roam, <))
+	{
+		/* another event got triggered in the meantime, reschedule */
+		timersub(&this->next_roam, &now, &diff);
+		this->mutex->unlock(this->mutex);
+		return JOB_RESCHEDULE_MS(diff.tv_sec * 1000 + diff.tv_usec / 1000);
+	}
+	this->roam_scheduled = FALSE;
+	this->mutex->unlock(this->mutex);
+
 	/* this will fail if no connection is up */
 	charonservice->bypass_socket(charonservice, -1, FALSE);
 	charon->kernel->roam(charon->kernel, TRUE);
@@ -76,29 +96,46 @@ static job_requeue_t roam_event()
 }

 /**
- * Listen for connectivity change events and queue a roam event
+ * Schedule a roam event after the given delay in ms. The mutex must be locked
+ * when calling this, it is unlocked automatically.
  */
-static void connectivity_cb(private_android_net_t *this,
-							bool disconnected)
+static void schedule_roam_unlock(private_android_net_t *this, u_int delay)
 {
-	timeval_t now;
+	timeval_t now, next, diff;
 	job_t *job;
+	u_int schedule = 0;

 	time_monotonic(&now);
-	this->mutex->lock(this->mutex);
-	this->connected = !disconnected;
-	if (!timercmp(&now, &this->next_roam, >))
+	next = now;
+	timeval_add_ms(&next, delay);
+	if (timercmp(&next, &this->next_roam, >))
+	{	/* only ever increase the target time */
+		this->next_roam = next;
+	}
+	if (!this->roam_scheduled)
 	{
-		this->mutex->unlock(this->mutex);
-		return;
+		timersub(&this->next_roam, &now, &diff);
+		schedule = diff.tv_sec * 1000 + diff.tv_usec / 1000;
+		this->roam_scheduled = schedule > 0;
 	}
-	timeval_add_ms(&now, ROAM_DELAY);
-	this->next_roam = now;
 	this->mutex->unlock(this->mutex);

-	job = (job_t*)callback_job_create((callback_job_cb_t)roam_event, NULL,
-									   NULL, NULL);
-	lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
+	if (schedule)
+	{
+		job = (job_t*)callback_job_create(roam_event, this, NULL, NULL);
+		lib->scheduler->schedule_job_ms(lib->scheduler, job, schedule);
+	}
+}
+
+/**
+ * Listen for connectivity change events and queue a roam event
+ */
+static void connectivity_cb(private_android_net_t *this,
+							bool disconnected)
+{
+	this->mutex->lock(this->mutex);
+	this->connected = !disconnected;
+	schedule_roam_unlock(this, ROAM_DELAY);
 }

 METHOD(kernel_net_t, get_source_addr, host_t*,
@@ -110,8 +147,6 @@ METHOD(kernel_net_t, get_source_addr, host_t*,
 		struct sockaddr_in6 sin6;
 	} addr = {};
 	socklen_t addrlen = *dst->get_sockaddr_len(dst);
-	timeval_t now;
-	job_t *job;
 	host_t *host = NULL;
 	int skt;

@@ -133,19 +168,13 @@ METHOD(kernel_net_t, get_source_addr, host_t*,
 		}
 		else
 		{
-			time_monotonic(&now);
 			this->mutex->lock(this->mutex);
-			if (this->connected && timercmp(&now, &this->next_roam, >))
-			{	/* we were not able to find a source address but reportedly are
+			if (this->connected)
+			{
+				/* we were not able to find a source address but reportedly are
 				 * connected, trigger a recheck in case an IP address appears
 				 * delayed but the callback is not triggered again */
-				timeval_add_ms(&now, ROAM_DELAY_RECHECK);
-				this->next_roam = now;
-				this->mutex->unlock(this->mutex);
-				job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
-												  NULL, NULL, NULL);
-				lib->scheduler->schedule_job_ms(lib->scheduler, job,
-												ROAM_DELAY_RECHECK);
+				schedule_roam_unlock(this, ROAM_DELAY_RECHECK);
 			}
 			else
 			{