GNetworkMonitorBase: implement can_reach_async

Implement the g_network_monitor_can_reach_async() rather than falling
back to the default implementation, which calls the sync version (not
in a thread).

https://bugzilla.gnome.org/show_bug.cgi?id=694181
This commit is contained in:
Dan Winship 2013-02-19 16:12:30 -05:00
parent 4ca3d80ff3
commit 9670d06a66

View File

@ -30,6 +30,7 @@
#include "gnetworkmonitor.h" #include "gnetworkmonitor.h"
#include "gsocketaddressenumerator.h" #include "gsocketaddressenumerator.h"
#include "gsocketconnectable.h" #include "gsocketconnectable.h"
#include "gtask.h"
#include "glibintl.h" #include "glibintl.h"
static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface); static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
@ -158,17 +159,37 @@ g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available"); g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
} }
static gboolean
g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
GSocketAddress *sockaddr)
{
GInetAddress *iaddr;
int i;
if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
return FALSE;
iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
for (i = 0; i < base->priv->networks->len; i++)
{
if (g_inet_address_mask_matches (base->priv->networks->pdata[i], iaddr))
return TRUE;
}
return FALSE;
}
static gboolean static gboolean
g_network_monitor_base_can_reach (GNetworkMonitor *monitor, g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
GSocketConnectable *connectable, GSocketConnectable *connectable,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
GNetworkMonitorBasePrivate *priv = G_NETWORK_MONITOR_BASE (monitor)->priv; GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
GSocketAddressEnumerator *enumerator; GSocketAddressEnumerator *enumerator;
GSocketAddress *addr; GSocketAddress *addr;
if (priv->networks->len == 0) if (base->priv->networks->len == 0)
{ {
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE, g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
_("Network unreachable")); _("Network unreachable"));
@ -184,8 +205,8 @@ g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
return FALSE; return FALSE;
} }
if (priv->have_ipv4_default_route && if (base->priv->have_ipv4_default_route &&
priv->have_ipv6_default_route) base->priv->have_ipv6_default_route)
{ {
g_object_unref (enumerator); g_object_unref (enumerator);
g_object_unref (addr); g_object_unref (addr);
@ -194,22 +215,12 @@ g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
while (addr) while (addr)
{ {
if (G_IS_INET_SOCKET_ADDRESS (addr)) if (g_network_monitor_base_can_reach_sockaddr (base, 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 (addr);
g_object_unref (enumerator); g_object_unref (enumerator);
return TRUE; return TRUE;
} }
}
}
g_object_unref (addr); g_object_unref (addr);
addr = g_socket_address_enumerator_next (enumerator, cancellable, error); addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
@ -224,10 +235,93 @@ g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
return FALSE; return FALSE;
} }
static void
can_reach_async_got_address (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object);
GTask *task = user_data;
GNetworkMonitorBase *base = g_task_get_source_object (task);
GSocketAddress *addr;
GError *error = NULL;
addr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
if (!addr)
{
if (error)
{
/* Either the user cancelled, or DNS resolution failed */
g_task_return_error (task, error);
g_object_unref (task);
return;
}
else
{
/* Resolved all addresses, none matched */
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
_("Host unreachable"));
g_object_unref (task);
return;
}
}
if (g_network_monitor_base_can_reach_sockaddr (base, addr))
{
g_object_unref (addr);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
g_object_unref (addr);
g_socket_address_enumerator_next_async (enumerator,
g_task_get_cancellable (task),
can_reach_async_got_address, task);
}
static void
g_network_monitor_base_can_reach_async (GNetworkMonitor *monitor,
GSocketConnectable *connectable,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
GSocketAddressEnumerator *enumerator;
task = g_task_new (monitor, cancellable, callback, user_data);
if (G_NETWORK_MONITOR_BASE (monitor)->priv->networks->len == 0)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
_("Network unreachable"));
g_object_unref (task);
return;
}
enumerator = g_socket_connectable_proxy_enumerate (connectable);
g_socket_address_enumerator_next_async (enumerator, cancellable,
can_reach_async_got_address, task);
g_object_unref (enumerator);
}
static gboolean
g_network_monitor_base_can_reach_finish (GNetworkMonitor *monitor,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
static void static void
g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface) g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
{ {
monitor_iface->can_reach = g_network_monitor_base_can_reach; monitor_iface->can_reach = g_network_monitor_base_can_reach;
monitor_iface->can_reach_async = g_network_monitor_base_can_reach_async;
monitor_iface->can_reach_finish = g_network_monitor_base_can_reach_finish;
network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR); network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
} }