Hi, On Wed, 2011-11-16 at 00:19 -0600, Dan Williams wrote: > Pretty much what I was thinking about, but I wonder what we should do > for the expected response. I'm not sure a regex is the right way to go > at the moment because regex libraries differ in syntax and that might > tie us into a specific one. But regex is powerful :) I think maybe for > the moment we should just specify that it's a string match. Then later > when more intelligently handling hotspot perhaps we'll do regexes.
i use g_str_has_prefix() now to compare the response with the expected response. Try it with: NetworkManager --no-daemon --log-domains=CORE --log-level=DEBUG --connectivity-uri=http://toabctl.de/conntest.txt --connectivity-response=HelloNM Cheers, Tom
>From b04fe037a5ab994d62943402874a2adba24012ef Mon Sep 17 00:00:00 2001 From: Thomas Bechtold <[email protected]> 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 g_str_has_prefix () to compare) * 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 8d57f71..a68ec63 100644 --- a/configure.ac +++ b/configure.ac @@ -283,6 +283,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 c46e5e8..d11fbd4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -187,7 +187,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=$@ $< @@ -250,6 +252,7 @@ NetworkManager_CPPFLAGS = \ $(LIBNL_CFLAGS) \ $(GMODULE_CFLAGS) \ $(POLKIT_CFLAGS) \ + $(LIBSOUP_CFLAGS) \ -DG_DISABLE_DEPRECATED \ -DBINDIR=\"$(bindir)\" \ -DSBINDIR=\"$(sbindir)\" \ @@ -290,6 +293,7 @@ NetworkManager_LDADD = \ $(LIBNL_LIBS) \ $(GMODULE_LIBS) \ $(POLKIT_LIBS) \ + $(LIBSOUP_LIBS) \ $(LIBM) \ $(LIBDL) diff --git a/src/main.c b/src/main.c index 26fa28f..4b92e2d 100644 --- a/src/main.c +++ b/src/main.c @@ -420,6 +420,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; @@ -449,6 +452,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 start of the response" }, {NULL} }; @@ -503,7 +509,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, @@ -637,6 +644,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", @@ -737,6 +747,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..03d4867 --- /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 <[email protected]> + */ + +#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_str_has_prefix (msg->response_body->data, priv->check_response))) { + 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' failed.", + 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 <[email protected]> + */ + +#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 7205c7a..bb4024a 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; @@ -475,21 +478,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; + } } } } @@ -510,6 +517,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: @@ -525,6 +533,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; @@ -2950,6 +2964,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, @@ -3150,6 +3194,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; @@ -3165,6 +3212,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); @@ -3263,6 +3315,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); @@ -3583,6 +3640,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 4e8d67e..47a0a9c 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
_______________________________________________ networkmanager-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/networkmanager-list
