Skip to content

Commit

Permalink
[connman-vpn] Increasing delay in VPN autoconnect. Contributes to JB#…
Browse files Browse the repository at this point in the history
…42337

This commit changes the vpn autoconnection to operate as follows:
 - Try to connect a VPN if the default transport service is connected
 - Stop autoconnecting if there is no transport service
 - Stop autoconnecting if default transport service is not connected
 - Stop autoconnecting if default transport service is connected VPN
 - Keep loop running when a VPN is in connecting state
 - When kept in loop increase the delay periodically

In order to show indication to the user it is important to let
autoconnect try to connect a VPN. Otherwise in case of network going
down to ready from online, or connecting a network which has no access
to Internet there is no indication that VPN is being connected.

The autoconnect function will be kept in main loop if there are VPNs to
automatically connect and the delay will increase based on the attempt
count. Every VPN_AUTOCONNECT_TIMEOUT_STEP (30) increases the delay with
1s up to 10s. The amount of attempts after which the delay no longer
increases is VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_TRESHOLD (270). After
initial call the delay is 1s, increasing up to 10s.

Each call to vpn_auto_connect() is changed to remove the timeout
function from main loop in order to reset the attempt counter and the
delay. This way each change happening in networking conditions that
triggers call to do_auto_connect() will also reset these and gets the
autoconnect running with no delay, otherwise there may be a max. 10s
delay before VPN is even attempted to connect.

Each connman service change now triggers vpn_auto_connect() (ecf3ce0) so
it is safe to drop out from main loop after no connected is found.
Except ready -> online state change does not trigger anything.

This reduces battery usage on situation, where VPN is to be connected
automatically but the network goes offline (e.g., during night) so the
VPN autoconnect would not be continuously running in the background with
1s intervals. Also, in case a VPN server goes unavailable for a short or
longer period this will first try to connect more rapidly in the first
30 tries and increase the delay periodically.
  • Loading branch information
LaakkonenJussi committed Sep 12, 2018
1 parent 18866d9 commit 992c05e
Showing 1 changed file with 64 additions and 44 deletions.
108 changes: 64 additions & 44 deletions connman/src/service.c
Expand Up @@ -50,6 +50,8 @@
#define ONLINE_CHECK_RETRY_COUNT 12

#define VPN_AUTOCONNECT_TIMEOUT_DEFAULT 1
#define VPN_AUTOCONNECT_TIMEOUT_STEP 30
#define VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_TRESHOLD 270

/* (Some) property names */
#define PROP_ACCESS "Access"
Expand Down Expand Up @@ -4507,9 +4509,17 @@ static void do_auto_connect(struct connman_service *service,
* Run service auto connect when a service is changed. This is not
* needed to be run when VPN service changes, then vpn auto connect is
* sufficient.
*
* Do not run vpn_auto_connect() when VPN entering failure state
* triggers this via service_complete() that is called for each service
* that is set to failure state in service_indicate_state(). Otherwise
* the timeout of vpn_auto_connect() will be reset and the delays for
* VPN connections are reset likewise.
*/
if (service->type != CONNMAN_SERVICE_TYPE_VPN)
__connman_service_auto_connect(reason);
else if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
return;

vpn_auto_connect();
}
Expand Down Expand Up @@ -5407,39 +5417,19 @@ static gboolean run_vpn_auto_connect(gpointer data) {
GList *list;
bool need_split = false;
int autoconnectable_vpns = 0;
int keep_in_loop = 0;
int delay = VPN_AUTOCONNECT_TIMEOUT_DEFAULT;
int attempts = 0;
int timeout = VPN_AUTOCONNECT_TIMEOUT_DEFAULT;
struct connman_service *def_service;

DBG("");

keep_in_loop = GPOINTER_TO_INT(data);
delay = keep_in_loop ? keep_in_loop : VPN_AUTOCONNECT_TIMEOUT_DEFAULT;
attempts = GPOINTER_TO_INT(data);
def_service = __connman_service_get_default();

/*
* If the transport service is not yet online but is connected do not
* stop auto connection unless VPN is being as default service.
*/
if (def_service && is_connected(def_service) &&
!is_online(def_service) &&
def_service->type != CONNMAN_SERVICE_TYPE_VPN) {
DBG("service %p %s not online (%s), connect delay %ds",
def_service, def_service->identifier,
state2string(def_service->state), delay);

/* Not the initial run, keep delay as it is */
if (keep_in_loop)
return G_SOURCE_CONTINUE;

goto retry;
}

/*
* Stop auto connecting VPN if there is no online transport service or
* if the current default service is a connected VPN (in ready state).
* Stop auto connecting VPN if there is no transport service or the
* transport service is not connected or if the current default service
* is a connected VPN (in ready state).
*/
if (!def_service || !is_online(def_service) ||
if (!def_service || !is_connected(def_service) ||
(def_service->type == CONNMAN_SERVICE_TYPE_VPN &&
is_connected(def_service))) {

Expand All @@ -5459,6 +5449,14 @@ static gboolean run_vpn_auto_connect(gpointer data) {
if (is_connected(service) || is_connecting(service)) {
if (!service->do_split_routing)
need_split = true;

/*
* If the service is connecting it must be accounted
* for to keep the autoconnection in main loop.
*/
if (is_connecting(service))
autoconnectable_vpns++;

continue;
}

Expand Down Expand Up @@ -5486,25 +5484,30 @@ static gboolean run_vpn_auto_connect(gpointer data) {
need_split = true;
}

/* If there is no VPN to automatically connect stop autoconnecting.*/
/* Stop if there is no VPN to automatically connect.*/
if (!autoconnectable_vpns) {
DBG("stopping, no autoconnectable VPNs found");
goto out;
}

/* Use current delay */
if (keep_in_loop) {
DBG("continuing, delay %ds", delay);
return G_SOURCE_CONTINUE;
}
/* Increase the attempt count up to the treshold.*/
if (attempts < VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_TRESHOLD)
attempts++;

/*
* Timeout increases with 1s after VPN_AUTOCONNECT_TIMEOUT_STEP amount
* of attempts made. After VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_TRESHOLD is
* reached the delay does not increase.
*/
timeout = timeout + (int)(attempts / VPN_AUTOCONNECT_TIMEOUT_STEP);

retry:
/* Re add this to main loop */
vpn_autoconnect_timeout =
g_timeout_add_seconds(delay, run_vpn_auto_connect,
GINT_TO_POINTER(delay));
g_timeout_add_seconds(timeout, run_vpn_auto_connect,
GINT_TO_POINTER(attempts));

DBG("re-added to main loop with %ds delay", delay);
DBG("re-added to main loop, next VPN autoconnect in %d seconds (#%d)",
timeout, attempts);

return G_SOURCE_REMOVE;

Expand All @@ -5515,8 +5518,18 @@ static gboolean run_vpn_auto_connect(gpointer data) {

static void vpn_auto_connect(void)
{
if (vpn_autoconnect_timeout)
return;
DBG("");

/*
* Remove existing autoconnect from main loop to reset the attempt
* counter in order to get VPN connected when there is a network change.
*/
if (vpn_autoconnect_timeout) {
if (!g_source_remove(vpn_autoconnect_timeout)) {
DBG("cannot remove VPN autoconnect from main loop");
return;
}
}

vpn_autoconnect_timeout =
g_timeout_add_seconds(0, run_vpn_auto_connect, NULL);
Expand Down Expand Up @@ -5600,12 +5613,19 @@ static gboolean service_retry_connect(gpointer data)

if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {

/* Clear the state */
service_ipconfig_indicate_states(service,
/*
* Do not reset VPN state here as doing so leads to reseting of
* the VPN autoconnect timer without proper reason.
*/
if (service->type != CONNMAN_SERVICE_TYPE_VPN) {
/* Clear the state */
service_ipconfig_indicate_states(service,
CONNMAN_SERVICE_STATE_IDLE);
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
service->state = CONNMAN_SERVICE_STATE_IDLE;
state_changed(service);
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);

service->state = CONNMAN_SERVICE_STATE_IDLE;
state_changed(service);
}

/* Schedule the next auto-connect round */
do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
Expand Down

0 comments on commit 992c05e

Please sign in to comment.