core: fix up connectivity state checks

We want to start the connectivity checks when any device gets
activated, and stop them when all devices get deactivated.  We
also want to make sure it's running if a device gets deactivated
but other devices are still active.  If multiple devices are
activated and if the default device gets deactivated, the other
device may become the default device and we'll need a connectivity
check for that device since we can't do per-device checks yet.

Also, if connectivity checking is enabled at compile-time but
not enabled at runtime, the connectivity bits should always
report "connected" to preserve previous behavior, and this code
makes it clearer how that is handled.
This commit is contained in:
Dan Williams 2011-12-14 13:41:57 -06:00
parent d47072a1a1
commit 5937861ca7
3 changed files with 85 additions and 51 deletions

View file

@ -71,6 +71,22 @@ nm_connectivity_get_connected (NMConnectivity *connectivity)
return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->connected;
}
static void
update_connected (NMConnectivity *self, gboolean connected)
{
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
gboolean old_connected = priv->connected;
if (priv->uri == NULL || priv->interval == 0) {
/* Default to connected if no checks are to be run */
priv->connected = TRUE;
} else
priv->connected = connected;
if (priv->connected != old_connected)
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_CONNECTED);
}
static void
nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
{
@ -103,62 +119,74 @@ nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_
g_free (uri_string);
/* update connectivity and emit signal */
if (priv->connected != connected_new) {
priv->connected = connected_new;
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_CONNECTED);
}
update_connected (self, connected_new);
priv->running = FALSE;
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_RUNNING);
}
void
nm_connectivity_check (NMConnectivity *self)
static gboolean
run_check (gpointer user_data)
{
NMConnectivity *self = NM_CONNECTIVITY (user_data);
NMConnectivityPrivate *priv;
SoupURI *soup_uri;
SoupMessage *msg;
g_return_if_fail (NM_IS_CONNECTIVITY (self));
g_return_val_if_fail (NM_IS_CONNECTIVITY (self), FALSE);
priv = NM_CONNECTIVITY_GET_PRIVATE (self);
if (priv->running)
return;
/* check given url async */
soup_uri = soup_uri_new (priv->uri);
if (soup_uri && SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
msg = soup_message_new_from_uri ("GET", soup_uri);
soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
soup_session_queue_message (priv->soup_session,
msg,
nm_connectivity_check_cb,
self);
if (priv->uri) {
/* check given url async */
soup_uri = soup_uri_new (priv->uri);
if (soup_uri && SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
msg = soup_message_new_from_uri ("GET", soup_uri);
soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
soup_session_queue_message (priv->soup_session,
msg,
nm_connectivity_check_cb,
self);
priv->running = TRUE;
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_RUNNING);
nm_log_dbg (LOGD_CORE, "Connectivity check with uri '%s' started.", priv->uri);
} else
nm_log_err (LOGD_CORE, "Invalid uri '%s' for connectivity check.", priv->uri);
priv->running = TRUE;
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_RUNNING);
nm_log_dbg (LOGD_CORE, "Connectivity check with uri '%s' started.", priv->uri);
} else
nm_log_err (LOGD_CORE, "Invalid uri '%s' for connectivity check.", priv->uri);
if (soup_uri)
soup_uri_free (soup_uri);
if (soup_uri)
soup_uri_free (soup_uri);
} else {
/* No URI given - default is connected */
if (!priv->connected) {
priv->connected = TRUE;
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_CONNECTED);
}
}
return TRUE; /* keep firing */
}
static gboolean
do_check (gpointer user_data)
void
nm_connectivity_start_check (NMConnectivity *self)
{
nm_connectivity_check (NM_CONNECTIVITY (user_data));
return TRUE; /* keep checking */
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
if (!priv->uri || !priv->interval) {
nm_connectivity_stop_check (self);
return;
}
if (priv->check_id == 0)
priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self);
/* Start an immediate check */
if (priv->running == FALSE)
run_check (self);
}
void
nm_connectivity_stop_check (NMConnectivity *self)
{
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
if (priv->check_id) {
g_source_remove (priv->check_id);
priv->check_id = 0;
}
update_connected (self, FALSE);
}
NMConnectivity *
@ -167,7 +195,6 @@ nm_connectivity_new (const gchar *check_uri,
const gchar *check_response)
{
NMConnectivity *self;
NMConnectivityPrivate *priv;
self = g_object_new (NM_TYPE_CONNECTIVITY,
NM_CONNECTIVITY_URI, check_uri,
@ -175,11 +202,7 @@ nm_connectivity_new (const gchar *check_uri,
NM_CONNECTIVITY_RESPONSE, check_response ? check_response : DEFAULT_RESPONSE,
NULL);
g_return_val_if_fail (self != NULL, NULL);
/* Kick off a check if required */
priv = NM_CONNECTIVITY_GET_PRIVATE (self);
if (priv->uri && priv->interval)
priv->check_id = g_timeout_add_seconds (priv->interval, do_check, self);
update_connected (self, FALSE);
return self;
}

View file

@ -57,7 +57,9 @@ NMConnectivity *nm_connectivity_new (const gchar *check_uri,
guint check_interval,
const gchar *check_response);
void nm_connectivity_check (NMConnectivity *connectivity);
void nm_connectivity_start_check (NMConnectivity *connectivity);
void nm_connectivity_stop_check (NMConnectivity *connectivity);
gboolean nm_connectivity_get_connected (NMConnectivity *connectivity);

View file

@ -470,7 +470,8 @@ manager_device_state_changed (NMDevice *device,
NMDeviceStateReason reason,
gpointer user_data)
{
NMManager *manager = NM_MANAGER (user_data);
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
switch (new_state) {
case NM_DEVICE_STATE_UNMANAGED:
@ -478,18 +479,26 @@ manager_device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_DISCONNECTED:
case NM_DEVICE_STATE_PREPARE:
case NM_DEVICE_STATE_FAILED:
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
break;
default:
break;
}
nm_manager_update_state (manager);
nm_manager_update_state (self);
#if WITH_CONCHECK
/* trigger a connectivity check */
if (new_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_ACTIVATED)
nm_connectivity_check (NM_MANAGER_GET_PRIVATE (manager)->connectivity);
if (priv->state >= NM_STATE_CONNECTED_LOCAL) {
if (old_state == NM_DEVICE_STATE_ACTIVATED || new_state == NM_DEVICE_STATE_ACTIVATED) {
/* Still connected, but a device activated or deactivated; make sure
* we still have connectivity on the other activated devices.
*/
nm_connectivity_start_check (priv->connectivity);
}
} else {
/* Cannot be connected if no devices are activated */
nm_connectivity_stop_check (priv->connectivity);
}
#endif
}