mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-26 20:07:51 +02:00
.gitlab-ci
.reuse
LICENSES
docs
fuzzing
gio
completion
gdbus-2.0
inotify
kqueue
tests
win32
xdgmime
data-to-c.py
dbus-daemon.xml
gaction.c
gaction.h
gactiongroup.c
gactiongroup.h
gactiongroupexporter.c
gactiongroupexporter.h
gactionmap.c
gactionmap.h
gappinfo.c
gappinfo.h
gappinfoprivate.h
gapplication-tool.c
gapplication.c
gapplication.h
gapplicationcommandline.c
gapplicationcommandline.h
gapplicationimpl-dbus.c
gapplicationimpl.h
gasynchelper.c
gasynchelper.h
gasyncinitable.c
gasyncinitable.h
gasyncresult.c
gasyncresult.h
gbufferedinputstream.c
gbufferedinputstream.h
gbufferedoutputstream.c
gbufferedoutputstream.h
gbytesicon.c
gbytesicon.h
gcancellable.c
gcancellable.h
gcharsetconverter.c
gcharsetconverter.h
gcocoanotificationbackend.m
gcontenttype-win32.c
gcontenttype.c
gcontenttype.h
gcontenttypeprivate.h
gcontextspecificgroup.c
gcontextspecificgroup.h
gconverter.c
gconverter.h
gconverterinputstream.c
gconverterinputstream.h
gconverteroutputstream.c
gconverteroutputstream.h
gcredentials.c
gcredentials.h
gcredentialsprivate.h
gdatagrambased.c
gdatagrambased.h
gdatainputstream.c
gdatainputstream.h
gdataoutputstream.c
gdataoutputstream.h
gdbus-tool.c
gdbusactiongroup-private.h
gdbusactiongroup.c
gdbusactiongroup.h
gdbusaddress.c
gdbusaddress.h
gdbusauth.c
gdbusauth.h
gdbusauthmechanism.c
gdbusauthmechanism.h
gdbusauthmechanismanon.c
gdbusauthmechanismanon.h
gdbusauthmechanismexternal.c
gdbusauthmechanismexternal.h
gdbusauthmechanismsha1.c
gdbusauthmechanismsha1.h
gdbusauthobserver.c
gdbusauthobserver.h
gdbusconnection.c
gdbusconnection.h
gdbusdaemon.c
gdbusdaemon.h
gdbuserror.c
gdbuserror.h
gdbusinterface.c
gdbusinterface.h
gdbusinterfaceskeleton.c
gdbusinterfaceskeleton.h
gdbusintrospection.c
gdbusintrospection.h
gdbusmenumodel.c
gdbusmenumodel.h
gdbusmessage.c
gdbusmessage.h
gdbusmethodinvocation.c
gdbusmethodinvocation.h
gdbusnameowning.c
gdbusnameowning.h
gdbusnamewatching.c
gdbusnamewatching.h
gdbusobject.c
gdbusobject.h
gdbusobjectmanager.c
gdbusobjectmanager.h
gdbusobjectmanagerclient.c
gdbusobjectmanagerclient.h
gdbusobjectmanagerserver.c
gdbusobjectmanagerserver.h
gdbusobjectproxy.c
gdbusobjectproxy.h
gdbusobjectskeleton.c
gdbusobjectskeleton.h
gdbusprivate.c
gdbusprivate.h
gdbusproxy.c
gdbusproxy.h
gdbusserver.c
gdbusserver.h
gdbusutils.c
gdbusutils.h
gdebugcontroller.c
gdebugcontroller.h
gdebugcontrollerdbus.c
gdebugcontrollerdbus.h
gdelayedsettingsbackend.c
gdelayedsettingsbackend.h
gdesktopappinfo.c
gdesktopappinfo.h
gdocumentportal.c
gdocumentportal.h
gdrive.c
gdrive.h
gdtlsclientconnection.c
gdtlsclientconnection.h
gdtlsconnection.c
gdtlsconnection.h
gdtlsserverconnection.c
gdtlsserverconnection.h
gdummyfile.c
gdummyfile.h
gdummyproxyresolver.c
gdummyproxyresolver.h
gdummytlsbackend.c
gdummytlsbackend.h
gemblem.c
gemblem.h
gemblemedicon.c
gemblemedicon.h
gfdonotificationbackend.c
gfile.c
gfile.h
gfileattribute-priv.h
gfileattribute.c
gfileattribute.h
gfiledescriptorbased.c
gfiledescriptorbased.h
gfileenumerator.c
gfileenumerator.h
gfileicon.c
gfileicon.h
gfileinfo-priv.h
gfileinfo.c
gfileinfo.h
gfileinputstream.c
gfileinputstream.h
gfileiostream.c
gfileiostream.h
gfilemonitor.c
gfilemonitor.h
gfilenamecompleter.c
gfilenamecompleter.h
gfileoutputstream.c
gfileoutputstream.h
gfilterinputstream.c
gfilterinputstream.h
gfilteroutputstream.c
gfilteroutputstream.h
ggtknotificationbackend.c
ghttpproxy.c
ghttpproxy.h
gicon.c
gicon.h
ginetaddress.c
ginetaddress.h
ginetaddressmask.c
ginetaddressmask.h
ginetsocketaddress.c
ginetsocketaddress.h
ginitable.c
ginitable.h
ginputstream.c
ginputstream.h
gio-autocleanups.h
gio-launch-desktop.c
gio-querymodules.c
gio-tool-cat.c
gio-tool-copy.c
gio-tool-info.c
gio-tool-launch.c
gio-tool-list.c
gio-tool-mime.c
gio-tool-mkdir.c
gio-tool-monitor.c
gio-tool-mount.c
gio-tool-move.c
gio-tool-open.c
gio-tool-remove.c
gio-tool-rename.c
gio-tool-save.c
gio-tool-set.c
gio-tool-trash.c
gio-tool-tree.c
gio-tool.c
gio-tool.h
gio.h
gio.rc.in
gio.stp.in
gio_probes.d
gio_trace.h
gioenums.h
gioenumtypes.c.template
gioenumtypes.h.template
gioerror.c
gioerror.h
giomodule-priv.c
giomodule-priv.h
giomodule.c
giomodule.h
gioprivate.h
gioscheduler.c
gioscheduler.h
giostream.c
giostream.h
giotypes.h
giounix-private.c
giounix-private.h
giowin32-afunix.h
giowin32-priv.h
giowin32-private.c
gkeyfilesettingsbackend.c
glib-compile-resources.c
glib-compile-schemas.c
glistmodel.c
glistmodel.h
gliststore.c
gliststore.h
gloadableicon.c
gloadableicon.h
glocalfile.c
glocalfile.h
glocalfileenumerator.c
glocalfileenumerator.h
glocalfileinfo.c
glocalfileinfo.h
glocalfileinputstream.c
glocalfileinputstream.h
glocalfileiostream.c
glocalfileiostream.h
glocalfilemonitor.c
glocalfilemonitor.h
glocalfileoutputstream.c
glocalfileoutputstream.h
glocalvfs.c
glocalvfs.h
gmarshal-internal.c
gmarshal-internal.h
gmarshal-internal.list
gmemoryinputstream.c
gmemoryinputstream.h
gmemorymonitor.c
gmemorymonitor.h
gmemorymonitordbus.c
gmemorymonitordbus.h
gmemorymonitorportal.c
gmemorymonitorportal.h
gmemorymonitorwin32.c
gmemoryoutputstream.c
gmemoryoutputstream.h
gmemorysettingsbackend.c
gmenu.c
gmenu.h
gmenuexporter.c
gmenuexporter.h
gmenumodel.c
gmenumodel.h
gmount.c
gmount.h
gmountoperation.c
gmountoperation.h
gmountprivate.h
gnativesocketaddress.c
gnativesocketaddress.h
gnativevolumemonitor.c
gnativevolumemonitor.h
gnetworkaddress.c
gnetworkaddress.h
gnetworking.c
gnetworking.h.in
gnetworkingprivate.h
gnetworkmonitor.c
gnetworkmonitor.h
gnetworkmonitorbase.c
gnetworkmonitorbase.h
gnetworkmonitornetlink.c
gnetworkmonitornetlink.h
gnetworkmonitornm.c
gnetworkmonitornm.h
gnetworkmonitorportal.c
gnetworkmonitorportal.h
gnetworkservice.c
gnetworkservice.h
gnextstepsettingsbackend.m
gnotification-private.h
gnotification.c
gnotification.h
gnotificationbackend.c
gnotificationbackend.h
gnullsettingsbackend.c
gopenuriportal.c
gopenuriportal.h
gosxappinfo.h
gosxappinfo.m
gosxcontenttype.m
goutputstream.c
goutputstream.h
gpermission.c
gpermission.h
gpollableinputstream.c
gpollableinputstream.h
gpollableoutputstream.c
gpollableoutputstream.h
gpollableutils.c
gpollableutils.h
gpollfilemonitor.c
gpollfilemonitor.h
gportalnotificationbackend.c
gportalsupport.c
gportalsupport.h
gpowerprofilemonitor.c
gpowerprofilemonitor.h
gpowerprofilemonitordbus.c
gpowerprofilemonitordbus.h
gpowerprofilemonitorportal.c
gpowerprofilemonitorportal.h
gpropertyaction.c
gpropertyaction.h
gproxy.c
gproxy.h
gproxyaddress.c
gproxyaddress.h
gproxyaddressenumerator.c
gproxyaddressenumerator.h
gproxyresolver.c
gproxyresolver.h
gproxyresolverportal.c
gproxyresolverportal.h
gregistrysettingsbackend.c
gregistrysettingsbackend.h
gremoteactiongroup.c
gremoteactiongroup.h
gresolver.c
gresolver.h
gresource-tool.c
gresource.c
gresource.dtd
gresource.h
gresourcefile.c
gresourcefile.h
gsandbox.c
gsandbox.h
gschema.dtd
gschema.its
gschema.loc
gseekable.c
gseekable.h
gsettings-mapping.c
gsettings-mapping.h
gsettings-tool.c
gsettings.c
gsettings.h
gsettingsbackend.c
gsettingsbackend.h
gsettingsbackendinternal.h
gsettingsschema-internal.h
gsettingsschema.c
gsettingsschema.h
gsimpleaction.c
gsimpleaction.h
gsimpleactiongroup.c
gsimpleactiongroup.h
gsimpleasyncresult.c
gsimpleasyncresult.h
gsimpleiostream.c
gsimpleiostream.h
gsimplepermission.c
gsimplepermission.h
gsimpleproxyresolver.c
gsimpleproxyresolver.h
gsocket.c
gsocket.h
gsocketaddress.c
gsocketaddress.h
gsocketaddressenumerator.c
gsocketaddressenumerator.h
gsocketclient.c
gsocketclient.h
gsocketconnectable.c
gsocketconnectable.h
gsocketconnection.c
gsocketconnection.h
gsocketcontrolmessage.c
gsocketcontrolmessage.h
gsocketinputstream.c
gsocketinputstream.h
gsocketlistener.c
gsocketlistener.h
gsocketoutputstream.c
gsocketoutputstream.h
gsocketservice.c
gsocketservice.h
gsocks4aproxy.c
gsocks4aproxy.h
gsocks4proxy.c
gsocks4proxy.h
gsocks5proxy.c
gsocks5proxy.h
gsrvtarget.c
gsrvtarget.h
gsubprocess.c
gsubprocess.h
gsubprocesslauncher-private.h
gsubprocesslauncher.c
gsubprocesslauncher.h
gtask.c
gtask.h
gtcpconnection.c
gtcpconnection.h
gtcpwrapperconnection.c
gtcpwrapperconnection.h
gtestdbus.c
gtestdbus.h
gthemedicon.c
gthemedicon.h
gthreadedresolver.c
gthreadedresolver.h
gthreadedsocketservice.c
gthreadedsocketservice.h
gtlsbackend.c
gtlsbackend.h
gtlscertificate.c
gtlscertificate.h
gtlsclientconnection.c
gtlsclientconnection.h
gtlsconnection.c
gtlsconnection.h
gtlsdatabase.c
gtlsdatabase.h
gtlsfiledatabase.c
gtlsfiledatabase.h
gtlsinteraction.c
gtlsinteraction.h
gtlspassword.c
gtlspassword.h
gtlsserverconnection.c
gtlsserverconnection.h
gtrashportal.c
gtrashportal.h
gunionvolumemonitor.c
gunionvolumemonitor.h
gunixconnection.c
gunixconnection.h
gunixcredentialsmessage.c
gunixcredentialsmessage.h
gunixfdlist.c
gunixfdlist.h
gunixfdmessage.c
gunixfdmessage.h
gunixinputstream.c
gunixinputstream.h
gunixmount.c
gunixmount.h
gunixmounts.c
gunixmounts.h
gunixoutputstream.c
gunixoutputstream.h
gunixsocketaddress.c
gunixsocketaddress.h
gunixvolume.c
gunixvolume.h
gunixvolumemonitor.c
gunixvolumemonitor.h
gvfs.c
gvfs.h
gvolume.c
gvolume.h
gvolumemonitor.c
gvolumemonitor.h
gwin32api-application-activation-manager.h
gwin32api-iterator.h
gwin32api-misc.h
gwin32api-package.h
gwin32api-storage.h
gwin32appinfo.c
gwin32appinfo.h
gwin32file-sync-stream.c
gwin32file-sync-stream.h
gwin32inputstream.c
gwin32inputstream.h
gwin32mount.c
gwin32mount.h
gwin32networkmonitor.c
gwin32networkmonitor.h
gwin32notificationbackend.c
gwin32outputstream.c
gwin32outputstream.h
gwin32packageparser.c
gwin32packageparser.h
gwin32registrykey.c
gwin32registrykey.h
gwin32sid.c
gwin32sid.h
gwin32volumemonitor.c
gwin32volumemonitor.h
gzlibcompressor.c
gzlibcompressor.h
gzlibdecompressor.c
gzlibdecompressor.h
meson.build
org.freedesktop.portal.Documents.xml
org.freedesktop.portal.OpenURI.xml
org.freedesktop.portal.ProxyResolver.xml
org.freedesktop.portal.Trash.xml
strinfo.c
thumbnail-verify.c
thumbnail-verify.h
girepository
glib
gmodule
gobject
gthread
m4macros
po
subprojects
tests
tools
.clang-format
.dir-locals.el
.editorconfig
.gitignore
.gitlab-ci.yml
.gitmodules
.lcovrc
CODE_OF_CONDUCT.md
CONTRIBUTING.md
COPYING
INSTALL.md
NEWS
README.md
SECURITY.md
glib.doap
meson.build
meson_options.txt
Add SPDX license (but not copyright) headers to all files which follow a certain pattern in their existing non-machine-readable header comment. This commit was entirely generated using the command: ``` git ls-files gio/*.[ch] | xargs perl -0777 -pi -e 's/\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/\n \*\n \* SPDX-License-Identifier: LGPL-2.1-or-later\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/igs' ``` Signed-off-by: Philip Withnall <pwithnall@endlessos.org> Helps: #1415
586 lines
18 KiB
C
586 lines
18 KiB
C
/* GIO - GLib Input, Output and Streaming Library
|
||
*
|
||
* Copyright 2011 Red Hat, Inc.
|
||
*
|
||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||
*
|
||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#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 "gtask.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);
|
||
|
||
enum
|
||
{
|
||
PROP_0,
|
||
|
||
PROP_NETWORK_AVAILABLE,
|
||
PROP_NETWORK_METERED,
|
||
PROP_CONNECTIVITY
|
||
};
|
||
|
||
struct _GNetworkMonitorBasePrivate
|
||
{
|
||
GHashTable *networks /* (element-type GInetAddressMask) (owned) */;
|
||
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 guint inet_address_mask_hash (gconstpointer key);
|
||
static gboolean inet_address_mask_equal (gconstpointer a,
|
||
gconstpointer b);
|
||
|
||
G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
|
||
G_ADD_PRIVATE (GNetworkMonitorBase)
|
||
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))
|
||
|
||
static void
|
||
g_network_monitor_base_init (GNetworkMonitorBase *monitor)
|
||
{
|
||
monitor->priv = g_network_monitor_base_get_instance_private (monitor);
|
||
monitor->priv->networks = g_hash_table_new_full (inet_address_mask_hash,
|
||
inet_address_mask_equal,
|
||
g_object_unref, NULL);
|
||
monitor->priv->context = g_main_context_get_thread_default ();
|
||
if (monitor->priv->context)
|
||
g_main_context_ref (monitor->priv->context);
|
||
|
||
monitor->priv->initializing = TRUE;
|
||
}
|
||
|
||
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);
|
||
if (mask)
|
||
{
|
||
/* On some environments (for example Windows without IPv6 support
|
||
* enabled) the string "::/0" can't be processed and causes
|
||
* g_inet_address_mask_new_from_string to return 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;
|
||
|
||
case PROP_NETWORK_METERED:
|
||
/* Default to FALSE in the unknown case. */
|
||
g_value_set_boolean (value, FALSE);
|
||
break;
|
||
|
||
case PROP_CONNECTIVITY:
|
||
g_value_set_enum (value,
|
||
monitor->priv->is_available ?
|
||
G_NETWORK_CONNECTIVITY_FULL :
|
||
G_NETWORK_CONNECTIVITY_LOCAL);
|
||
break;
|
||
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
static void
|
||
g_network_monitor_base_finalize (GObject *object)
|
||
{
|
||
GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);
|
||
|
||
g_hash_table_unref (monitor->priv->networks);
|
||
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);
|
||
|
||
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");
|
||
g_object_class_override_property (gobject_class, PROP_NETWORK_METERED, "network-metered");
|
||
g_object_class_override_property (gobject_class, PROP_CONNECTIVITY, "connectivity");
|
||
}
|
||
|
||
static gboolean
|
||
g_network_monitor_base_can_reach_sockaddr (GNetworkMonitorBase *base,
|
||
GSocketAddress *sockaddr)
|
||
{
|
||
GInetAddress *iaddr;
|
||
GHashTableIter iter;
|
||
gpointer key;
|
||
|
||
if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
|
||
return FALSE;
|
||
|
||
iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sockaddr));
|
||
g_hash_table_iter_init (&iter, base->priv->networks);
|
||
while (g_hash_table_iter_next (&iter, &key, NULL))
|
||
{
|
||
GInetAddressMask *mask = key;
|
||
if (g_inet_address_mask_matches (mask, iaddr))
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
g_network_monitor_base_can_reach (GNetworkMonitor *monitor,
|
||
GSocketConnectable *connectable,
|
||
GCancellable *cancellable,
|
||
GError **error)
|
||
{
|
||
GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (monitor);
|
||
GSocketAddressEnumerator *enumerator;
|
||
GSocketAddress *addr;
|
||
|
||
if (g_hash_table_size (base->priv->networks) == 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;
|
||
}
|
||
|
||
if (base->priv->have_ipv4_default_route &&
|
||
base->priv->have_ipv6_default_route)
|
||
{
|
||
g_object_unref (enumerator);
|
||
g_object_unref (addr);
|
||
return TRUE;
|
||
}
|
||
|
||
while (addr)
|
||
{
|
||
if (g_network_monitor_base_can_reach_sockaddr (base, addr))
|
||
{
|
||
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
|
||
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);
|
||
g_task_set_source_tag (task, g_network_monitor_base_can_reach_async);
|
||
|
||
if (g_hash_table_size (G_NETWORK_MONITOR_BASE (monitor)->priv->networks) == 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
|
||
g_network_monitor_base_iface_init (GNetworkMonitorInterface *monitor_iface)
|
||
{
|
||
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);
|
||
}
|
||
|
||
static gboolean
|
||
g_network_monitor_base_initable_init (GInitable *initable,
|
||
GCancellable *cancellable,
|
||
GError **error)
|
||
{
|
||
GNetworkMonitorBase *base = G_NETWORK_MONITOR_BASE (initable);
|
||
|
||
base->priv->initializing = FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
g_network_monitor_base_initable_iface_init (GInitableIface *iface)
|
||
{
|
||
iface->init = g_network_monitor_base_initable_init;
|
||
}
|
||
|
||
static guint
|
||
inet_address_mask_hash (gconstpointer key)
|
||
{
|
||
GInetAddressMask *mask = G_INET_ADDRESS_MASK (key);
|
||
guint addr_hash;
|
||
guint mask_length = g_inet_address_mask_get_length (mask);
|
||
GInetAddress *addr = g_inet_address_mask_get_address (mask);
|
||
const guint8 *bytes = g_inet_address_to_bytes (addr);
|
||
gsize bytes_length = g_inet_address_get_native_size (addr);
|
||
|
||
union
|
||
{
|
||
const guint8 *bytes;
|
||
guint32 *hash32;
|
||
guint64 *hash64;
|
||
} integerifier;
|
||
|
||
/* If we can fit the entire address into the hash key, do it. Don’t worry
|
||
* about endianness; the address should always be in network endianness. */
|
||
if (bytes_length == sizeof (guint32))
|
||
{
|
||
integerifier.bytes = bytes;
|
||
addr_hash = *integerifier.hash32;
|
||
}
|
||
else if (bytes_length == sizeof (guint64))
|
||
{
|
||
integerifier.bytes = bytes;
|
||
addr_hash = *integerifier.hash64;
|
||
}
|
||
else
|
||
{
|
||
gsize i;
|
||
|
||
/* Otherwise, fall back to adding the bytes together. We do this, rather
|
||
* than XORing them, as routes often have repeated tuples which would
|
||
* cancel out under XOR. */
|
||
addr_hash = 0;
|
||
for (i = 0; i < bytes_length; i++)
|
||
addr_hash += bytes[i];
|
||
}
|
||
|
||
return addr_hash + mask_length;;
|
||
}
|
||
|
||
static gboolean
|
||
inet_address_mask_equal (gconstpointer a,
|
||
gconstpointer b)
|
||
{
|
||
GInetAddressMask *mask_a = G_INET_ADDRESS_MASK (a);
|
||
GInetAddressMask *mask_b = G_INET_ADDRESS_MASK (b);
|
||
|
||
return g_inet_address_mask_equal (mask_a, mask_b);
|
||
}
|
||
|
||
static gboolean
|
||
emit_network_changed (gpointer user_data)
|
||
{
|
||
GNetworkMonitorBase *monitor = user_data;
|
||
gboolean is_available;
|
||
|
||
if (g_source_is_destroyed (g_main_current_source ()))
|
||
return FALSE;
|
||
|
||
g_object_ref (monitor);
|
||
|
||
is_available = (monitor->priv->have_ipv4_default_route ||
|
||
monitor->priv->have_ipv6_default_route);
|
||
if (monitor->priv->is_available != is_available)
|
||
{
|
||
monitor->priv->is_available = is_available;
|
||
g_object_notify (G_OBJECT (monitor), "network-available");
|
||
}
|
||
|
||
g_signal_emit (monitor, network_changed_signal, 0, is_available);
|
||
|
||
g_source_unref (monitor->priv->network_changed_source);
|
||
monitor->priv->network_changed_source = NULL;
|
||
|
||
g_object_unref (monitor);
|
||
return FALSE;
|
||
}
|
||
|
||
static void
|
||
queue_network_changed (GNetworkMonitorBase *monitor)
|
||
{
|
||
if (!monitor->priv->network_changed_source &&
|
||
!monitor->priv->initializing)
|
||
{
|
||
GSource *source;
|
||
|
||
source = g_idle_source_new ();
|
||
/* Use G_PRIORITY_HIGH_IDLE priority so that multiple
|
||
* network-change-related notifications coming in at
|
||
* G_PRIORITY_DEFAULT will get coalesced into one signal
|
||
* emission.
|
||
*/
|
||
g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
|
||
g_source_set_callback (source, emit_network_changed, monitor, NULL);
|
||
g_source_set_static_name (source, "[gio] emit_network_changed");
|
||
g_source_attach (source, monitor->priv->context);
|
||
monitor->priv->network_changed_source = source;
|
||
}
|
||
|
||
/* Normally we wait to update is_available until we emit the signal,
|
||
* to keep things consistent. But when we're first creating the
|
||
* object, we want it to be correct right away.
|
||
*/
|
||
if (monitor->priv->initializing)
|
||
{
|
||
monitor->priv->is_available = (monitor->priv->have_ipv4_default_route ||
|
||
monitor->priv->have_ipv6_default_route);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* g_network_monitor_base_add_network:
|
||
* @monitor: the #GNetworkMonitorBase
|
||
* @network: (transfer none): a #GInetAddressMask
|
||
*
|
||
* Adds @network to @monitor's list of available networks.
|
||
*
|
||
* Since: 2.32
|
||
*/
|
||
void
|
||
g_network_monitor_base_add_network (GNetworkMonitorBase *monitor,
|
||
GInetAddressMask *network)
|
||
{
|
||
if (!g_hash_table_add (monitor->priv->networks, g_object_ref (network)))
|
||
return;
|
||
|
||
if (g_inet_address_mask_get_length (network) == 0)
|
||
{
|
||
switch (g_inet_address_mask_get_family (network))
|
||
{
|
||
case G_SOCKET_FAMILY_IPV4:
|
||
monitor->priv->have_ipv4_default_route = TRUE;
|
||
break;
|
||
case G_SOCKET_FAMILY_IPV6:
|
||
monitor->priv->have_ipv6_default_route = TRUE;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Don't emit network-changed when multicast-link-local routing
|
||
* changes. This rather arbitrary decision is mostly because it
|
||
* seems to change quite often...
|
||
*/
|
||
if (g_inet_address_get_is_mc_link_local (g_inet_address_mask_get_address (network)))
|
||
return;
|
||
|
||
queue_network_changed (monitor);
|
||
}
|
||
|
||
/**
|
||
* g_network_monitor_base_remove_network:
|
||
* @monitor: the #GNetworkMonitorBase
|
||
* @network: a #GInetAddressMask
|
||
*
|
||
* Removes @network from @monitor's list of available networks.
|
||
*
|
||
* Since: 2.32
|
||
*/
|
||
void
|
||
g_network_monitor_base_remove_network (GNetworkMonitorBase *monitor,
|
||
GInetAddressMask *network)
|
||
{
|
||
if (!g_hash_table_remove (monitor->priv->networks, network))
|
||
return;
|
||
|
||
if (g_inet_address_mask_get_length (network) == 0)
|
||
{
|
||
switch (g_inet_address_mask_get_family (network))
|
||
{
|
||
case G_SOCKET_FAMILY_IPV4:
|
||
monitor->priv->have_ipv4_default_route = FALSE;
|
||
break;
|
||
case G_SOCKET_FAMILY_IPV6:
|
||
monitor->priv->have_ipv6_default_route = FALSE;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
queue_network_changed (monitor);
|
||
}
|
||
|
||
/**
|
||
* g_network_monitor_base_set_networks:
|
||
* @monitor: the #GNetworkMonitorBase
|
||
* @networks: (array length=length): an array of #GInetAddressMask
|
||
* @length: length of @networks
|
||
*
|
||
* Drops @monitor's current list of available networks and replaces
|
||
* it with @networks.
|
||
*/
|
||
void
|
||
g_network_monitor_base_set_networks (GNetworkMonitorBase *monitor,
|
||
GInetAddressMask **networks,
|
||
gint length)
|
||
{
|
||
int i;
|
||
|
||
g_hash_table_remove_all (monitor->priv->networks);
|
||
monitor->priv->have_ipv4_default_route = FALSE;
|
||
monitor->priv->have_ipv6_default_route = FALSE;
|
||
|
||
for (i = 0; i < length; i++)
|
||
g_network_monitor_base_add_network (monitor, networks[i]);
|
||
}
|