From 5ed808d7c497d6861c1588911edb1f1b4ff59d96 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 20 Jul 2018 18:53:57 -0400 Subject: [PATCH] network monitor: Update portal implementation The network monitor portal interface is changing. Version 2 is no longer using properties, but getters instead (this lets the portal apply access control and avoid sending information to non-networked sandboxes). To support both version 1 and 2 of the interface, we stop using generated code and instead deal with the api differences in our own code, which is not too difficult. Support version 1 as well --- gio/gnetworkmonitorportal.c | 236 +++++++++++++++--- gio/org.freedesktop.portal.NetworkMonitor.xml | 81 +++++- 2 files changed, 278 insertions(+), 39 deletions(-) diff --git a/gio/gnetworkmonitorportal.c b/gio/gnetworkmonitorportal.c index 856f8aa5b..16249ac55 100644 --- a/gio/gnetworkmonitorportal.c +++ b/gio/gnetworkmonitorportal.c @@ -21,7 +21,6 @@ #include "gnetworkmonitorportal.h" #include "ginitable.h" #include "giomodule-priv.h" -#include "gnetworkmonitor.h" #include "xdp-dbus.h" #include "gportalsupport.h" @@ -39,8 +38,13 @@ enum struct _GNetworkMonitorPortalPrivate { - GXdpNetworkMonitor *proxy; - gboolean network_available; + GDBusProxy *proxy; + gboolean has_network; + int version; + + gboolean available; + gboolean metered; + GNetworkConnectivity connectivity; }; G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorPortal, g_network_monitor_portal, G_TYPE_NETWORK_MONITOR_BASE, @@ -72,22 +76,15 @@ g_network_monitor_portal_get_property (GObject *object, switch (prop_id) { case PROP_NETWORK_AVAILABLE: - g_value_set_boolean (value, - nm->priv->network_available && - gxdp_network_monitor_get_available (nm->priv->proxy)); + g_value_set_boolean (value, nm->priv->available); break; case PROP_NETWORK_METERED: - g_value_set_boolean (value, - nm->priv->network_available && - gxdp_network_monitor_get_metered (nm->priv->proxy)); + g_value_set_boolean (value, nm->priv->metered); break; case PROP_CONNECTIVITY: - g_value_set_enum (value, - nm->priv->network_available - ? gxdp_network_monitor_get_connectivity (nm->priv->proxy) - : G_NETWORK_CONNECTIVITY_LOCAL); + g_value_set_enum (value, nm->priv->connectivity); break; default: @@ -97,22 +94,184 @@ g_network_monitor_portal_get_property (GObject *object, } static void -proxy_changed (GXdpNetworkMonitor *proxy, - gboolean available, - GNetworkMonitorPortal *nm) +got_available (GObject *source, + GAsyncResult *res, + gpointer data) { - if (nm->priv->network_available) - g_signal_emit_by_name (nm, "network-changed", available); + GDBusProxy *proxy = G_DBUS_PROXY (source); + GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (data); + GError *error = NULL; + GVariant *ret; + gboolean available; + + ret = g_dbus_proxy_call_finish (proxy, res, &error); + if (ret == NULL) + { + g_warning ("%s", error->message); + g_clear_error (&error); + return; + } + + g_variant_get (ret, "(b)", &available); + g_variant_unref (ret); + + if (nm->priv->available != available) + { + nm->priv->available = available; + g_object_notify (G_OBJECT (nm), "network-available"); + g_signal_emit_by_name (nm, "network-changed", available); + } } +static void +got_metered (GObject *source, + GAsyncResult *res, + gpointer data) +{ + GDBusProxy *proxy = G_DBUS_PROXY (source); + GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (data); + GError *error = NULL; + GVariant *ret; + gboolean metered; + + ret = g_dbus_proxy_call_finish (proxy, res, &error); + if (ret == NULL) + { + g_warning ("%s", error->message); + g_clear_error (&error); + return; + } + + g_variant_get (ret, "(b)", &metered); + g_variant_unref (ret); + + if (nm->priv->metered != metered) + { + nm->priv->metered = metered; + g_object_notify (G_OBJECT (nm), "network-metered"); + } +} + +static void +got_connectivity (GObject *source, + GAsyncResult *res, + gpointer data) +{ + GDBusProxy *proxy = G_DBUS_PROXY (source); + GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (data); + GError *error = NULL; + GVariant *ret; + GNetworkConnectivity connectivity; + + ret = g_dbus_proxy_call_finish (proxy, res, &error); + if (ret == NULL) + { + g_warning ("%s", error->message); + g_clear_error (&error); + return; + } + + g_variant_get (ret, "(u)", &connectivity); + g_variant_unref (ret); + + if (nm->priv->connectivity != connectivity) + { + nm->priv->connectivity = connectivity; + g_object_notify (G_OBJECT (nm), "connectivity"); + } +} + +static void +proxy_signal (GDBusProxy *proxy, + const char *sender, + const char *signal, + GVariant *parameters, + GNetworkMonitorPortal *nm) +{ + if (!nm->priv->has_network) + return; + + if (nm->priv->version == 1) + { + gboolean available; + + g_variant_get (parameters, "(b)", &available); + g_signal_emit_by_name (nm, "network-changed", available); + } + else if (nm->priv->version == 2) + { + g_dbus_proxy_call (proxy, "GetConnectivity", NULL, 0, -1, NULL, got_connectivity, nm); + g_dbus_proxy_call (proxy, "GetMetered", NULL, 0, -1, NULL, got_metered, nm); + g_dbus_proxy_call (proxy, "GetAvailable", NULL, 0, -1, NULL, got_available, nm); + } +} + +static void +proxy_properties_changed (GDBusProxy *proxy, + GVariant *changed, + GVariant *invalidated, + GNetworkMonitorPortal *nm) +{ + if (!nm->priv->has_network) + return; + + if (nm->priv->version == 1) + { + GVariant *ret; + + ret = g_dbus_proxy_get_cached_property (proxy, "connectivity"); + if (ret) + { + GNetworkConnectivity connectivity = g_variant_get_uint32 (ret); + if (nm->priv->connectivity != connectivity) + { + nm->priv->connectivity = connectivity; + g_object_notify (G_OBJECT (nm), "connectivity"); + } + g_variant_unref (ret); + } + + ret = g_dbus_proxy_get_cached_property (proxy, "metered"); + if (ret) + { + gboolean metered = g_variant_get_boolean (ret); + if (nm->priv->metered != metered) + { + nm->priv->metered = metered; + g_object_notify (G_OBJECT (nm), "network-metered"); + } + g_variant_unref (ret); + } + + ret = g_dbus_proxy_get_cached_property (proxy, "available"); + if (ret) + { + gboolean available = g_variant_get_boolean (ret); + if (nm->priv->available != available) + { + nm->priv->available = available; + g_object_notify (G_OBJECT (nm), "network-available"); + g_signal_emit_by_name (nm, "network-changed", available); + } + g_variant_unref (ret); + } + } +} + static gboolean g_network_monitor_portal_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (initable); - GXdpNetworkMonitor *proxy; + GDBusProxy *proxy; gchar *name_owner = NULL; + int version; + GVariant *ret; + + nm->priv->available = FALSE; + nm->priv->metered = FALSE; + nm->priv->connectivity = G_NETWORK_CONNECTIVITY_LOCAL; if (!glib_should_use_portal ()) { @@ -120,17 +279,19 @@ g_network_monitor_portal_initable_init (GInitable *initable, return FALSE; } - proxy = gxdp_network_monitor_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START - | G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - cancellable, - error); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START + | G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + NULL, + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.NetworkMonitor", + cancellable, + error); if (!proxy) return FALSE; - name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy)); + name_owner = g_dbus_proxy_get_name_owner (proxy); if (!name_owner) { @@ -144,9 +305,26 @@ g_network_monitor_portal_initable_init (GInitable *initable, g_free (name_owner); - g_signal_connect (proxy, "changed", G_CALLBACK (proxy_changed), nm); + ret = g_dbus_proxy_get_cached_property (proxy, "version"); + g_variant_get (ret, "u", &version); + g_variant_unref (ret); + + if (version != 1 && version != 2) + { + g_object_unref (proxy); + g_set_error (error, + G_DBUS_ERROR, + G_DBUS_ERROR_NAME_HAS_NO_OWNER, + "NetworkMonitor portal unsupported version: %d", version); + return FALSE; + } + + g_signal_connect (proxy, "g-signal", G_CALLBACK (proxy_signal), nm); + g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (proxy_properties_changed), nm); + nm->priv->proxy = proxy; - nm->priv->network_available = glib_network_available_in_sandbox (); + nm->priv->has_network = glib_network_available_in_sandbox (); + nm->priv->version = version; return initable_parent_iface->init (initable, cancellable, error); } diff --git a/gio/org.freedesktop.portal.NetworkMonitor.xml b/gio/org.freedesktop.portal.NetworkMonitor.xml index 8d3a471d5..fb551d6ed 100644 --- a/gio/org.freedesktop.portal.NetworkMonitor.xml +++ b/gio/org.freedesktop.portal.NetworkMonitor.xml @@ -5,25 +5,86 @@ 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. + 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, see . + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . Author: Matthias Clasen --> - + + - - - - - - + + + + + + + + + + + + + + +