Commit 267bc993 authored by Thomas Bechtold's avatar Thomas Bechtold Committed by Dan Williams

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
parent 5ea7e608
......@@ -288,6 +288,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
......
......@@ -190,7 +190,11 @@ NetworkManager_SOURCES = \
nm-rfkill.h \
nm-session-monitor.h \
nm-session-utils.c \
nm-session-utils.h
nm-session-utils.h \
nm-session-monitor.c \
nm-session-monitor.h \
nm-connectivity.c \
nm-connectivity.h
if SESSION_TRACKING_SYSTEMD
NetworkManager_SOURCES += nm-session-monitor-systemd.c
......@@ -272,6 +276,7 @@ NetworkManager_CPPFLAGS = \
$(GMODULE_CFLAGS) \
$(POLKIT_CFLAGS) \
$(SYSTEMD_CFLAGS) \
$(LIBSOUP_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DBINDIR=\"$(bindir)\" \
-DSBINDIR=\"$(sbindir)\" \
......@@ -307,6 +312,7 @@ NetworkManager_LDADD = \
$(GMODULE_LIBS) \
$(POLKIT_LIBS) \
$(SYSTEMD_LIBS) \
$(LIBSOUP_LIBS) \
$(LIBM) \
$(LIBDL)
......
......@@ -346,6 +346,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;
......@@ -379,6 +382,9 @@ main (int argc, char *argv[])
" AGENTS,SETTINGS,SUSPEND,CORE,DEVICE,OLPC,WIMAX,\n"
" INFINIBAND,FIREWALL]"),
"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}
};
......@@ -436,7 +442,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,
......@@ -566,6 +573,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",
......@@ -666,6 +676,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);
......
......@@ -34,6 +34,9 @@ struct NMConfig {
char **dns_plugins;
char *log_level;
char *log_domains;
char *connectivity_uri;
guint connectivity_interval;
char *connectivity_response;
};
/************************************************************************/
......@@ -97,6 +100,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
......@@ -105,6 +133,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;
......@@ -144,6 +175,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;
}
......@@ -156,6 +203,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;
......@@ -165,7 +215,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;
}
......@@ -180,7 +232,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) {
......@@ -192,7 +246,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) {
......@@ -230,7 +286,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);
}
......
......@@ -38,6 +38,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);
......@@ -46,6 +49,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);
......
This diff is collapsed.
/* -*- 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 */
......@@ -67,6 +67,8 @@
#include "nm-device-factory.h"
#include "wifi-utils.h"
#include "nm-enum-types.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"
......@@ -194,6 +196,7 @@ typedef struct {
GSList *devices;
NMState state;
NMConnectivity *connectivity;
NMDBusManager *dbus_mgr;
NMUdevManager *udev_mgr;
......@@ -424,21 +427,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;
}
}
}
}
......@@ -459,6 +466,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:
......@@ -473,6 +481,10 @@ 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);
}
/* Removes a device from a device list; returns the start of the new device list */
......@@ -3341,6 +3353,36 @@ handle_firmware_changed (gpointer user_data)
return FALSE;
}
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,
......@@ -3542,6 +3584,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;
......@@ -3557,6 +3602,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);
......@@ -3655,6 +3705,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);
......
......@@ -84,7 +84,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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment