Commit fe5ba0f2 authored by Dan Winship's avatar Dan Winship

add GNetworkMonitor, for... monitoring the network

Add GNetworkMonitor and its associated extension point, provide a base
implementation that always claims the network is available, and a
netlink-based implementation built on top of that that actually tracks
the network state.

https://bugzilla.gnome.org/show_bug.cgi?id=620932
parent eb9755dc
......@@ -1109,6 +1109,10 @@ if test $glib_native_win32 = no; then
fi
AC_SUBST(NETWORK_LIBS)
AC_CHECK_HEADER([linux/netlink.h],
[AC_DEFINE(HAVE_NETLINK, 1, [We have AF_NETLINK sockets])])
AM_CONDITIONAL(HAVE_NETLINK, [test "$ac_cv_header_linux_netlink_h" = "yes"])
case $host in
*-*-solaris* )
AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, Needed to get declarations for msg_control and msg_controllen on Solaris)
......
......@@ -104,7 +104,7 @@
<xi:include href="xml/gasyncinitable.xml"/>
</chapter>
<chapter id="networking">
<title>Lowlevel network support</title>
<title>Low-level network support</title>
<xi:include href="xml/gsocket.xml"/>
<xi:include href="xml/ginetaddress.xml"/>
<xi:include href="xml/ginetaddressmask.xml"/>
......@@ -120,7 +120,7 @@
<xi:include href="xml/gproxyaddress.xml"/>
</chapter>
<chapter id="highlevel-socket">
<title>Highlevel network functionallity</title>
<title>High-level network functionallity</title>
<xi:include href="xml/gsocketclient.xml"/>
<xi:include href="xml/gsocketconnection.xml"/>
<xi:include href="xml/gunixconnection.xml"/>
......@@ -129,6 +129,7 @@
<xi:include href="xml/gsocketlistener.xml"/>
<xi:include href="xml/gsocketservice.xml"/>
<xi:include href="xml/gthreadedsocketservice.xml"/>
<xi:include href="xml/gnetworkmonitor.xml"/>
</chapter>
<chapter id="tls">
<title>TLS (SSL) support</title>
......
......@@ -3460,3 +3460,23 @@ G_DBUS_OBJECT_MANAGER_SERVER_GET_CLASS
<SUBSECTION Private>
GDBusObjectManagerServerPrivate
</SECTION>
<SECTION>
<FILE>gnetworkmonitor</FILE>
<TITLE>GNetworkMonitor</TITLE>
GNetworkMonitor
GNetworkMonitorInterface
G_NETWORK_MONITOR_EXTENSION_POINT_NAME
g_network_monitor_get_default
g_network_monitor_get_network_available
g_network_monitor_can_reach
g_network_monitor_can_reach_async
g_network_monitor_can_reach_finish
<SUBSECTION Standard>
g_network_monitor_get_type
G_TYPE_NETWORK_MONITOR
G_NETWORK_MONITOR
G_IS_NETWORK_MONITOR
G_NETWORK_MONITOR_GET_INTERFACE
</SECTION>
......@@ -232,6 +232,13 @@ giounixinclude_HEADERS = \
gunixoutputstream.h \
gunixsocketaddress.h \
$(NULL)
if HAVE_NETLINK
unix_sources += \
gnetworkmonitornetlink.c \
gnetworkmonitornetlink.h \
$(NULL)
endif
endif
win32_actual_sources = \
......@@ -332,6 +339,9 @@ libgio_2_0_la_SOURCES = \
gnativevolumemonitor.h \
gnetworkaddress.c \
gnetworkingprivate.h \
gnetworkmonitor.c \
gnetworkmonitorbase.c \
gnetworkmonitorbase.h \
gnetworkservice.c \
goutputstream.c \
gpermission.c \
......@@ -498,6 +508,7 @@ gio_headers = \
gmountoperation.h \
gnativevolumemonitor.h \
gnetworkaddress.h \
gnetworkmonitor.h \
gnetworkservice.h \
goutputstream.h \
gpermission.h \
......
......@@ -92,6 +92,7 @@
#include <gio/gmountoperation.h>
#include <gio/gnativevolumemonitor.h>
#include <gio/gnetworkaddress.h>
#include <gio/gnetworkmonitor.h>
#include <gio/gnetworkservice.h>
#include <gio/goutputstream.h>
#include <gio/gpermission.h>
......
......@@ -1564,3 +1564,13 @@ g_dbus_object_manager_server_set_connection
g_dbus_object_manager_server_get_type
g_dbus_object_manager_server_new
g_dbus_object_manager_server_unexport
g_network_monitor_can_reach
g_network_monitor_can_reach_async
g_network_monitor_can_reach_finish
g_network_monitor_get_default
g_network_monitor_get_network_available
g_network_monitor_get_type
g_network_monitor_base_add_network
g_network_monitor_base_get_type
g_network_monitor_base_remove_network
g_network_monitor_base_set_networks
......@@ -771,6 +771,10 @@ extern GType _g_winhttp_vfs_get_type (void);
extern GType _g_dummy_proxy_resolver_get_type (void);
extern GType _g_dummy_tls_backend_get_type (void);
extern GType g_network_monitor_base_get_type (void);
#ifdef HAVE_NETLINK
extern GType _g_network_monitor_netlink_get_type (void);
#endif
#ifdef G_PLATFORM_WIN32
......@@ -850,6 +854,9 @@ _g_io_modules_ensure_extension_points_registered (void)
ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND);
ep = g_io_extension_point_register (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
g_io_extension_point_set_required_type (ep, G_TYPE_NETWORK_MONITOR);
}
G_UNLOCK (registered_extensions);
......@@ -921,6 +928,10 @@ _g_io_modules_ensure_loaded (void)
_g_socks4_proxy_get_type ();
_g_socks5_proxy_get_type ();
_g_dummy_tls_backend_get_type ();
g_network_monitor_base_get_type ();
#ifdef HAVE_NETLINK
_g_network_monitor_netlink_get_type ();
#endif
}
G_UNLOCK (loaded_dirs);
......
......@@ -123,6 +123,7 @@ typedef struct _GMemoryOutputStream GMemoryOutputStream;
typedef struct _GMount GMount; /* Dummy typedef */
typedef struct _GMountOperation GMountOperation;
typedef struct _GNetworkAddress GNetworkAddress;
typedef struct _GNetworkMonitor GNetworkMonitor;
typedef struct _GNetworkService GNetworkService;
typedef struct _GOutputStream GOutputStream;
typedef struct _GIOStream GIOStream;
......
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "glib.h"
#include "glibintl.h"
#include "gnetworkmonitor.h"
#include "ginetaddress.h"
#include "ginetsocketaddress.h"
#include "ginitable.h"
#include "gioenumtypes.h"
#include "giomodule-priv.h"
#include "gsimpleasyncresult.h"
/**
* SECTION:gnetworkmonitor
* @title: GNetworkMonitor
* @short_description: Network status monitor
* @include: gio/gio.h
*/
/**
* GNetworkMonitor:
*
* #GNetworkMonitor monitors the status of network connections and
* indicates when a possibly-user-visible change has occurred.
*
* Since: 2.32
*/
G_DEFINE_INTERFACE_WITH_CODE (GNetworkMonitor, g_network_monitor, G_TYPE_OBJECT,
g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_INITABLE);)
enum {
NETWORK_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/**
* g_network_monitor_get_default:
*
* Gets the default #GNetworkMonitor for the system.
*
* Returns: (transfer none): a #GNetworkMonitor
*
* Since: 2.32
*/
GNetworkMonitor *
g_network_monitor_get_default (void)
{
return _g_io_module_get_default (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
"GIO_USE_NETWORK_MONITOR",
NULL);
}
/**
* g_network_monitor_get_network_available:
* @monitor: the #GNetworkMonitor
*
* Checks if the network is available. "Available" here means that the
* system has a default route available for at least one of IPv4 or
* IPv6. It does not necessarily imply that the public Internet is
* reachable. See #GNetworkMonitor:network-available for more details.
*
* Return value: whether the network is available
*
* Since: 2.32
*/
gboolean
g_network_monitor_get_network_available (GNetworkMonitor *monitor)
{
gboolean available = FALSE;
g_object_get (G_OBJECT (monitor), "network-available", &available, NULL);
return available;
}
/**
* g_network_monitor_can_reach:
* @monitor: a #GNetworkMonitor
* @connectable: a #GSocketConnectable
* @cancellable: a #GCancellable, or %NULL
* @error: return location for a #GError, or %NULL
*
* Attempts to determine whether or not the host pointed to by
* @connectable can be reached, without actually trying to connect to
* it.
*
* This may return %TRUE even when #GNetworkMonitor:network-available
* is %FALSE, if, for example, @monitor can determine that
* @connectable refers to a host on a local network.
*
* If @monitor believes that an attempt to connect to @connectable
* will succeed, it will return %TRUE. Otherwise, it will return
* %FALSE and set @error to an appropriate error (such as
* %G_IO_ERROR_HOST_UNREACHABLE).
*
* Note that although this does not attempt to connect to
* @connectable, it may still block for a brief period of time (eg,
* trying to do multicast DNS on the local network), so if you do not
* want to block, you should use g_network_monitor_can_reach_async().
*
* Return value: %TRUE if @connectable is reachable, %FALSE if not.
*
* Since: 2.32
*/
gboolean
g_network_monitor_can_reach (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GError **error)
{
GNetworkMonitorInterface *iface;
iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
return iface->can_reach (monitor, connectable, cancellable, error);
}
static void
g_network_monitor_real_can_reach_async (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
GError *error = NULL;
simple = g_simple_async_result_new (G_OBJECT (monitor),
callback, user_data,
g_network_monitor_real_can_reach_async);
if (g_network_monitor_can_reach (monitor, connectable, cancellable, &error))
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
else
g_simple_async_result_take_error (simple, error);
g_simple_async_result_complete_in_idle (simple);
g_object_unref (simple);
}
void
g_network_monitor_can_reach_async (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GNetworkMonitorInterface *iface;
iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
iface->can_reach_async (monitor, connectable, cancellable, callback, user_data);
}
static gboolean
g_network_monitor_real_can_reach_finish (GNetworkMonitor *monitor,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (monitor), g_network_monitor_real_can_reach_async), FALSE);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
else
return g_simple_async_result_get_op_res_gboolean (simple);
}
gboolean
g_network_monitor_can_reach_finish (GNetworkMonitor *monitor,
GAsyncResult *result,
GError **error)
{
GNetworkMonitorInterface *iface;
iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor);
return iface->can_reach_finish (monitor, result, error);
}
static void
g_network_monitor_default_init (GNetworkMonitorInterface *iface)
{
iface->can_reach_async = g_network_monitor_real_can_reach_async;
iface->can_reach_finish = g_network_monitor_real_can_reach_finish;
/**
* GNetworkMonitor::network-changed:
* @monitor: a #GNetworkMonitor
* @available: the current value of #GNetworkMonitor:network-available
*
* Emitted when the network configuration changes. If @available is
* %TRUE, then some hosts may be reachable that were not reachable
* before, while others that were reachable before may no longer be
* reachable. If @available is %FALSE, then no remote hosts are
* reachable.
*
* Since: 2.32
*/
signals[NETWORK_CHANGED] =
g_signal_new (I_("network-changed"),
G_TYPE_NETWORK_MONITOR,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GNetworkMonitorInterface, network_changed),
NULL, NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE, 1,
G_TYPE_BOOLEAN);
/**
* GNetworkMonitor:network-available:
*
* Whether the network is considered available. That is, whether the
* system has a default route for at least one of IPv4 or IPv6.
*
* Real-world networks are of course much more complicated than
* this; the machine may be connected to a wifi hotspot that
* requires payment before allowing traffic through, or may be
* connected to a functioning router that has lost its own upstream
* connectivity. Some hosts might only be accessible when a VPN is
* active. Other hosts might only be accessible when the VPN is
* <emphasis>not</emphasis> active. Thus, it is best to use
* g_network_monitor_can_reach() or
* g_network_monitor_can_reach_async() to test for reachability on a
* host-by-host basis. (On the other hand, when the property is
* %FALSE, the application can reasonably expect that no remote
* hosts at all are reachable, and should indicate this to the user
* in its UI.)
*
* See also #GNetworkMonitor::network-changed.
*
* Since: 2.32
*/
g_object_interface_install_property (iface,
g_param_spec_boolean ("network-available",
P_("Network available"),
P_("Whether the network is available"),
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
#ifndef __G_NETWORK_MONITOR_H__
#define __G_NETWORK_MONITOR_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
/**
* G_NETWORK_MONITOR_EXTENSION_POINT_NAME:
*
* Extension point for network status monitoring functionality.
* See <link linkend="extending-gio">Extending GIO</link>.
*
* Since: 2.30
*/
#define G_NETWORK_MONITOR_EXTENSION_POINT_NAME "gio-network-monitor"
#define G_TYPE_NETWORK_MONITOR (g_network_monitor_get_type ())
#define G_NETWORK_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NETWORK_MONITOR, GNetworkMonitor))
#define G_IS_NETWORK_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_NETWORK_MONITOR))
#define G_NETWORK_MONITOR_GET_INTERFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_NETWORK_MONITOR, GNetworkMonitorInterface))
typedef struct _GNetworkMonitorInterface GNetworkMonitorInterface;
struct _GNetworkMonitorInterface {
GTypeInterface g_iface;
void (*network_changed) (GNetworkMonitor *monitor,
gboolean available);
gboolean (*can_reach) (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GError **error);
void (*can_reach_async) (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (*can_reach_finish) (GNetworkMonitor *monitor,
GAsyncResult *result,
GError **error);
};
GType g_network_monitor_get_type (void) G_GNUC_CONST;
GNetworkMonitor *g_network_monitor_get_default (void);
gboolean g_network_monitor_get_network_available (GNetworkMonitor *monitor);
gboolean g_network_monitor_can_reach (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GError **error);
void g_network_monitor_can_reach_async (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean g_network_monitor_can_reach_finish (GNetworkMonitor *monitor,
GAsyncResult *result,
GError **error);
G_END_DECLS
#endif /* __G_NETWORK_MONITOR_H__ */
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gnetworkmonitorbase.h"
#include "ginetaddress.h"
#include "ginetaddressmask.h"
#include "ginetsocketaddress.h"
#include "ginitable.h"
#include "gioerror.h"
#include "giomodule-priv.h"
#include "gnetworkmonitor.h"
#include "gsocketaddressenumerator.h"
#include "gsocketconnectable.h"
#include "glibintl.h"
static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
static void g_network_monitor_base_initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_network_monitor_base_initable_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
g_network_monitor_base_iface_init)
_g_io_modules_ensure_extension_points_registered ();
g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
g_define_type_id,
"base",
0))
enum
{
PROP_0,
PROP_NETWORK_AVAILABLE
};
struct _GNetworkMonitorBasePrivate
{
GPtrArray *networks;
gboolean have_ipv4_default_route;
gboolean have_ipv6_default_route;
gboolean is_available;
GMainContext *context;
GSource *network_changed_source;
gboolean initializing;
};
static guint network_changed_signal = 0;
static void queue_network_changed (GNetworkMonitorBase *monitor);
static void
g_network_monitor_base_init (GNetworkMonitorBase *monitor)
{
monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
G_TYPE_NETWORK_MONITOR_BASE,
GNetworkMonitorBasePrivate);
monitor->priv->networks = g_ptr_array_new_with_free_func (g_object_unref);
monitor->priv->context = g_main_context_get_thread_default ();
if (monitor->priv->context)
g_main_context_ref (monitor->priv->context);
monitor->priv->initializing = TRUE;
queue_network_changed (monitor);
}
static void
g_network_monitor_base_constructed (GObject *object)
{
GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
{
GInetAddressMask *mask;
/* We're the dumb base class, not a smarter subclass. So just
* assume that the network is available.
*/
mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
g_network_monitor_base_add_network (monitor, mask);
g_object_unref (mask);
mask = g_inet_address_mask_new_from_string ("::/0", NULL);
g_network_monitor_base_add_network (monitor, mask);
g_object_unref (mask);
}
}
static void
g_network_monitor_base_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
switch (prop_id)
{
case PROP_NETWORK_AVAILABLE:
g_value_set_boolean (value, monitor->priv->is_available);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_network_monitor_base_finalize (GObject *object)
{
GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
g_ptr_array_free (monitor->priv->networks, TRUE);
if (monitor->priv->network_changed_source)
{
g_source_destroy (monitor->priv->network_changed_source);
g_source_unref (monitor->priv->network_changed_source);
}
if (monitor->priv->context)
g_main_context_unref (monitor->priv->context);
G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
}
static void
g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);
g_type_class_add_private (monitor_class, sizeof (GNetworkMonitorBasePrivate));
gobject_class->constructed = g_network_monitor_base_constructed;
gobject_class->get_property = g_network_monitor_base_get_property;
gobject_class->finalize = g_network_monitor_base_finalize;
g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
}
static gboolean
g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GError **error)
{
GNetworkMonitorBasePrivate *priv = G_NETWORK_MONITOR_BASE (monitor)->priv;
GSocketAddressEnumerator *enumerator;
GSocketAddress *addr;
if (priv->have_ipv4_default_route &&
priv->have_ipv6_default_route)
return TRUE;
if (priv->networks->len == 0)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
_("Network unreachable"));
return FALSE;
}
enumerator = g_socket_connectable_proxy_enumerate (connectable);
addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
if (!addr)
{
/* Either the user cancelled, or DNS resolution failed */
g_object_unref (enumerator);
return FALSE;
}
while (addr)
{
if (G_IS_INET_SOCKET_ADDRESS (addr))
{
GInetAddress *iaddr;
int i;
iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
for (i = 0; i < priv->networks->len; i++)
{
if (g_inet_address_mask_matches (priv->networks->pdata[i], iaddr))
{
g_object_unref (addr);
g_object_unref (enumerator);
return TRUE;
}
}
}
g_object_unref (addr);
addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
}
g_object_unref (enumerator);
if (error && !*error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
_("Host unreachable"));
}
return FALSE;
}
static void
g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
{
monitor_iface->can_reach = g_network_monitor_base_can_reach;
network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
}
static gboolean
g_network_monitor_base_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
return TRUE;
}
static void
g_network_monitor_base_initable_iface_init (GInitableIface *iface)
{
iface->init = g_network_monitor_base_initable_init;
}
static gboolean
emit_network_changed (gpointer user_data)
{
GNetworkMonitorBase *monitor = user_data;