about summary refs log tree commit diff
path: root/libnm-glib/nm-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-glib/nm-client.c')
-rw-r--r--libnm-glib/nm-client.c322
1 files changed, 317 insertions, 5 deletions
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 3ffa7b9e..9226d350 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -60,6 +60,9 @@ typedef struct {
 	NMState state;
 	GPtrArray *devices;
 	GPtrArray *active_connections;
+	NMConnectivityState connectivity;
+	NMActiveConnection *primary_connection;
+	NMActiveConnection *activating_connection;
 
 	DBusGProxyCall *perm_call;
 	GHashTable *permissions;
@@ -93,6 +96,9 @@ enum {
 	PROP_WIMAX_ENABLED,
 	PROP_WIMAX_HARDWARE_ENABLED,
 	PROP_ACTIVE_CONNECTIONS,
+	PROP_CONNECTIVITY,
+	PROP_PRIMARY_CONNECTION,
+	PROP_ACTIVATING_CONNECTION,
 
 	LAST_PROP
 };
@@ -161,6 +167,9 @@ register_properties (NMClient *client)
 		{ NM_CLIENT_WIMAX_ENABLED,             &priv->wimax_enabled },
 		{ NM_CLIENT_WIMAX_HARDWARE_ENABLED,    &priv->wimax_hw_enabled },
 		{ NM_CLIENT_ACTIVE_CONNECTIONS,        &priv->active_connections, NULL, NM_TYPE_ACTIVE_CONNECTION },
+		{ NM_CLIENT_CONNECTIVITY,              &priv->connectivity },
+		{ NM_CLIENT_PRIMARY_CONNECTION,        &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
+		{ NM_CLIENT_ACTIVATING_CONNECTION,     &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
 		{ NULL },
 	};
 
@@ -464,7 +473,7 @@ static void
 recheck_pending_activations (NMClient *self, const char *failed_path, GError *error)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
-	GSList *iter;
+	GSList *iter, *next;
 	const GPtrArray *active_connections;
 	gboolean found_in_active = FALSE;
 	gboolean found_in_pending = FALSE;
@@ -479,9 +488,11 @@ recheck_pending_activations (NMClient *self, const char *failed_path, GError *er
 	 * If the connection to activate doesn't make it to active_connections,
 	 * due to an error, we have to call the callback for failed_path.
 	 */
-	for (iter = priv->pending_activations; iter; iter = g_slist_next (iter)) {
+	for (iter = priv->pending_activations; iter; iter = next) {
 		ActivateInfo *info = iter->data;
 
+		next = g_slist_next (iter);
+
 		if (!found_in_pending && failed_path && g_strcmp0 (failed_path, info->active_path) == 0) {
 			found_in_pending = TRUE;
 			ainfo = info;
@@ -542,7 +553,7 @@ activate_cb (DBusGProxy *proxy,
  * @device: (allow-none): the #NMDevice
  * @specific_object: (allow-none): the object path of a connection-type-specific
  *   object this activation should use. This parameter is currently ignored for
- *   wired and mobile broadband connections, and the value of NULL should be used
+ *   wired and mobile broadband connections, and the value of %NULL should be used
  *   (ie, no specific object).  For WiFi or WiMAX connections, pass the object
  *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
  *   get using nm_object_get_path(), and which will be used to complete the
@@ -618,12 +629,12 @@ add_activate_cb (DBusGProxy *proxy,
  * nm_client_add_and_activate_connection:
  * @client: a #NMClient
  * @partial: (allow-none): an #NMConnection to add; the connection may be
- *   partially filled (or even NULL) and will be completed by NetworkManager
+ *   partially filled (or even %NULL) and will be completed by NetworkManager
  *   using the given @device and @specific_object before being added
  * @device: the #NMDevice
  * @specific_object: (allow-none): the object path of a connection-type-specific
  *   object this activation should use. This parameter is currently ignored for
- *   wired and mobile broadband connections, and the value of NULL should be used
+ *   wired and mobile broadband connections, and the value of %NULL should be used
  *   (ie, no specific object).  For WiFi or WiMAX connections, pass the object
  *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
  *   get using nm_object_get_path(), and which will be used to complete the
@@ -1125,6 +1136,58 @@ nm_client_set_logging (NMClient *client, const char *level, const char *domains,
 	return TRUE;
 }
 
+/**
+ * nm_client_get_primary_connection:
+ * @client: an #NMClient
+ *
+ * Gets the #NMActiveConnection corresponding to the primary active
+ * network device.
+ *
+ * In particular, when there is no VPN active, or the VPN does not
+ * have the default route, this returns the active connection that has
+ * the default route. If there is a VPN active with the default route,
+ * then this function returns the active connection that contains the
+ * route to the VPN endpoint.
+ *
+ * If there is no default route, or the default route is over a
+ * non-NetworkManager-recognized device, this will return %NULL.
+ *
+ * Returns: (transfer none): the appropriate #NMActiveConnection, if
+ * any
+ *
+ * Since: 0.9.8.4
+ */
+NMActiveConnection *
+nm_client_get_primary_connection (NMClient *client)
+{
+	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (client));
+	return NM_CLIENT_GET_PRIVATE (client)->primary_connection;
+}
+
+/**
+ * nm_client_get_activating_connection:
+ * @client: an #NMClient
+ *
+ * Gets the #NMActiveConnection corresponding to a
+ * currently-activating connection that is expected to become the new
+ * #NMClient:primary-connection upon successful activation.
+ *
+ * Returns: (transfer none): the appropriate #NMActiveConnection, if
+ * any.
+ *
+ * Since: 0.9.8.4
+ */
+NMActiveConnection *
+nm_client_get_activating_connection (NMClient *client)
+{
+	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (client));
+	return NM_CLIENT_GET_PRIVATE (client)->activating_connection;
+}
+
 /****************************************************************/
 
 static void
@@ -1251,6 +1314,197 @@ client_device_removed (NMObject *client, NMObject *device)
 	g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
 }
 
+/**
+ * nm_client_get_connectivity:
+ * @client: an #NMClient
+ *
+ * Gets the current network connectivity state. Contrast
+ * nm_client_check_connectivity() and
+ * nm_client_check_connectivity_async(), which re-check the
+ * connectivity state first before returning any information.
+ *
+ * Returns: the current connectivity state
+ * Since: 0.9.8.4
+ */
+NMConnectivityState
+nm_client_get_connectivity (NMClient *client)
+{
+	NMClientPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_CLIENT (client), NM_STATE_UNKNOWN);
+	priv = NM_CLIENT_GET_PRIVATE (client);
+
+	_nm_object_ensure_inited (NM_OBJECT (client));
+
+	return priv->connectivity;
+}
+
+/**
+ * nm_client_check_connectivity:
+ * @client: an #NMClient
+ * @cancellable: a #GCancellable
+ * @error: return location for a #GError
+ *
+ * Updates the network connectivity state and returns the (new)
+ * current state. Contrast nm_client_get_connectivity(), which returns
+ * the most recent known state without re-checking.
+ *
+ * This is a blocking call; use nm_client_check_connectivity_async()
+ * if you do not want to block.
+ *
+ * Returns: the (new) current connectivity state
+ * Since: 0.9.8.4
+ */
+NMConnectivityState
+nm_client_check_connectivity (NMClient *client,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+	NMClientPrivate *priv;
+	NMConnectivityState connectivity;
+
+	g_return_val_if_fail (NM_IS_CLIENT (client), NM_CONNECTIVITY_UNKNOWN);
+	priv = NM_CLIENT_GET_PRIVATE (client);
+
+	if (!dbus_g_proxy_call (priv->client_proxy, "CheckConnectivity", error,
+	                        G_TYPE_INVALID,
+	                        G_TYPE_UINT, &connectivity,
+	                        G_TYPE_INVALID))
+		connectivity = NM_CONNECTIVITY_UNKNOWN;
+
+	return connectivity;
+}
+
+typedef struct {
+	NMClient *client;
+	DBusGProxyCall *call;
+	GCancellable *cancellable;
+	guint cancelled_id;
+	NMConnectivityState connectivity;
+} CheckConnectivityData;
+
+static void
+check_connectivity_data_free (CheckConnectivityData *ccd)
+{
+	if (ccd->cancellable) {
+		if (ccd->cancelled_id)
+			g_signal_handler_disconnect (ccd->cancellable, ccd->cancelled_id);
+		g_object_unref (ccd->cancellable);
+	}
+
+	g_slice_free (CheckConnectivityData, ccd);
+}
+
+static void
+check_connectivity_cb (DBusGProxy *proxy,
+                       DBusGProxyCall *call,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	CheckConnectivityData *ccd = g_simple_async_result_get_op_res_gpointer (simple);
+	GError *error = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call, &error,
+	                            G_TYPE_UINT, &ccd->connectivity,
+	                            G_TYPE_INVALID))
+		g_simple_async_result_take_error (simple, error);
+
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+}
+
+static void
+check_connectivity_cancelled_cb (GCancellable *cancellable,
+                                 gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	CheckConnectivityData *ccd = g_simple_async_result_get_op_res_gpointer (simple);
+
+	g_signal_handler_disconnect (cancellable, ccd->cancelled_id);
+	ccd->cancelled_id = 0;
+
+	dbus_g_proxy_cancel_call (NM_CLIENT_GET_PRIVATE (ccd->client)->client_proxy, ccd->call);
+	g_simple_async_result_complete_in_idle (simple);
+}
+
+/**
+ * nm_client_check_connectivity_async:
+ * @client: an #NMClient
+ * @cancellable: a #GCancellable
+ * @callback: callback to call with the result
+ * @user_data: data for @callback.
+ *
+ * Asynchronously updates the network connectivity state and invokes
+ * @callback when complete. Contrast nm_client_get_connectivity(),
+ * which (immediately) returns the most recent known state without
+ * re-checking, and nm_client_check_connectivity(), which blocks.
+ *
+ * Since: 0.9.8.4
+ */
+void
+nm_client_check_connectivity_async (NMClient *client,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+	NMClientPrivate *priv;
+	GSimpleAsyncResult *simple;
+	CheckConnectivityData *ccd;
+
+	g_return_if_fail (NM_IS_CLIENT (client));
+	priv = NM_CLIENT_GET_PRIVATE (client);
+
+	ccd = g_slice_new (CheckConnectivityData);
+	ccd->client = client;
+
+	simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
+	                                    nm_client_check_connectivity_async);
+	g_simple_async_result_set_op_res_gpointer (simple, ccd, (GDestroyNotify) check_connectivity_data_free);
+
+	if (cancellable) {
+		ccd->cancellable = g_object_ref (cancellable);
+		ccd->cancelled_id = g_signal_connect (cancellable, "cancelled",
+		                                      G_CALLBACK (check_connectivity_cancelled_cb),
+		                                      simple);
+		g_simple_async_result_set_check_cancellable (simple, cancellable);
+	}
+
+	ccd->call = dbus_g_proxy_begin_call (priv->client_proxy, "CheckConnectivity",
+	                                     check_connectivity_cb, simple, NULL,
+	                                     G_TYPE_INVALID);
+}
+
+/**
+ * nm_client_check_connectivity_finish:
+ * @client: an #NMClient
+ * @result: the #GAsyncResult
+ * @error: return location for a #GError
+ *
+ * Retrieves the result of an nm_client_check_connectivity_async()
+ * call.
+ *
+ * Returns: the (new) current connectivity state
+ * Since: 0.9.8.4
+ */
+NMConnectivityState
+nm_client_check_connectivity_finish (NMClient *client,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	GSimpleAsyncResult *simple;
+	CheckConnectivityData *ccd;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), nm_client_check_connectivity_async), NM_CONNECTIVITY_UNKNOWN);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	ccd = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NM_CONNECTIVITY_UNKNOWN;
+
+	return ccd->connectivity;
+}
+
 /****************************************************************/
 
 /**
@@ -1677,6 +1931,8 @@ dispose (GObject *object)
 
 	free_devices (client, FALSE);
 	free_active_connections (client, FALSE);
+	g_clear_object (&priv->primary_connection);
+	g_clear_object (&priv->activating_connection);
 
 	g_slist_foreach (priv->pending_activations, (GFunc) activate_info_free, NULL);
 	g_slist_free (priv->pending_activations);
@@ -1785,6 +2041,15 @@ get_property (GObject *object,
 	case PROP_ACTIVE_CONNECTIONS:
 		g_value_set_boxed (value, nm_client_get_active_connections (self));
 		break;
+	case PROP_CONNECTIVITY:
+		g_value_set_uint (value, priv->connectivity);
+		break;
+	case PROP_PRIMARY_CONNECTION:
+		g_value_set_object (value, priv->primary_connection);
+		break;
+	case PROP_ACTIVATING_CONNECTION:
+		g_value_set_object (value, priv->activating_connection);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1951,6 +2216,53 @@ nm_client_class_init (NMClientClass *client_class)
 						   NM_TYPE_OBJECT_ARRAY,
 						   G_PARAM_READABLE));
 
+	/**
+	 * NMClient:connectivity:
+	 *
+	 * The network connectivity state.
+	 *
+	 * Since: 0.9.8.4
+	 */
+	g_object_class_install_property
+		(object_class, PROP_CONNECTIVITY,
+		 g_param_spec_uint (NM_CLIENT_CONNECTIVITY,
+		                    "Connectivity",
+		                    "Connectivity state",
+		                    NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
+		                    G_PARAM_READABLE));
+
+	/**
+	 * NMClient:primary-connection:
+	 *
+	 * The #NMActiveConnection of the device with the default route;
+	 * see nm_client_get_primary_connection() for more details.
+	 *
+	 * Since: 0.9.8.4
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_PRIMARY_CONNECTION,
+		 g_param_spec_object (NM_CLIENT_PRIMARY_CONNECTION,
+		                      "Primary connection",
+		                      "Primary connection",
+		                      NM_TYPE_ACTIVE_CONNECTION,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMClient:activating-connection:
+	 *
+	 * The #NMActiveConnection of the activating connection that is
+	 * likely to become the new #NMClient:primary-connection.
+	 *
+	 * Since: 0.9.8.4
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_ACTIVATING_CONNECTION,
+		 g_param_spec_object (NM_CLIENT_ACTIVATING_CONNECTION,
+		                      "Activating connection",
+		                      "Activating connection",
+		                      NM_TYPE_ACTIVE_CONNECTION,
+		                      G_PARAM_READABLE));
+
 	/* signals */
 
 	/**