glib/gio/gnetworkmonitornm.c
Iain Lane f7be461601 gnetworkmonitornm: Check if network-manager is running
We were asking for properties on NM's dbus interface, but if NM is not
running then there won't be any. Check if the name has an owner before
doing anything to it.

https://bugzilla.gnome.org/show_bug.cgi?id=741653
2015-01-13 12:11:06 +01:00

323 lines
9.0 KiB
C

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2014 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "gnetworkmonitornm.h"
#include "gioerror.h"
#include "ginitable.h"
#include "giomodule-priv.h"
#include "glibintl.h"
#include "glib/gstdio.h"
#include "gnetworkingprivate.h"
#include "gnetworkmonitor.h"
#include "gdbusproxy.h"
static void g_network_monitor_nm_iface_init (GNetworkMonitorInterface *iface);
static void g_network_monitor_nm_initable_iface_init (GInitableIface *iface);
enum
{
PROP_0,
PROP_NETWORK_AVAILABLE,
PROP_CONNECTIVITY
};
typedef enum {
NM_CONNECTIVITY_UNKNOWN,
NM_CONNECTIVITY_NONE,
NM_CONNECTIVITY_PORTAL,
NM_CONNECTIVITY_LIMITED,
NM_CONNECTIVITY_FULL
} NMConnectivityState;
struct _GNetworkMonitorNMPrivate
{
GDBusProxy *proxy;
GNetworkConnectivity connectivity;
gboolean network_available;
};
#define g_network_monitor_nm_get_type _g_network_monitor_nm_get_type
G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorNM, g_network_monitor_nm, G_TYPE_NETWORK_MONITOR_NETLINK,
G_ADD_PRIVATE (GNetworkMonitorNM)
G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
g_network_monitor_nm_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_network_monitor_nm_initable_iface_init)
_g_io_modules_ensure_extension_points_registered ();
g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
g_define_type_id,
"networkmanager",
30))
static void
g_network_monitor_nm_init (GNetworkMonitorNM *nm)
{
nm->priv = g_network_monitor_nm_get_instance_private (nm);
}
static void
g_network_monitor_nm_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GNetworkMonitorNM *nm = G_NETWORK_MONITOR_NM (object);
switch (prop_id)
{
case PROP_NETWORK_AVAILABLE:
g_value_set_boolean (value, nm->priv->network_available);
break;
case PROP_CONNECTIVITY:
g_value_set_enum (value, nm->priv->connectivity);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GNetworkConnectivity
nm_conn_to_g_conn (int nm_state)
{
switch (nm_state)
{
case NM_CONNECTIVITY_UNKNOWN:
return G_NETWORK_CONNECTIVITY_LOCAL;
case NM_CONNECTIVITY_NONE:
return G_NETWORK_CONNECTIVITY_LOCAL;
case NM_CONNECTIVITY_PORTAL:
return G_NETWORK_CONNECTIVITY_PORTAL;
case NM_CONNECTIVITY_LIMITED:
return G_NETWORK_CONNECTIVITY_LIMITED;
case NM_CONNECTIVITY_FULL:
return G_NETWORK_CONNECTIVITY_FULL;
default:
g_warning ("Unknown NM connectivity state %d", nm_state);
return G_NETWORK_CONNECTIVITY_LOCAL;
}
}
static void
sync_properties (GNetworkMonitorNM *nm,
gboolean emit_signals)
{
GVariant *v;
NMConnectivityState nm_connectivity;
gboolean new_network_available;
GNetworkConnectivity new_connectivity;
v = g_dbus_proxy_get_cached_property (nm->priv->proxy, "Connectivity");
nm_connectivity = g_variant_get_uint32 (v);
g_variant_unref (v);
if (nm_connectivity == NM_CONNECTIVITY_NONE)
{
new_network_available = FALSE;
new_connectivity = G_NETWORK_CONNECTIVITY_LOCAL;
}
else
{
new_network_available = TRUE;
new_connectivity = nm_conn_to_g_conn (nm_connectivity);
}
if (!emit_signals)
{
nm->priv->network_available = new_network_available;
nm->priv->connectivity = new_connectivity;
return;
}
if (new_network_available != nm->priv->network_available)
{
nm->priv->network_available = new_network_available;
g_object_notify (G_OBJECT (nm), "network-available");
}
if (new_connectivity != nm->priv->connectivity)
{
nm->priv->connectivity = new_connectivity;
g_object_notify (G_OBJECT (nm), "connectivity");
}
}
static void
update_cached_property (GDBusProxy *proxy,
const char *property_name,
GVariantDict *dict)
{
GVariant *v;
v = g_variant_dict_lookup_value (dict, property_name, NULL);
if (!v)
return;
g_dbus_proxy_set_cached_property (proxy, property_name, v);
}
static void
proxy_signal_cb (GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GVariant *parameters,
GNetworkMonitorNM *nm)
{
GVariant *asv;
GVariantDict *dict;
if (g_strcmp0 (signal_name, "PropertiesChanged") != 0)
return;
g_variant_get (parameters, "(@a{sv})", &asv);
if (!asv)
return;
dict = g_variant_dict_new (asv);
if (!dict)
{
g_warning ("Failed to handle PropertiesChanged signal from NetworkManager");
return;
}
update_cached_property (nm->priv->proxy, "Connectivity", dict);
g_variant_dict_unref (dict);
sync_properties (nm, TRUE);
}
static gboolean
has_property (GDBusProxy *proxy,
const char *property_name)
{
char **props;
guint i;
gboolean prop_found = FALSE;
props = g_dbus_proxy_get_cached_property_names (proxy);
if (!props)
return FALSE;
for (i = 0; props[i] != NULL; i++)
{
if (g_str_equal (props[i], property_name))
{
prop_found = TRUE;
break;
}
}
g_strfreev (props);
return prop_found;
}
static gboolean
g_network_monitor_nm_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
GNetworkMonitorNM *nm = G_NETWORK_MONITOR_NM (initable);
GDBusProxy *proxy;
GInitableIface *parent_iface;
gchar *name_owner = NULL;
parent_iface = g_type_interface_peek_parent (G_NETWORK_MONITOR_NM_GET_INITABLE_IFACE (initable));
if (!parent_iface->init (initable, cancellable, error))
return FALSE;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
NULL,
"org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager",
"org.freedesktop.NetworkManager",
cancellable,
error);
if (!proxy)
return FALSE;
name_owner = g_dbus_proxy_get_name_owner (proxy);
if (!name_owner)
{
g_object_unref (proxy);
return FALSE;
}
g_free (name_owner);
/* Verify it has the PrimaryConnection and Connectivity properties */
if (!has_property (proxy, "Connectivity"))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("NetworkManager version too old"));
g_object_unref (proxy);
return FALSE;
}
g_signal_connect (G_OBJECT (proxy), "g-signal",
G_CALLBACK (proxy_signal_cb), nm);
nm->priv->proxy = proxy;
sync_properties (nm, FALSE);
return TRUE;
}
static void
g_network_monitor_nm_finalize (GObject *object)
{
GNetworkMonitorNM *nm = G_NETWORK_MONITOR_NM (object);
g_clear_object (&nm->priv->proxy);
G_OBJECT_CLASS (g_network_monitor_nm_parent_class)->finalize (object);
}
static void
g_network_monitor_nm_class_init (GNetworkMonitorNMClass *nl_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
gobject_class->finalize = g_network_monitor_nm_finalize;
gobject_class->get_property = g_network_monitor_nm_get_property;
g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
g_object_class_override_property (gobject_class, PROP_CONNECTIVITY, "connectivity");
}
static void
g_network_monitor_nm_iface_init (GNetworkMonitorInterface *monitor_iface)
{
}
static void
g_network_monitor_nm_initable_iface_init (GInitableIface *iface)
{
iface->init = g_network_monitor_nm_initable_init;
}