Re: [PATCH] core: add internet connectivity check
- From: Thomas Bechtold <thomasbechtold jpberlin de>
- To: Marcel Holtmann <marcel holtmann org>
- Cc: networkmanager-list gnome org
- Subject: Re: [PATCH] core: add internet connectivity check
- Date: Sat, 22 Oct 2011 21:01:11 +0200
Hi Marcel,
On Sat, 2011-10-22 at 11:59 +0200, Marcel Holtmann wrote:
> Hi Tom,
>
> > * use libsoup to check internet connectivity with
> > a http request to a configurable uri and check
> > the response code for 200
>
> just checking for result code 200 will not be enough. A bunch of
> hotspots return result code 200 actually. You need to also check that
> the content of your requested website is valid. Otherwise you have a
> bunch of false positives.
you are right. result code check is not enough. the attached patch adds
another parameter (connectivity-response) to define the expected
response. the connectivity-response can be a regular expression and if
the expression match the http response, connectivity check was
successful. the status code doesn't matter any more.
to test the connectivity check, do eg:
./NetworkManager --no-daemon --log-level=DEBUG --log-domains=CORE
--connectivity-uri=http://toabctl.de
--connectivity-response="<title>toabctl.de</title>"
Tom
>From c5e05b7181b74db80525f49eb2224b81adc190a7 Mon Sep 17 00:00:00 2001
From: Thomas Bechtold <thomasbechtold jpberlin de>
Date: Fri, 21 Oct 2011 21:21:30 +0200
Subject: [PATCH] core: add internet connectivity check
* use libsoup to compare a http response from a given
uri with a given response (use regex for this)
* do periodically check the connectivity. Check interval
is configurable
* check connectivity when device state change
from/to NM_DEVICE_STATE_ACTIVATED
---
configure.ac | 4 +
src/Makefile.am | 6 +-
src/main.c | 14 ++-
src/nm-config.c | 66 +++++++++-
src/nm-config.h | 6 +
src/nm-connectivity.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++
src/nm-connectivity.h | 69 ++++++++++
src/nm-manager.c | 84 ++++++++++--
src/nm-manager.h | 5 +-
9 files changed, 583 insertions(+), 20 deletions(-)
create mode 100644 src/nm-connectivity.c
create mode 100644 src/nm-connectivity.h
diff --git a/configure.ac b/configure.ac
index ac6da48..dabb4f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -266,6 +266,10 @@ PKG_CHECK_MODULES(GIO, gio-2.0)
AC_SUBST(GIO_CFLAGS)
AC_SUBST(GIO_LIBS)
+PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.26])
+AC_SUBST(LIBSOUP_CFLAGS)
+AC_SUBST(LIBSOUP_LIBS)
+
GOBJECT_INTROSPECTION_CHECK([0.9.6])
# Qt4
diff --git a/src/Makefile.am b/src/Makefile.am
index cbcfdc6..d8e9a2d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -177,7 +177,9 @@ NetworkManager_SOURCES = \
nm-dhcp6-config.h \
nm-rfkill.h \
nm-session-monitor.c \
- nm-session-monitor.h
+ nm-session-monitor.h \
+ nm-connectivity.c \
+ nm-connectivity.h
nm-access-point-glue.h: $(top_srcdir)/introspection/nm-access-point.xml
$(AM_V_GEN) dbus-binding-tool --prefix=nm_access_point --mode=glib-server --output=$@ $<
@@ -240,6 +242,7 @@ NetworkManager_CPPFLAGS = \
$(LIBNL_CFLAGS) \
$(GMODULE_CFLAGS) \
$(POLKIT_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DBINDIR=\"$(bindir)\" \
-DSBINDIR=\"$(sbindir)\" \
@@ -279,6 +282,7 @@ NetworkManager_LDADD = \
$(LIBNL_LIBS) \
$(GMODULE_LIBS) \
$(POLKIT_LIBS) \
+ $(LIBSOUP_LIBS) \
$(LIBM) \
$(LIBDL)
diff --git a/src/main.c b/src/main.c
index b7c0fd5..3b972d1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -419,6 +419,9 @@ main (int argc, char *argv[])
char *pidfile = NULL, *state_file = NULL;
char *config_path = NULL, *plugins = NULL;
char *log_level = NULL, *log_domains = NULL;
+ char *connectivity_uri = NULL;
+ gint connectivity_interval = -1;
+ char *connectivity_response = NULL;
gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
gboolean success, show_version = FALSE;
NMPolicy *policy = NULL;
@@ -447,6 +450,9 @@ main (int argc, char *argv[])
" WIFI_SCAN,IP4,IP6,AUTOIP4,DNS,VPN,SHARING,SUPPLICANT,\n"
" AGENTS,SETTINGS,SUSPEND,CORE,DEVICE,OLPC,WIMAX]",
"HW,RFKILL,WIFI" },
+ { "connectivity-uri", 0, 0, G_OPTION_ARG_STRING, &connectivity_uri, "A http(s) address to check internet connectivity" },
+ { "connectivity-interval", 0, 0, G_OPTION_ARG_INT, &connectivity_interval, "the interval in seconds how often a connectivity check will be done" },
+ { "connectivity-response", 0, 0, G_OPTION_ARG_STRING, &connectivity_response, "the expected response (regular expression)" },
{NULL}
};
@@ -501,7 +507,8 @@ main (int argc, char *argv[])
exit (1);
/* Read the config file and CLI overrides */
- config = nm_config_new (config_path, plugins, log_level, log_domains, &error);
+ config = nm_config_new (config_path, plugins, log_level, log_domains,
+ connectivity_uri, connectivity_interval, connectivity_response, &error);
if (config == NULL) {
fprintf (stderr, "Failed to read configuration: (%d) %s\n",
error ? error->code : -1,
@@ -626,6 +633,9 @@ main (int argc, char *argv[])
wifi_enabled,
wwan_enabled,
wimax_enabled,
+ nm_config_get_connectivity_uri (config),
+ nm_config_get_connectivity_interval (config),
+ nm_config_get_connectivity_response (config),
&error);
if (manager == NULL) {
nm_log_err (LOGD_CORE, "failed to initialize the network manager: %s",
@@ -716,6 +726,8 @@ done:
g_free (plugins);
g_free (log_level);
g_free (log_domains);
+ g_free (connectivity_uri);
+ g_free (connectivity_response);
nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
exit (success ? 0 : 1);
diff --git a/src/nm-config.c b/src/nm-config.c
index 71f67d5..e2e4f93 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -34,6 +34,9 @@ struct NMConfig {
char **dns_plugins;
char *log_level;
char *log_domains;
+ char *connectivity_uri;
+ guint connectivity_interval;
+ char *connectivity_response;
};
/************************************************************************/
@@ -116,6 +119,31 @@ nm_config_get_log_domains (NMConfig *config)
return config->log_domains;
}
+const char *
+nm_config_get_connectivity_uri (NMConfig *config)
+{
+ g_return_val_if_fail (config != NULL, NULL);
+
+ return config->connectivity_uri;
+}
+
+const guint
+nm_config_get_connectivity_interval (NMConfig *config)
+{
+ g_return_val_if_fail (config != NULL, -1);
+
+ return config->connectivity_interval;
+}
+
+const char *
+nm_config_get_connectivity_response (NMConfig *config)
+{
+ g_return_val_if_fail (config != NULL, NULL);
+
+ return config->connectivity_response;
+}
+
+
/************************************************************************/
static gboolean
@@ -124,6 +152,9 @@ fill_from_file (NMConfig *config,
const char *cli_plugins,
const char *cli_log_level,
const char *cli_log_domains,
+ const char *cli_connectivity_uri,
+ const gint cli_connectivity_interval,
+ const char *cli_connectivity_response,
GError **error)
{
GKeyFile *kf;
@@ -163,6 +194,22 @@ fill_from_file (NMConfig *config,
config->log_domains = g_strdup (cli_log_domains);
else
config->log_domains = g_key_file_get_value (kf, "logging", "domains", NULL);
+
+ if (cli_connectivity_uri && strlen (cli_connectivity_uri))
+ config->connectivity_uri = g_strdup (cli_connectivity_uri);
+ else
+ config->connectivity_uri = g_key_file_get_value (kf, "connectivity", "uri", NULL);
+
+ if (cli_connectivity_interval >= 0)
+ config->connectivity_interval = cli_connectivity_interval;
+ else
+ config->connectivity_interval = g_key_file_get_integer (kf, "connectivity", "interval", NULL);
+
+ if (cli_connectivity_response && strlen (cli_connectivity_response))
+ config->connectivity_response = g_strdup (cli_connectivity_response);
+ else
+ config->connectivity_response = g_key_file_get_value (kf, "connectivity", "response", NULL);
+
success = TRUE;
}
@@ -175,6 +222,9 @@ nm_config_new (const char *cli_config_path,
const char *cli_plugins,
const char *cli_log_level,
const char *cli_log_domains,
+ const char *cli_connectivity_uri,
+ const gint cli_connectivity_interval,
+ const char *cli_connectivity_response,
GError **error)
{
NMConfig *config;
@@ -184,7 +234,9 @@ nm_config_new (const char *cli_config_path,
if (cli_config_path) {
/* Bad user-specific config file path is a hard error */
- if (!fill_from_file (config, cli_config_path, cli_plugins, cli_log_level, cli_log_domains, error)) {
+ if (!fill_from_file (config, cli_config_path, cli_plugins, cli_log_level, cli_log_domains,
+ cli_connectivity_uri, cli_connectivity_interval, cli_connectivity_response,
+ error)) {
nm_config_free (config);
return NULL;
}
@@ -199,7 +251,9 @@ nm_config_new (const char *cli_config_path,
*/
/* Try deprecated nm-system-settings.conf first */
- if (fill_from_file (config, NM_OLD_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains, &local))
+ if (fill_from_file (config, NM_OLD_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains,
+ cli_connectivity_uri, cli_connectivity_interval, cli_connectivity_response,
+ &local))
return config;
if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) {
@@ -211,7 +265,9 @@ nm_config_new (const char *cli_config_path,
g_clear_error (&local);
/* Try the standard config file location next */
- if (fill_from_file (config, NM_DEFAULT_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains, &local))
+ if (fill_from_file (config, NM_DEFAULT_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains,
+ cli_connectivity_uri, cli_connectivity_interval, cli_connectivity_response,
+ &local))
return config;
if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) {
@@ -226,6 +282,7 @@ nm_config_new (const char *cli_config_path,
/* ignore error if config file not found */
g_clear_error (&local);
+
return config;
}
@@ -240,7 +297,8 @@ nm_config_free (NMConfig *config)
g_strfreev (config->dns_plugins);
g_free (config->log_level);
g_free (config->log_domains);
-
+ g_free (config->connectivity_uri);
+ g_free (config->connectivity_response);
memset (config, 0, sizeof (*config));
g_free (config);
}
diff --git a/src/nm-config.h b/src/nm-config.h
index fae344f..e65f6fb 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -40,6 +40,9 @@ NMConfig *nm_config_new (const char *cli_config_path,
const char *cli_plugins,
const char *cli_log_level,
const char *cli_log_domains,
+ const char *cli_connectivity_check_uri,
+ const gint connectivity_check_interval,
+ const char *cli_connectivity_check_response,
GError **error);
const char *nm_config_get_path (NMConfig *config);
@@ -48,6 +51,9 @@ const char *nm_config_get_dhcp_client (NMConfig *config);
const char **nm_config_get_dns_plugins (NMConfig *config);
const char *nm_config_get_log_level (NMConfig *config);
const char *nm_config_get_log_domains (NMConfig *config);
+const char *nm_config_get_connectivity_uri (NMConfig *config);
+const guint nm_config_get_connectivity_interval (NMConfig *config);
+const char *nm_config_get_connectivity_response (NMConfig *config);
void nm_config_free (NMConfig *config);
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
new file mode 100644
index 0000000..a3aa02e
--- /dev/null
+++ b/src/nm-connectivity.c
@@ -0,0 +1,349 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Thomas Bechtold <thomasbechtold jpberlin de>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <libsoup/soup.h>
+
+#include "nm-connectivity.h"
+#include "nm-logging.h"
+#include "nm-manager.h"
+
+
+typedef struct {
+ //used for http requests
+ SoupSession *soup_session;
+ //indicates if a connectivity check is currently running
+ gboolean check_running;
+ //the uri to check
+ const gchar *check_uri;
+ //seconds when a check will be repeated
+ guint check_interval;
+ //the expected response for the connectivity check
+ const gchar *check_response;
+ //indicates if the last connection check was successful
+ gboolean connected;
+ //the source id for the periodic check
+ guint check_interval_source_id;
+
+} NMConnectivityPrivate;
+
+G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT)
+
+#define NM_CONNECTIVITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONNECTIVITY, NMConnectivityPrivate))
+
+
+enum {
+ CONNECTED_CHANGED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+ PROP_0,
+ PROP_CHECK_RUNNING,
+ PROP_CHECK_URI,
+ PROP_CHECK_INTERVAL,
+ PROP_CHECK_RESPONSE,
+ PROP_CONNECTED,
+ LAST_PROP
+};
+
+
+static gboolean nm_connectivity_interval (NMConnectivity *connectivity)
+{
+ /* periodically check connectivity */
+ nm_connectivity_check (connectivity);
+ return TRUE;
+}
+
+
+static void
+nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+ NMConnectivity *connectivity;
+ NMConnectivityPrivate *priv;
+ SoupURI *soup_uri;
+ gboolean connected_new;
+
+ g_return_if_fail (NM_IS_CONNECTIVITY (user_data));
+ connectivity = NM_CONNECTIVITY (user_data);
+ priv = NM_CONNECTIVITY_GET_PRIVATE (connectivity);
+
+ soup_uri = soup_message_get_uri (msg);
+
+ /* check response */
+ if (msg->response_body->data &&
+ (g_regex_match_simple (priv->check_response, msg->response_body->data, 0, 0))) {
+ nm_log_dbg (LOGD_CORE, "Connectivity check for uri '%s' with expected response '%s' successful.", soup_uri_to_string (soup_uri, FALSE), priv->check_response);
+ connected_new = TRUE;
+ } else {
+ nm_log_dbg (LOGD_CORE, "Connectivity check for uri '%s' with expected response '%s' not successful.", soup_uri_to_string (soup_uri, FALSE), priv->check_response);
+ connected_new = FALSE;
+ }
+
+ /* update connectivity and emit signal */
+ if (priv->connected != connected_new) {
+ priv->connected = connected_new;
+ g_object_notify (G_OBJECT (connectivity), NM_CONNECTIVITY_CONNECTED);
+ g_signal_emit_by_name (connectivity, NM_CONNECTIVITY_SIGNAL_CONNECTED_CHANGED, priv->connected);
+ }
+
+ priv->check_running = FALSE;
+ g_object_notify (G_OBJECT (connectivity), NM_CONNECTIVITY_CHECK_RUNNING);
+}
+
+
+void
+nm_connectivity_check (NMConnectivity *connectivity)
+{
+ NMConnectivityPrivate *priv;
+ SoupURI *soup_uri;
+ SoupMessage *connectivity_check_msg;
+
+ g_return_if_fail (NM_IS_CONNECTIVITY (connectivity));
+ priv = NM_CONNECTIVITY_GET_PRIVATE (connectivity);
+
+ if (priv->check_running) return;
+
+ if (priv->check_uri && strlen (priv->check_uri) && priv->check_response && strlen (priv->check_response)) {
+ /* check given url async */
+ soup_uri = soup_uri_new (priv->check_uri);
+ if (soup_uri && SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
+ connectivity_check_msg = soup_message_new_from_uri ("GET", soup_uri);
+ soup_session_queue_message (priv->soup_session, connectivity_check_msg, nm_connectivity_check_cb, connectivity);
+
+ priv->check_running = TRUE;
+ g_object_notify (G_OBJECT (connectivity), NM_CONNECTIVITY_CHECK_RUNNING);
+ nm_log_dbg (LOGD_CORE, "connectivity check with uri '%s' started.", priv->check_uri);
+ soup_uri_free (soup_uri);
+ }
+ else {
+ nm_log_err (LOGD_CORE, "Invalid uri '%s' for connectivity check.", priv->check_uri);
+ }
+ }
+ else {
+ /* no uri/response given - default is connected so nm-manager can set NMState to GLOBAL */
+ if (!priv->connected)
+ {
+ priv->connected = TRUE;
+ g_object_notify (G_OBJECT (connectivity), NM_CONNECTIVITY_CONNECTED);
+ g_signal_emit_by_name (connectivity, NM_CONNECTIVITY_SIGNAL_CONNECTED_CHANGED, priv->connected);
+ }
+ }
+}
+
+
+NMConnectivity*
+nm_connectivity_new (const gchar *check_uri, guint check_interval, const gchar *check_response)
+{
+ NMConnectivity *connectivity = g_object_new (NM_TYPE_CONNECTIVITY, NULL);
+ NMConnectivityPrivate *priv;
+
+ priv = NM_CONNECTIVITY_GET_PRIVATE (connectivity);
+
+ priv->check_uri = check_uri;
+ priv->check_interval = check_interval;
+ priv->check_response = check_response;
+
+ if (check_uri && strlen (check_uri) && check_interval > 0)
+ priv->check_interval_source_id = g_timeout_add_seconds (check_interval, (GSourceFunc) nm_connectivity_interval, connectivity);
+ else
+ priv->check_interval_source_id = 0;
+
+ return connectivity;
+}
+
+
+static void
+nm_connectivity_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMConnectivity *self = NM_CONNECTIVITY (object);
+ NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+ switch (property_id)
+ {
+ case PROP_CHECK_RUNNING:
+ priv->check_running = g_value_get_boolean (value);
+ break;
+ case PROP_CHECK_URI:
+ priv->check_uri = g_value_get_string (value);
+ break;
+ case PROP_CHECK_INTERVAL:
+ priv->check_interval = g_value_get_uint (value);
+ break;
+ case PROP_CHECK_RESPONSE:
+ priv->check_response = g_value_get_string (value);
+ break;
+ case PROP_CONNECTED:
+ priv->connected = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_connectivity_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMConnectivity *self = NM_CONNECTIVITY (object);
+ NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+ switch (property_id)
+ {
+ case PROP_CHECK_RUNNING:
+ g_value_set_boolean (value, priv->check_running);
+ break;
+ case PROP_CHECK_URI:
+ g_value_set_static_string (value, priv->check_uri);
+ break;
+ case PROP_CHECK_INTERVAL:
+ g_value_set_uint (value, priv->check_interval);
+ break;
+ case PROP_CHECK_RESPONSE:
+ g_value_set_static_string (value, priv->check_response);
+ break;
+ case PROP_CONNECTED:
+ g_value_set_boolean (value, priv->connected);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+nm_connectivity_init (NMConnectivity *self)
+{
+ NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+ priv->soup_session = soup_session_async_new ();
+ priv->check_running = FALSE;
+ priv->connected = FALSE;
+ priv->check_uri = NULL;
+ priv->check_interval = 0;
+ priv->check_interval_source_id = 0;
+ priv->check_response = NULL;
+}
+
+
+static void
+nm_connectivity_dispose (GObject *object)
+{
+ NMConnectivity *connectivity = NM_CONNECTIVITY (object);
+ NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (connectivity);
+
+ if (priv->soup_session)
+ {
+ soup_session_abort (priv->soup_session);
+ g_object_unref (priv->soup_session);
+ priv->soup_session = NULL;
+ }
+
+ priv->check_running = FALSE;
+ priv->connected = FALSE;
+
+ priv->check_uri = NULL;
+ priv->check_interval = 0;
+ priv->check_response = NULL;
+
+ if (priv->check_interval_source_id > 0)
+ {
+ g_warn_if_fail (g_source_remove (priv->check_interval_source_id) == TRUE);
+ priv->check_interval_source_id = 0;
+ }
+}
+
+
+static void
+nm_connectivity_class_init (NMConnectivityClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_type_class_add_private (klass, sizeof (NMConnectivityPrivate));
+
+ /* virtual methods */
+ object_class->set_property = nm_connectivity_set_property;
+ object_class->get_property = nm_connectivity_get_property;
+ object_class->dispose = nm_connectivity_dispose;
+
+ /* properties */
+ g_object_class_install_property
+ (object_class, PROP_CHECK_RUNNING,
+ g_param_spec_string (NM_CONNECTIVITY_CHECK_RUNNING,
+ "Running",
+ "Is Connectivity chunk running",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property
+ (object_class, PROP_CHECK_URI,
+ g_param_spec_string (NM_CONNECTIVITY_CHECK_URI,
+ "URI",
+ "Connectivity check URI",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property
+ (object_class, PROP_CHECK_INTERVAL,
+ g_param_spec_uint (NM_CONNECTIVITY_CHECK_INTERVAL,
+ "Interval",
+ "Connectivity check interval in seconds",
+ 0,
+ G_MAXUINT,
+ 300,
+ G_PARAM_READWRITE));
+ g_object_class_install_property
+ (object_class, PROP_CHECK_RESPONSE,
+ g_param_spec_string (NM_CONNECTIVITY_CHECK_RESPONSE,
+ "REsponse",
+ "Connectivity check reponse",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property
+ (object_class, PROP_CONNECTED,
+ g_param_spec_string (NM_CONNECTIVITY_CONNECTED,
+ "Connected",
+ "Is connected",
+ NULL,
+ G_PARAM_READABLE));
+
+ /* signals */
+ signals[CONNECTED_CHANGED] =
+ g_signal_new (NM_CONNECTIVITY_SIGNAL_CONNECTED_CHANGED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMConnectivityClass, connected_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+}
+
+
+gboolean
+nm_connectivity_get_connected (NMConnectivity *connectivity)
+{
+ g_return_val_if_fail (NM_IS_CONNECTIVITY (connectivity), FALSE);
+ return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->connected;
+}
diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h
new file mode 100644
index 0000000..cccedfb
--- /dev/null
+++ b/src/nm-connectivity.h
@@ -0,0 +1,69 @@
+
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Thomas Bechtold <thomasbechtold jpberlin de>
+ */
+
+#ifndef NM_CONNECTIVITY_H
+#define NM_CONNECTIVITY_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "NetworkManager.h"
+
+#define NM_TYPE_CONNECTIVITY (nm_connectivity_get_type ())
+#define NM_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTIVITY, NMConnectivity))
+#define NM_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTIVITY, NMConnectivityClass))
+#define NM_IS_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTIVITY))
+#define NM_IS_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CONNECTIVITY))
+#define NM_CONNECTIVITY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTIVITY, NMConnectivityClass))
+
+
+#define NM_CONNECTIVITY_CHECK_RUNNING "check-running"
+#define NM_CONNECTIVITY_CHECK_URI "check-uri"
+#define NM_CONNECTIVITY_CHECK_INTERVAL "check-interval"
+#define NM_CONNECTIVITY_CHECK_RESPONSE "check-response"
+#define NM_CONNECTIVITY_CONNECTED "connected"
+
+
+#define NM_CONNECTIVITY_SIGNAL_CONNECTED_CHANGED "connected-changed"
+
+
+typedef struct {
+ GObject parent;
+} NMConnectivity;
+
+typedef struct {
+ GObjectClass parent;
+
+ /* Signals */
+ void (*connected_changed) (NMConnectivity *connectivity, gboolean connected);
+} NMConnectivityClass;
+
+GType nm_connectivity_get_type (void);
+
+
+NMConnectivity *nm_connectivity_new (const gchar *check_uri, guint check_interval, const gchar *check_response);
+
+void nm_connectivity_check (NMConnectivity *connectivity);
+
+gboolean nm_connectivity_get_connected (NMConnectivity *connectivity);
+
+#endif /* NM_CONNECTIVITY_H */
+
diff --git a/src/nm-manager.c b/src/nm-manager.c
index b09cceb..58f9171 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -64,6 +64,8 @@
#include "nm-manager-auth.h"
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
+#include "nm-connectivity.h"
+
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
@@ -200,6 +202,7 @@ typedef struct {
GSList *devices;
NMState state;
+ NMConnectivity *connectivity;
NMDBusManager *dbus_mgr;
NMUdevManager *udev_mgr;
@@ -457,21 +460,25 @@ nm_manager_update_state (NMManager *manager)
if (manager_sleeping (manager))
new_state = NM_STATE_ASLEEP;
else {
- for (iter = priv->devices; iter; iter = iter->next) {
- NMDevice *dev = NM_DEVICE (iter->data);
- NMDeviceState state = nm_device_get_state (dev);
+ if (nm_connectivity_get_connected (priv->connectivity))
+ new_state = NM_STATE_CONNECTED_GLOBAL;
+ else {
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *dev = NM_DEVICE (iter->data);
+ NMDeviceState state = nm_device_get_state (dev);
- if (state == NM_DEVICE_STATE_ACTIVATED) {
- /* FIXME: handle local-only and site too */
- new_state = NM_STATE_CONNECTED_GLOBAL;
- break;
- }
+ if (state == NM_DEVICE_STATE_ACTIVATED) {
+ /* FIXME: handle local-only too */
+ new_state = NM_STATE_CONNECTED_SITE;
+ break;
+ }
- if (nm_device_is_activating (dev))
- new_state = NM_STATE_CONNECTING;
- else if (new_state != NM_STATE_CONNECTING) {
- if (state == NM_DEVICE_STATE_DEACTIVATING)
- new_state = NM_STATE_DISCONNECTING;
+ if (nm_device_is_activating (dev))
+ new_state = NM_STATE_CONNECTING;
+ else if (new_state != NM_STATE_CONNECTING) {
+ if (state == NM_DEVICE_STATE_DEACTIVATING)
+ new_state = NM_STATE_DISCONNECTING;
+ }
}
}
}
@@ -492,6 +499,7 @@ manager_device_state_changed (NMDevice *device,
gpointer user_data)
{
NMManager *manager = NM_MANAGER (user_data);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
switch (new_state) {
case NM_DEVICE_STATE_UNMANAGED:
@@ -507,6 +515,12 @@ manager_device_state_changed (NMDevice *device,
nm_manager_update_state (manager);
+ /* trigger a connectivity check */
+ if (new_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_ACTIVATED)
+ {
+ nm_connectivity_check (priv->connectivity);
+ }
+
if (new_state == NM_DEVICE_STATE_ACTIVATED) {
NMActRequest *req;
@@ -2858,6 +2872,36 @@ handle_firmware_changed (gpointer user_data)
}
static void
+connectivity_connected_changed (NMConnectivity *connectivity, gboolean connected, gpointer user_data)
+{
+ NMManager *manager;
+ NMManagerPrivate *priv;
+ NMState new_state;
+ g_return_if_fail (NM_IS_MANAGER (user_data));
+
+ manager = NM_MANAGER (user_data);
+ priv = NM_MANAGER_GET_PRIVATE (manager);
+
+ new_state = NM_STATE_DISCONNECTED;
+
+ if (connected)
+ new_state = NM_STATE_CONNECTED_GLOBAL;
+ else
+ {
+ /* FIXME: handle local here, too */
+ new_state = NM_STATE_CONNECTED_SITE;
+ }
+
+ if (priv->state != new_state) {
+ priv->state = new_state;
+ g_object_notify (G_OBJECT (manager), NM_MANAGER_STATE);
+
+ g_signal_emit (manager, signals[STATE_CHANGED], 0, priv->state);
+ nm_log_dbg (LOGD_CORE, "connectivity changed to: %i", connected);
+ }
+}
+
+static void
firmware_dir_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
@@ -3058,6 +3102,9 @@ nm_manager_new (NMSettings *settings,
gboolean initial_wifi_enabled,
gboolean initial_wwan_enabled,
gboolean initial_wimax_enabled,
+ const gchar *connectivity_uri,
+ gint connectivity_interval,
+ const gchar *connectivity_response,
GError **error)
{
NMManagerPrivate *priv;
@@ -3073,6 +3120,11 @@ nm_manager_new (NMSettings *settings,
priv = NM_MANAGER_GET_PRIVATE (singleton);
+ priv->connectivity = nm_connectivity_new (connectivity_uri, connectivity_interval, connectivity_response);
+
+ g_signal_connect (priv->connectivity, NM_CONNECTIVITY_SIGNAL_CONNECTED_CHANGED,
+ G_CALLBACK (connectivity_connected_changed), singleton);
+
bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
g_assert (bus);
dbus_connection = dbus_g_connection_get_connection (bus);
@@ -3171,6 +3223,11 @@ dispose (GObject *object)
TRUE);
}
+ if (priv->connectivity) {
+ g_object_unref (priv->connectivity);
+ priv->connectivity = NULL;
+ }
+
g_free (priv->hostname);
g_object_unref (priv->settings);
@@ -3491,6 +3548,7 @@ nm_manager_init (NMManager *manager)
priv->sleeping = FALSE;
priv->state = NM_STATE_DISCONNECTED;
+ priv->connectivity = NULL;
priv->dbus_mgr = nm_dbus_manager_get ();
diff --git a/src/nm-manager.h b/src/nm-manager.h
index b044971..b27d43f 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -73,7 +73,10 @@ NMManager *nm_manager_new (NMSettings *settings,
gboolean initial_net_enabled,
gboolean initial_wifi_enabled,
gboolean initial_wwan_enabled,
- gboolean initial_wimax_enabled,
+ gboolean initial_wimax_enabled,
+ const gchar *connectivity_uri,
+ gint connectivity_interval,
+ const gchar *connectivity_response,
GError **error);
NMManager *nm_manager_get (void);
--
1.7.5.4
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]