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
This commit is contained in:
Matthias Clasen 2018-07-20 18:53:57 -04:00
parent e0b120cc3c
commit 5ed808d7c4
2 changed files with 278 additions and 39 deletions

View File

@ -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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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/>.
Author: Matthias Clasen <mclasen@redhat.com>
-->
<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd" name="/">
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<!--
org.freedesktop.portal.NetworkMonitor:
@short_description: Network monitoring portal
The NetworkMonitor interface provides network status information
to sandboxed applications. It is not a portal in the strict sense,
since it does not involve user interaction. Applications are
expected to use this interface indirectly, via a library API
such as the GLib GNetworkMonitor interface.
This documentation describes version 2 of this interface.
-->
<interface name="org.freedesktop.portal.NetworkMonitor">
<signal name="changed">
<arg type="b" name="available"/>
</signal>
<property name="available" type="b" access="read"/>
<property name="metered" type="b" access="read"/>
<property name="connectivity" type="u" access="read"/>
<!--
changed:
Emitted when the network configuration changes.
-->
<signal name="changed"/>
<!--
GetAvailable:
@available: whether the network is available
Returns whether the network is considered available.
That is, whether the system as a default route for
at least one of IPv4 or IPv6.
This method was added in version 2 to replace
the available property.
-->
<method name="GetAvailable">
<arg type='b' name='available' direction='out'/>
</method>
<!--
GetMetered:
@metered: whether the network is metered
Returns whether the network is considered metered.
That is, whether the system as traffic flowing through
the default connection that is subject ot limitations
by service providers.
This method was added in version 2 to replace
the metered property.
-->
<method name="GetMetered">
<arg type='b' name='metered' direction='out'/>
</method>
<!--
GetConnectivity:
@connectivity: the level of connectivity
Returs more detailed information about the host's network
connectivity. The meaning of the value is:
<simplelist>
<member>1: Local only. The host is not configured with a route to the internet.</member>
<member>2: Limited connectivity. The host is connected to a network, but can't reach the full internet.</member>
<member>3: Captive portal. The host is behind a captive portal and cannot reach the full internet.</member>
<member>4: Full network. The host connected to a network, and can reach the full internet.</member>
</simplelist>
This method was added in version 2 to replace
the connectivity property.
-->
<method name="GetConnectivity">
<arg type='u' name='connectivity' direction='out'/>
</method>
<property name="version" type="u" access="read"/>
</interface>
</node>