diff options
author | Thomas Haller <thaller@redhat.com> | 2018-10-17 13:03:57 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-10-17 13:03:57 +0200 |
commit | fd7115eeed527c92925b3b176add81d9a3605455 (patch) | |
tree | f3f59da05103cc52c2e364e59de8b404a7f14ebc | |
parent | 09719bc479b63c8e5fef3950e980b263aca7eff5 (diff) | |
parent | 47146b4be3300308967605040612b6207ddb5057 (diff) | |
download | NetworkManager-fd7115eeed527c92925b3b176add81d9a3605455.tar.gz |
core: merge branch 'th/no-gasyncresult'
https://github.com/NetworkManager/NetworkManager/pull/227
25 files changed, 590 insertions, 469 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 8b36bbd27b..22c85cd769 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -305,6 +305,10 @@ void _nm_dbus_errors_init (void); extern gboolean _nm_utils_is_manager_process; +gboolean _nm_dbus_typecheck_response (GVariant *response, + const GVariantType *reply_type, + GError **error); + gulong _nm_dbus_signal_connect_data (GDBusProxy *proxy, const char *signal_name, const GVariantType *signature, @@ -329,6 +333,11 @@ GVariant *_nm_dbus_proxy_call_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error); +GVariant * _nm_dbus_connection_call_finish (GDBusConnection *dbus_connection, + GAsyncResult *result, + const GVariantType *reply_type, + GError **error); + gboolean _nm_dbus_error_has_name (GError *error, const char *dbus_error_name); diff --git a/libnm-core/nm-dbus-utils.c b/libnm-core/nm-dbus-utils.c index 25af7c9964..69f4bb2f8a 100644 --- a/libnm-core/nm-dbus-utils.c +++ b/libnm-core/nm-dbus-utils.c @@ -174,23 +174,35 @@ _nm_dbus_signal_connect_data (GDBusProxy *proxy, * Returns: the signal handler ID, as with _nm_signal_connect_data(). */ -static void -typecheck_response (GVariant **response, - const GVariantType *reply_type, - GError **error) +/** + * _nm_dbus_typecheck_response: + * @response: the #GVariant response to check. + * @reply_type: the expected reply type. It may be %NULL to perform no + * checking. + * @error: (allow-none): the error in case the @reply_type does not match. + * + * Returns: %TRUE, if @response is of the expected @reply_type. + */ +gboolean +_nm_dbus_typecheck_response (GVariant *response, + const GVariantType *reply_type, + GError **error) { - if ( *response - && reply_type - && !g_variant_is_of_type (*response, reply_type)) { - /* This is the same error code that g_dbus_connection_call() returns if - * @reply_type doesn't match. - */ - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Method returned type '%s', but expected '%s'"), - g_variant_get_type_string (*response), - g_variant_type_peek_string (reply_type)); - g_clear_pointer (response, g_variant_unref); - } + g_return_val_if_fail (response, FALSE); + + if (!reply_type) + return TRUE; + if (g_variant_is_of_type (response, reply_type)) + return TRUE; + + /* This is the same error code that g_dbus_connection_call() returns if + * @reply_type doesn't match. + */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Method returned type '%s', but expected '%s'"), + g_variant_get_type_string (response), + g_variant_type_peek_string (reply_type)); + return FALSE; } /** @@ -215,11 +227,15 @@ _nm_dbus_proxy_call_finish (GDBusProxy *proxy, const GVariantType *reply_type, GError **error) { - GVariant *ret; + GVariant *variant; - ret = g_dbus_proxy_call_finish (proxy, res, error); - typecheck_response (&ret, reply_type, error); - return ret; + variant = g_dbus_proxy_call_finish (proxy, + res, + error); + if ( variant + && !_nm_dbus_typecheck_response (variant, reply_type, error)) + nm_clear_pointer (&variant, g_variant_unref); + return variant; } /** @@ -253,13 +269,34 @@ _nm_dbus_proxy_call_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error) { - GVariant *ret; + GVariant *variant; + + variant = g_dbus_proxy_call_sync (proxy, + method_name, + parameters, + flags, + timeout_msec, + cancellable, + error); + if ( variant + && !_nm_dbus_typecheck_response (variant, reply_type, error)) + nm_clear_pointer (&variant, g_variant_unref); + return variant; +} + +GVariant * +_nm_dbus_connection_call_finish (GDBusConnection *dbus_connection, + GAsyncResult *result, + const GVariantType *reply_type, + GError **error) +{ + GVariant *variant; - ret = g_dbus_proxy_call_sync (proxy, method_name, parameters, - flags, timeout_msec, - cancellable, error); - typecheck_response (&ret, reply_type, error); - return ret; + variant = g_dbus_connection_call_finish (dbus_connection, result, error); + if ( variant + && !_nm_dbus_typecheck_response (variant, reply_type, error)) + nm_clear_pointer (&variant, g_variant_unref); + return variant; } /** diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 2ace309841..c41b5e68c2 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -2055,3 +2055,70 @@ _nm_utils_unescape_spaces (char *str) } #undef IS_SPACE + +/*****************************************************************************/ + +typedef struct { + gpointer callback_user_data; + GCancellable *cancellable; + NMUtilsInvokeOnIdleCallback callback; + gulong cancelled_id; + guint idle_id; +} InvokeOnIdleData; + +static gboolean +_nm_utils_invoke_on_idle_cb_idle (gpointer user_data) +{ + InvokeOnIdleData *data = user_data; + + data->idle_id = 0; + nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id); + + data->callback (data->callback_user_data, data->cancellable); + nm_g_object_unref (data->cancellable); + g_slice_free (InvokeOnIdleData, data); + return G_SOURCE_REMOVE; +} + +static void +_nm_utils_invoke_on_idle_cb_cancelled (GCancellable *cancellable, + InvokeOnIdleData *data) +{ + /* on cancellation, we invoke the callback synchronously. */ + nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id); + nm_clear_g_source (&data->idle_id); + data->callback (data->callback_user_data, data->cancellable); + nm_g_object_unref (data->cancellable); + g_slice_free (InvokeOnIdleData, data); +} + +void +nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data, + GCancellable *cancellable) +{ + InvokeOnIdleData *data; + + g_return_if_fail (callback); + + data = g_slice_new (InvokeOnIdleData); + data->callback = callback; + data->callback_user_data = callback_user_data; + data->cancellable = nm_g_object_ref (cancellable); + if ( cancellable + && !g_cancellable_is_cancelled (cancellable)) { + /* if we are passed a non-cancelled cancellable, we register to the "cancelled" + * signal an invoke the callback synchronously (from the signal handler). + * + * We don't do that, + * - if the cancellable is already cancelled (because we don't want to invoke + * the callback synchronously from the caller). + * - if we have no cancellable at hand. */ + data->cancelled_id = g_signal_connect (cancellable, + "cancelled", + G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled), + data); + } else + data->cancelled_id = 0; + data->idle_id = g_idle_add (_nm_utils_invoke_on_idle_cb_idle, data); +} diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index fb37535d76..7ee76799bd 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -909,4 +909,13 @@ void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...); const char *_nm_utils_escape_spaces (const char *str, char **to_free); char *_nm_utils_unescape_spaces (char *str); +/*****************************************************************************/ + +typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer callback_user_data, + GCancellable *cancellable); + +void nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data, + GCancellable *cancellable); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index c9984f5135..9cec81920f 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -523,7 +523,7 @@ adsl_cleanup (NMDeviceAdsl *self) if (priv->ppp_manager) { g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_state_changed), self); g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_ip4_config), self); - nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL, NULL); g_clear_object (&priv->ppp_manager); } diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index b722f692ce..8e2a96b78f 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -451,6 +451,9 @@ nm_bluez_device_disconnect (NMBluezDevice *self) g_return_if_fail (priv->dbus_connection); + /* FIXME: if we are in the process of connecting and cancel the + * connection attempt, we must complete the pending connect request. + * However, we must also ensure that we don't leave a connected device. */ if (priv->connection_bt_type == NM_BT_CAPABILITY_DUN) { if (priv->bluez_version == 4) { /* Can't pass a NULL interface name through dbus to bluez, so just @@ -496,76 +499,109 @@ out: } static void -bluez_connect_cb (GDBusConnection *dbus_connection, +_connect_complete (NMBluezDevice *self, + const char *device, + NMBluezDeviceConnectCallback callback, + gpointer callback_user_data, + GError *error) +{ + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + nm_assert ((device || error) && !(device && error)); + + if ( device + && priv->bluez_version == 5) { + priv->connected = TRUE; + _notify (self, PROP_CONNECTED); + } + + if (callback) + callback (self, device, error, callback_user_data); +} + +static void +_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { - GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); - GObject *result_object = g_async_result_get_source_object (G_ASYNC_RESULT (result)); - NMBluezDevice *self = NM_BLUEZ_DEVICE (result_object); - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GError *error = NULL; - char *device; - GVariant *variant; + gs_unref_object NMBluezDevice *self = NULL; + NMBluezDevicePrivate *priv; + NMBluezDeviceConnectCallback callback; + gpointer callback_user_data; + gs_free_error GError *error = NULL; + char *device = NULL; + gs_unref_variant GVariant *variant = NULL; - variant = g_dbus_connection_call_finish (dbus_connection, res, &error); + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); - if (!variant) { - g_simple_async_result_take_error (result, error); - } else { - g_variant_get (variant, "(s)", &device); + priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - g_simple_async_result_set_op_res_gpointer (result, - g_strdup (device), - g_free); + variant = _nm_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, G_VARIANT_TYPE ("(s)"), &error); + if (variant) { + g_variant_get (variant, "(s)", &device); priv->b4_iface = device; - g_variant_unref (variant); } - g_simple_async_result_complete (result); - g_object_unref (result); - g_object_unref (result_object); + _connect_complete (self, device, callback, callback_user_data, error); } #if WITH_BLUEZ5_DUN static void -bluez5_dun_connect_cb (NMBluez5DunContext *context, - const char *device, - GError *error, - gpointer user_data) +_connect_cb_bluez5_dun (NMBluez5DunContext *context, + const char *device, + GError *error, + gpointer user_data) { - GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + gs_unref_object NMBluezDevice *self = NULL; + gs_unref_object GCancellable *cancellable = NULL; + NMBluezDeviceConnectCallback callback; + gpointer callback_user_data; + gs_free_error GError *cancelled_error = NULL; - if (error) { - g_simple_async_result_take_error (result, error); - } else { - g_simple_async_result_set_op_res_gpointer (result, - g_strdup (device), - g_free); - } + nm_utils_user_data_unpack (user_data, &self, &cancellable, &callback, &callback_user_data); + + /* FIXME(shutdown): the async operation nm_bluez5_dun_connect() should be cancellable. + * Fake it here. */ + if (g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error)) + error = cancelled_error; - g_simple_async_result_complete (result); - g_object_unref (result); + _connect_complete (self, device, callback, callback_user_data, error); } -#endif +#else /* WITH_BLUEZ5_DUN */ +static void +_connect_cb_bluez5_dun_idle_no_b5 (gpointer user_data, + GCancellable *cancellable) +{ + gs_unref_object NMBluezDevice *self = NULL; + NMBluezDeviceConnectCallback callback; + gpointer callback_user_data; + gs_free_error GError *error = NULL; + + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); + + if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) { + g_set_error (&error, + NM_BT_ERROR, + NM_BT_ERROR_DUN_CONNECT_FAILED, + "NetworkManager built without support for Bluez 5"); + } + callback (self, NULL, error, callback_user_data); +} +#endif /* WITH_BLUEZ5_DUN */ void nm_bluez_device_connect_async (NMBluezDevice *self, NMBluetoothCapabilities connection_bt_type, - GAsyncReadyCallback callback, - gpointer user_data) + GCancellable *cancellable, + NMBluezDeviceConnectCallback callback, + gpointer callback_user_data) { - GSimpleAsyncResult *simple; NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); const char *dbus_iface = NULL; const char *connect_type = NULL; g_return_if_fail (priv->capabilities & connection_bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP)); - simple = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - nm_bluez_device_connect_async); priv->connection_bt_type = connection_bt_type; if (connection_bt_type == NM_BT_CAPABILITY_NAP) { @@ -582,19 +618,29 @@ nm_bluez_device_connect_async (NMBluezDevice *self, #if WITH_BLUEZ5_DUN if (priv->b5_dun_context == NULL) priv->b5_dun_context = nm_bluez5_dun_new (priv->adapter_address, priv->address); - nm_bluez5_dun_connect (priv->b5_dun_context, bluez5_dun_connect_cb, simple); + nm_bluez5_dun_connect (priv->b5_dun_context, + _connect_cb_bluez5_dun, + nm_utils_user_data_pack (g_object_ref (self), + nm_g_object_ref (cancellable), + callback, + callback_user_data)); #else - g_simple_async_result_set_error (simple, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "NetworkManager built without support for Bluez 5"); - g_simple_async_result_complete (simple); + if (callback) { + nm_utils_invoke_on_idle (_connect_cb_bluez5_dun_idle_no_b5, + nm_utils_user_data_pack (g_object_ref (self), + callback, + callback_user_data), + cancellable); + } #endif return; } } else - g_assert_not_reached (); + g_return_if_reached (); + /* FIXME: we need to remember that a connect is in progress. + * So, if the request gets cancelled, that we disconnect the + * connection that was established in the meantime. */ g_dbus_connection_call (priv->dbus_connection, NM_BLUEZ_SERVICE, priv->path, @@ -604,37 +650,11 @@ nm_bluez_device_connect_async (NMBluezDevice *self, NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) bluez_connect_cb, - simple); -} - -const char * -nm_bluez_device_connect_finish (NMBluezDevice *self, - GAsyncResult *result, - GError **error) -{ - NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - GSimpleAsyncResult *simple; - const char *device; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, - G_OBJECT (self), - nm_bluez_device_connect_async), - NULL); - - simple = (GSimpleAsyncResult *) result; - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - device = (const char *) g_simple_async_result_get_op_res_gpointer (simple); - if (device && priv->bluez_version == 5) { - priv->connected = TRUE; - _notify (self, PROP_CONNECTED); - } - - return device; + cancellable, + _connect_cb, + nm_utils_user_data_pack (g_object_ref (self), + callback, + callback_user_data)); } /*****************************************************************************/ diff --git a/src/devices/bluetooth/nm-bluez-device.h b/src/devices/bluetooth/nm-bluez-device.h index f8a1872f2e..d2d0beb016 100644 --- a/src/devices/bluetooth/nm-bluez-device.h +++ b/src/devices/bluetooth/nm-bluez-device.h @@ -66,16 +66,17 @@ guint32 nm_bluez_device_get_capabilities (NMBluezDevice *self); gboolean nm_bluez_device_get_connected (NMBluezDevice *self); +typedef void (*NMBluezDeviceConnectCallback) (NMBluezDevice *self, + const char *device, + GError *error, + gpointer user_data); + void nm_bluez_device_connect_async (NMBluezDevice *self, NMBluetoothCapabilities connection_bt_type, - GAsyncReadyCallback callback, - gpointer user_data); - -const char * -nm_bluez_device_connect_finish (NMBluezDevice *self, - GAsyncResult *result, - GError **error); + GCancellable *cancellable, + NMBluezDeviceConnectCallback callback, + gpointer callback_user_data); void nm_bluez_device_disconnect (NMBluezDevice *self); diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c index ca09b276e7..32f8da65eb 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.c +++ b/src/devices/bluetooth/nm-bluez5-dun.c @@ -342,13 +342,14 @@ nm_bluez5_dun_connect (NMBluez5DunContext *context, if (context->rfcomm_channel != -1) { nm_log_dbg (LOGD_BT, "(%s): channel number on device %s cached: %d", - context->src_str, context->dst_str, context->rfcomm_channel); + context->src_str, context->dst_str, context->rfcomm_channel); + /* FIXME: don't invoke the callback synchronously. */ dun_connect (context); return; } nm_log_dbg (LOGD_BT, "(%s): starting channel number discovery for device %s", - context->src_str, context->dst_str); + context->src_str, context->dst_str); context->sdp_session = sdp_connect (&context->src, &context->dst, SDP_NON_BLOCKING); if (!context->sdp_session) { @@ -358,10 +359,12 @@ nm_bluez5_dun_connect (NMBluez5DunContext *context, error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Failed to connect to the SDP server: (%d) %s", err, strerror (err)); + /* FIXME: don't invoke the callback synchronously. */ context->callback (context, NULL, error, context->user_data); return; } + /* FIXME(shutdown): make connect cancellable. */ channel = g_io_channel_unix_new (sdp_get_socket (context->sdp_session)); context->sdp_watch_id = g_io_add_watch (channel, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, diff --git a/src/devices/bluetooth/nm-bluez5-dun.h b/src/devices/bluetooth/nm-bluez5-dun.h index 124c1a05b0..b75e4399a7 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.h +++ b/src/devices/bluetooth/nm-bluez5-dun.h @@ -32,7 +32,8 @@ NMBluez5DunContext *nm_bluez5_dun_new (const char *adapter, const char *remote); void nm_bluez5_dun_connect (NMBluez5DunContext *context, - NMBluez5DunFunc callback, gpointer user_data); + NMBluez5DunFunc callback, + gpointer user_data); /* Clean up connection resources */ void nm_bluez5_dun_cleanup (NMBluez5DunContext *context); diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 1f650d339f..b05c569beb 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -78,7 +78,9 @@ typedef struct { char *rfcomm_iface; NMModem *modem; - guint32 timeout_id; + guint timeout_id; + + GCancellable *cancellable; guint32 bt_type; /* BT type of the current connection */ } NMDeviceBtPrivate; @@ -672,6 +674,7 @@ component_added (NMDevice *device, GObject *component) /* Got the modem */ nm_clear_g_source (&priv->timeout_id); + nm_clear_g_cancellable (&priv->cancellable); /* Can only accept the modem in stage2, but since the interface matched * what we were expecting, don't let anything else claim the modem either. @@ -715,8 +718,11 @@ static gboolean modem_find_timeout (gpointer user_data) { NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + priv->timeout_id = 0; + nm_clear_g_cancellable (&priv->cancellable); - NM_DEVICE_BT_GET_PRIVATE (self)->timeout_id = 0; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); @@ -738,8 +744,8 @@ check_connect_continue (NMDeviceBt *self) "Activation: (bluetooth) Stage 2 of 5 (Device Configure) successful. Will connect via %s.", dun ? "DUN" : (pan ? "PAN" : "unknown")); - /* Kill the connect timeout since we're connected now */ nm_clear_g_source (&priv->timeout_id); + nm_clear_g_cancellable (&priv->cancellable); if (pan) { /* Bluez says we're connected now. Start IP config. */ @@ -755,25 +761,25 @@ check_connect_continue (NMDeviceBt *self) } static void -bluez_connect_cb (GObject *object, - GAsyncResult *res, - void *user_data) +bluez_connect_cb (NMBluezDevice *bt_device, + const char *device_name, + GError *error, + gpointer user_data) { - gs_unref_object NMDeviceBt *self = NM_DEVICE_BT (user_data); + gs_unref_object NMDeviceBt *self = user_data; NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - GError *error = NULL; - const char *device; - device = nm_bluez_device_connect_finish (NM_BLUEZ_DEVICE (object), - res, &error); + if (nm_utils_error_is_cancelled (error, FALSE)) + return; + + nm_clear_g_source (&priv->timeout_id); + g_clear_object (&priv->cancellable); if (!nm_device_is_activating (NM_DEVICE (self))) return; - if (!device) { + if (!device_name) { _LOGW (LOGD_BT, "Error connecting with bluez: %s", error->message); - g_clear_error (&error); - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); @@ -782,10 +788,10 @@ bluez_connect_cb (GObject *object, if (priv->bt_type == NM_BT_CAPABILITY_DUN) { g_free (priv->rfcomm_iface); - priv->rfcomm_iface = g_strdup (device); + priv->rfcomm_iface = g_strdup (device_name); } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { - if (!nm_device_set_ip_iface (NM_DEVICE (self), device)) { - _LOGW (LOGD_BT, "Error connecting with bluez: cannot find device %s", device); + if (!nm_device_set_ip_iface (NM_DEVICE (self), device_name)) { + _LOGW (LOGD_BT, "Error connecting with bluez: cannot find device %s", device_name); nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); @@ -843,10 +849,13 @@ static gboolean bt_connect_timeout (gpointer user_data) { NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); _LOGD (LOGD_BT, "initial connection timed out"); - NM_DEVICE_BT_GET_PRIVATE (self)->timeout_id = 0; + priv->timeout_id = 0; + nm_clear_g_cancellable (&priv->cancellable); + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); @@ -876,13 +885,17 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) _LOGD (LOGD_BT, "requesting connection to the device"); - /* Connect to the BT device */ - nm_bluez_device_connect_async (priv->bt_device, - priv->bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP), - bluez_connect_cb, g_object_ref (device)); - nm_clear_g_source (&priv->timeout_id); + nm_clear_g_cancellable (&priv->cancellable); + priv->timeout_id = g_timeout_add_seconds (30, bt_connect_timeout, device); + priv->cancellable = g_cancellable_new (); + + nm_bluez_device_connect_async (priv->bt_device, + priv->bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP), + priv->cancellable, + bluez_connect_cb, + g_object_ref (self)); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -925,6 +938,9 @@ deactivate (NMDevice *device) priv->have_iface = FALSE; priv->connected = FALSE; + nm_clear_g_source (&priv->timeout_id); + nm_clear_g_cancellable (&priv->cancellable); + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { if (priv->modem) { nm_modem_deactivate (priv->modem, device); @@ -942,8 +958,6 @@ deactivate (NMDevice *device) if (priv->bt_type != NM_BT_CAPABILITY_NONE) nm_bluez_device_disconnect (priv->bt_device); - nm_clear_g_source (&priv->timeout_id); - priv->bt_type = NM_BT_CAPABILITY_NONE; g_free (priv->rfcomm_iface); @@ -1128,6 +1142,7 @@ dispose (GObject *object) NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); nm_clear_g_source (&priv->timeout_id); + nm_clear_g_cancellable (&priv->cancellable); g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 0fb8fea42c..1587a2a343 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1347,7 +1347,7 @@ deactivate (NMDevice *device) nm_clear_g_source (&priv->pppoe_wait_id); if (priv->ppp_manager) { - nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL, NULL); g_clear_object (&priv->ppp_manager); } diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 74b4d710ca..3a3f9054a1 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -221,7 +221,7 @@ deactivate (NMDevice *device) NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); if (priv->ppp_manager) { - nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL, NULL); g_clear_object (&priv->ppp_manager); } } diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 7a9f03800a..ce21803bfa 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -14537,30 +14537,25 @@ ip6_managed_setup (NMDevice *self) static void deactivate_async_ready (NMDevice *self, - GAsyncResult *res, + GError *error, gpointer user_data) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDeviceStateReason reason = GPOINTER_TO_UINT (user_data); - GError *error = NULL; - - NM_DEVICE_GET_CLASS (self)->deactivate_async_finish (self, res, &error); - /* If operation cancelled, just return */ - if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) - || (priv->deactivating_cancellable && g_cancellable_is_cancelled (priv->deactivating_cancellable))) { - _LOGW (LOGD_DEVICE, "Deactivation cancelled"); - } else { - /* In every other case, transition to the DISCONNECTED state */ - if (error) { - _LOGW (LOGD_DEVICE, "Deactivation failed: %s", - error->message); - } - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (LOGD_DEVICE, "Deactivation cancelled"); + return; } g_clear_object (&priv->deactivating_cancellable); - g_clear_error (&error); + + /* In every other case, transition to the DISCONNECTED state */ + if (error) { + _LOGW (LOGD_DEVICE, "Deactivation failed: %s", + error->message); + } + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); } static void @@ -14580,14 +14575,13 @@ deactivate_dispatcher_complete (guint call_id, gpointer user_data) priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; if (nm_clear_g_cancellable (&priv->deactivating_cancellable)) - g_warn_if_reached (); + nm_assert_not_reached (); - if ( NM_DEVICE_GET_CLASS (self)->deactivate_async - && NM_DEVICE_GET_CLASS (self)->deactivate_async_finish) { + if (NM_DEVICE_GET_CLASS (self)->deactivate_async) { priv->deactivating_cancellable = g_cancellable_new (); NM_DEVICE_GET_CLASS (self)->deactivate_async (self, priv->deactivating_cancellable, - (GAsyncReadyCallback) deactivate_async_ready, + deactivate_async_ready, GUINT_TO_POINTER (reason)); } else nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); @@ -14644,8 +14638,8 @@ _set_state_full (NMDevice *self, queued_state_clear (self); dispatcher_cleanup (self); - if (priv->deactivating_cancellable) - g_cancellable_cancel (priv->deactivating_cancellable); + + nm_clear_g_cancellable (&priv->deactivating_cancellable); /* Cache the activation request for the dispatcher */ req = nm_g_object_ref (priv->act_request.obj); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index d1e58d4749..199ef51b0b 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -197,6 +197,10 @@ typedef enum { /*< skip >*/ NM_DEVICE_CHECK_DEV_AVAILABLE_ALL = (1L << 1) - 1, } NMDeviceCheckDevAvailableFlags; +typedef void (*NMDeviceDeactivateCallback) (NMDevice *self, + GError *error, + gpointer user_data); + typedef struct _NMDeviceClass { NMDBusObjectClass parent; @@ -354,11 +358,8 @@ typedef struct _NMDeviceClass { /* Async deactivating (in the DEACTIVATING phase) */ void (* deactivate_async) (NMDevice *self, GCancellable *cancellable, - GAsyncReadyCallback callback, + NMDeviceDeactivateCallback callback, gpointer user_data); - gboolean (* deactivate_async_finish) (NMDevice *self, - GAsyncResult *res, - GError **error); void (* deactivate_reset_hw_addr) (NMDevice *self); diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 9038b68d14..5a601b7412 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -444,7 +444,10 @@ cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect) } static void -reset_mode (NMDeviceIwd *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) +reset_mode (NMDeviceIwd *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -454,7 +457,9 @@ reset_mode (NMDeviceIwd *self, GCancellable *cancellable, GAsyncReadyCallback ca "Mode", g_variant_new_string ("station")), G_DBUS_CALL_FLAGS_NONE, 2000, - cancellable, callback, user_data); + cancellable, + callback, + user_data); } static void @@ -473,43 +478,53 @@ deactivate (NMDevice *device) reset_mode (self, NULL, NULL, NULL); } -static gboolean -deactivate_async_finish (NMDevice *device, GAsyncResult *res, GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - static void disconnect_cb (GObject *source, GAsyncResult *res, gpointer user_data) { - GTask *task = user_data; + gs_unref_object NMDeviceIwd *self = NULL; + NMDeviceDeactivateCallback callback; + gpointer callback_user_data; gs_unref_variant GVariant *variant = NULL; - GError *error = NULL; + gs_free_error GError *error = NULL; + + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); - if (variant) - g_task_return_boolean (task, TRUE); - else - g_task_return_error (task, error); + callback (NM_DEVICE (self), error, callback_user_data); +} + +static void +disconnect_cb_on_idle (gpointer user_data, + GCancellable *cancellable) +{ + gs_unref_object NMDeviceIwd *self = NULL; + NMDeviceDeactivateCallback callback; + gpointer callback_user_data; + gs_free_error GError *cancelled_error = NULL; - g_object_unref (task); + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); + + g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error); + callback (NM_DEVICE (self), cancelled_error, callback_user_data); } static void deactivate_async (NMDevice *device, GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) + NMDeviceDeactivateCallback callback, + gpointer callback_user_data) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - GTask *task; + gpointer user_data; + + nm_assert (G_IS_CANCELLABLE (cancellable)); + nm_assert (callback); - task = g_task_new (self, cancellable, callback, user_data); + user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data); if (!priv->dbus_obj) { - g_task_return_boolean (task, TRUE); - g_object_unref (task); + nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable); return; } @@ -517,10 +532,16 @@ deactivate_async (NMDevice *device, priv->act_mode_switch = FALSE; if (priv->dbus_station_proxy) { - g_dbus_proxy_call (priv->dbus_station_proxy, "Disconnect", g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, cancellable, disconnect_cb, task); + g_dbus_proxy_call (priv->dbus_station_proxy, + "Disconnect", + g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + disconnect_cb, + user_data); } else - reset_mode (self, cancellable, disconnect_cb, task); + reset_mode (self, cancellable, disconnect_cb, user_data); } static gboolean @@ -2540,7 +2561,6 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) device_class->get_configured_mtu = get_configured_mtu; device_class->deactivate = deactivate; device_class->deactivate_async = deactivate_async; - device_class->deactivate_async_finish = deactivate_async_finish; device_class->can_reapply_change = can_reapply_change; device_class->state_changed = device_state_changed; diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index 70b954c5d8..ea966afe6a 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -6,7 +6,6 @@ global: nm_modem_complete_connection; nm_modem_deactivate; nm_modem_deactivate_async; - nm_modem_deactivate_async_finish; nm_modem_device_state_changed; nm_modem_get_capabilities; nm_modem_get_configured_mtu; diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index f3e2cbd7eb..e98118b60c 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -61,7 +61,7 @@ struct _NMDeviceModemClass { G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) -#define NM_DEVICE_MODEM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceModem, NM_IS_DEVICE_MODEM) +#define NM_DEVICE_MODEM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceModem, NM_IS_DEVICE_MODEM, NMDevice) /*****************************************************************************/ @@ -483,44 +483,35 @@ deactivate (NMDevice *device) /*****************************************************************************/ -static gboolean -deactivate_async_finish (NMDevice *self, - GAsyncResult *res, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); -} - static void -modem_deactivate_async_ready (NMModem *modem, - GAsyncResult *res, - GSimpleAsyncResult *simple) +modem_deactivate_async_cb (NMModem *modem, + GError *error, + gpointer user_data) { - GError *error = NULL; + gs_unref_object NMDevice *self = NULL; + NMDeviceDeactivateCallback callback; + gpointer callback_user_data; - if (!nm_modem_deactivate_async_finish (modem, res, &error)) - g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - g_object_unref (simple); + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); + callback (self, error, callback_user_data); } static void deactivate_async (NMDevice *self, GCancellable *cancellable, - GAsyncReadyCallback callback, + NMDeviceDeactivateCallback callback, gpointer user_data) { - GSimpleAsyncResult *simple; + nm_assert (G_IS_CANCELLABLE (cancellable)); + nm_assert (callback); - simple = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - deactivate_async); - nm_modem_deactivate_async (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) self)->modem, + nm_modem_deactivate_async (NM_DEVICE_MODEM_GET_PRIVATE (self)->modem, self, cancellable, - (GAsyncReadyCallback) modem_deactivate_async_ready, - simple); + modem_deactivate_async_cb, + nm_utils_user_data_pack (g_object_ref (self), + callback, + user_data)); } /*****************************************************************************/ @@ -805,7 +796,6 @@ nm_device_modem_class_init (NMDeviceModemClass *klass) device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; device_class->deactivate_async = deactivate_async; - device_class->deactivate_async_finish = deactivate_async_finish; device_class->deactivate = deactivate; device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 352b775829..824fd6db42 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -1098,100 +1098,101 @@ stage3_ip6_config_request (NMModem *modem, NMDeviceStateReason *out_failure_reas typedef struct { NMModemBroadband *self; - GSimpleAsyncResult *result; + _NMModemDisconnectCallback callback; + gpointer callback_user_data; GCancellable *cancellable; gboolean warn; } DisconnectContext; static void -disconnect_context_complete (DisconnectContext *ctx) +disconnect_context_complete (DisconnectContext *ctx, GError *error) { - g_simple_async_result_complete_in_idle (ctx->result); - if (ctx->cancellable) - g_object_unref (ctx->cancellable); - g_object_unref (ctx->result); + if (ctx->callback) + ctx->callback (NM_MODEM (ctx->self), error, ctx->callback_user_data); + nm_g_object_unref (ctx->cancellable); g_object_unref (ctx->self); g_slice_free (DisconnectContext, ctx); } -static gboolean -disconnect_finish (NMModem *self, - GAsyncResult *res, - GError **error) +static void +disconnect_context_complete_on_idle (gpointer user_data, + GCancellable *cancellable) { - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); + DisconnectContext *ctx = NULL; + gs_free_error GError *cancelled_error = NULL; + + g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error); + disconnect_context_complete (ctx, cancelled_error); } static void -simple_disconnect_ready (MMModemSimple *modem_iface, +simple_disconnect_ready (GObject *source_object, GAsyncResult *res, - DisconnectContext *ctx) + gpointer user_data) { + MMModemSimple *modem_iface = MM_MODEM_SIMPLE (source_object); + DisconnectContext *ctx = user_data; GError *error = NULL; if (!mm_modem_simple_disconnect_finish (modem_iface, res, &error)) { - if (ctx->warn && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + if ( ctx->warn + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { NMModemBroadband *self = ctx->self; _LOGW ("failed to disconnect modem: %s", error->message); } - g_simple_async_result_take_error (ctx->result, error); } - disconnect_context_complete (ctx); + disconnect_context_complete (ctx, error); } static void disconnect (NMModem *modem, gboolean warn, GCancellable *cancellable, - GAsyncReadyCallback callback, + _NMModemDisconnectCallback callback, gpointer user_data) { NMModemBroadband *self = NM_MODEM_BROADBAND (modem); DisconnectContext *ctx; - GError *error = NULL; connect_context_clear (self); - ctx = g_slice_new (DisconnectContext); - ctx->cancellable = NULL; + + ctx = g_slice_new0 (DisconnectContext); ctx->self = g_object_ref (self); - ctx->result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - disconnect); + ctx->cancellable = nm_g_object_ref (cancellable); + ctx->callback = callback; + ctx->callback_user_data = user_data; + /* Don't bother warning on FAILED since the modem is already gone */ ctx->warn = warn; - /* Already cancelled? */ - if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { - g_simple_async_result_take_error (ctx->result, error); - disconnect_context_complete (ctx); - return; - } - - /* If no simple iface, we're done */ - if (!ctx->self->_priv.simple_iface) { - disconnect_context_complete (ctx); + /* Already cancelled or no simple-iface? We are done. */ + if ( !ctx->self->_priv.simple_iface + || g_cancellable_is_cancelled (cancellable)) { + nm_utils_invoke_on_idle (disconnect_context_complete_on_idle, + ctx, + cancellable); return; } _LOGD ("notifying ModemManager about the modem disconnection"); - ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - mm_modem_simple_disconnect (ctx->self->_priv.simple_iface, + mm_modem_simple_disconnect (self->_priv.simple_iface, NULL, /* bearer path; if NULL given ALL get disconnected */ cancellable, - (GAsyncReadyCallback) simple_disconnect_ready, + simple_disconnect_ready, ctx); } /*****************************************************************************/ static void -deactivate_cleanup (NMModem *_self, NMDevice *device) +deactivate_cleanup (NMModem *modem, + NMDevice *device, + gboolean stop_ppp_manager) { - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + NMModemBroadband *self = NM_MODEM_BROADBAND (modem); /* TODO: cancel SimpleConnect() if any */ @@ -1202,8 +1203,9 @@ deactivate_cleanup (NMModem *_self, NMDevice *device) self->_priv.pin_tries = 0; - /* Chain up parent's */ - NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate_cleanup (_self, device); + NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate_cleanup (modem, + device, + stop_ppp_manager); } /*****************************************************************************/ @@ -1468,7 +1470,6 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass) modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; modem_class->stage3_ip6_config_request = stage3_ip6_config_request; modem_class->disconnect = disconnect; - modem_class->disconnect_finish = disconnect_finish; modem_class->deactivate_cleanup = deactivate_cleanup; modem_class->set_mm_enabled = set_mm_enabled; modem_class->get_user_pass = get_user_pass; diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index ab5cb0befa..56b6d745c5 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -146,30 +146,36 @@ update_modem_state (NMModemOfono *self) /* Disconnect */ typedef struct { NMModemOfono *self; - GSimpleAsyncResult *result; + _NMModemDisconnectCallback callback; + gpointer callback_user_data; GCancellable *cancellable; gboolean warn; } DisconnectContext; static void -disconnect_context_complete (DisconnectContext *ctx) +disconnect_context_complete (DisconnectContext *ctx, GError *error) { - if (ctx->cancellable) - g_object_unref (ctx->cancellable); - if (ctx->result) { - g_simple_async_result_complete_in_idle (ctx->result); - g_object_unref (ctx->result); - } + if (ctx->callback) + ctx->callback (NM_MODEM (ctx->self), error, ctx->callback_user_data); + nm_g_object_unref (ctx->cancellable); g_object_unref (ctx->self); g_slice_free (DisconnectContext, ctx); } -static gboolean -disconnect_finish (NMModem *self, - GAsyncResult *result, - GError **error) +static void +disconnect_context_complete_on_idle (gpointer user_data, + GCancellable *cancellable) { - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); + DisconnectContext *ctx = NULL; + gs_free_error GError *error = NULL; + + if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) { + g_set_error_literal (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + ("modem is currently not connected")); + } + disconnect_context_complete (ctx, error); } static void @@ -177,16 +183,14 @@ disconnect_done (GObject *source, GAsyncResult *result, gpointer user_data) { - DisconnectContext *ctx = (DisconnectContext*) user_data; + DisconnectContext *ctx = user_data; NMModemOfono *self = ctx->self; gs_free_error GError *error = NULL; gs_unref_variant GVariant *v = NULL; v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - if (ctx->result) - g_simple_async_result_take_error (ctx->result, g_steal_pointer (&error)); - disconnect_context_complete (ctx); + disconnect_context_complete (ctx, error); return; } @@ -196,21 +200,21 @@ disconnect_done (GObject *source, _LOGD ("modem disconnected"); update_modem_state (self); - disconnect_context_complete (ctx); + disconnect_context_complete (ctx, error); } static void disconnect (NMModem *modem, gboolean warn, GCancellable *cancellable, - GAsyncReadyCallback callback, + _NMModemDisconnectCallback callback, gpointer user_data) { NMModemOfono *self = NM_MODEM_OFONO (modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); DisconnectContext *ctx; NMModemState state = nm_modem_get_state (NM_MODEM (self)); - GError *error = NULL; + gs_free_error GError *error = NULL; _LOGD ("warn: %s modem_state: %s", warn ? "TRUE" : "FALSE", @@ -218,37 +222,19 @@ disconnect (NMModem *modem, ctx = g_slice_new0 (DisconnectContext); ctx->self = g_object_ref (self); + ctx->cancellable = nm_g_object_ref (cancellable); ctx->warn = warn; - if (callback) { - ctx->result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - disconnect); - } - - if (state != NM_MODEM_STATE_CONNECTED) { - if (ctx->result) { - g_set_error_literal (&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - ("modem is currently not connected")); - g_simple_async_result_take_error (ctx->result, error); - } - disconnect_context_complete (ctx); + ctx->callback = callback; + ctx->callback_user_data = user_data; + + if ( state != NM_MODEM_STATE_CONNECTED + || g_cancellable_is_cancelled (cancellable)) { + nm_utils_invoke_on_idle (disconnect_context_complete_on_idle, + ctx, + cancellable); return; } - if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { - if (ctx->result) - g_simple_async_result_take_error (ctx->result, error); - else - g_clear_error (&error); - disconnect_context_complete (ctx); - return; - } - - ctx->cancellable = nm_g_object_ref (cancellable); - nm_modem_set_state (NM_MODEM (self), NM_MODEM_STATE_DISCONNECTING, nm_modem_state_to_string (NM_MODEM_STATE_DISCONNECTING)); @@ -266,7 +252,9 @@ disconnect (NMModem *modem, } static void -deactivate_cleanup (NMModem *modem, NMDevice *device) +deactivate_cleanup (NMModem *modem, + NMDevice *device, + gboolean stop_ppp_manager) { NMModemOfono *self = NM_MODEM_OFONO (modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); @@ -275,7 +263,9 @@ deactivate_cleanup (NMModem *modem, NMDevice *device) g_clear_object (&priv->ip4_config); - NM_MODEM_CLASS (nm_modem_ofono_parent_class)->deactivate_cleanup (modem, device); + NM_MODEM_CLASS (nm_modem_ofono_parent_class)->deactivate_cleanup (modem, + device, + stop_ppp_manager); } static gboolean @@ -1319,7 +1309,6 @@ nm_modem_ofono_class_init (NMModemOfonoClass *klass) modem_class->get_capabilities = get_capabilities; modem_class->disconnect = disconnect; - modem_class->disconnect_finish = disconnect_finish; modem_class->deactivate_cleanup = deactivate_cleanup; modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 59b081e980..56d9811645 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -1105,7 +1105,9 @@ nm_modem_complete_connection (NMModem *self, /*****************************************************************************/ static void -deactivate_cleanup (NMModem *self, NMDevice *device) +deactivate_cleanup (NMModem *self, + NMDevice *device, + gboolean stop_ppp_manager) { NMModemPrivate *priv; int ifindex; @@ -1126,7 +1128,8 @@ deactivate_cleanup (NMModem *self, NMDevice *device) if (priv->ppp_manager) { g_signal_handlers_disconnect_by_data (priv->ppp_manager, self); - nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); + if (stop_ppp_manager) + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL, NULL); g_clear_object (&priv->ppp_manager); } @@ -1157,189 +1160,109 @@ deactivate_cleanup (NMModem *self, NMDevice *device) /*****************************************************************************/ -typedef enum { - DEACTIVATE_CONTEXT_STEP_FIRST, - DEACTIVATE_CONTEXT_STEP_CLEANUP, - DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP, - DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT, - DEACTIVATE_CONTEXT_STEP_LAST -} DeactivateContextStep; - typedef struct { NMModem *self; NMDevice *device; GCancellable *cancellable; - GSimpleAsyncResult *result; - DeactivateContextStep step; - NMPPPManager *ppp_manager; - NMPPPManagerStopHandle *ppp_stop_handle; - gulong ppp_stop_cancellable_id; + NMModemDeactivateCallback callback; + gpointer callback_user_data; } DeactivateContext; static void -deactivate_context_complete (DeactivateContext *ctx) +deactivate_context_complete (DeactivateContext *ctx, GError *error) { - if (ctx->ppp_stop_handle) - nm_ppp_manager_stop_cancel (ctx->ppp_stop_handle); + NMModem *self = ctx->self; - nm_assert (!ctx->ppp_stop_handle); - nm_assert (ctx->ppp_stop_cancellable_id == 0); + _LOGD ("modem deactivation finished %s%s%s", + NM_PRINT_FMT_QUOTED (error, "with failure: ", error->message, "", "successfully")); - if (ctx->ppp_manager) - g_object_unref (ctx->ppp_manager); - if (ctx->cancellable) - g_object_unref (ctx->cancellable); - g_simple_async_result_complete_in_idle (ctx->result); - g_object_unref (ctx->result); + if (ctx->callback) + ctx->callback (ctx->self, error, ctx->callback_user_data); + nm_g_object_unref (ctx->cancellable); g_object_unref (ctx->device); g_object_unref (ctx->self); g_slice_free (DeactivateContext, ctx); } -gboolean -nm_modem_deactivate_async_finish (NMModem *self, - GAsyncResult *res, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); -} - -static void deactivate_step (DeactivateContext *ctx); - static void -disconnect_ready (NMModem *self, - GAsyncResult *res, - DeactivateContext *ctx) +_deactivate_call_disconnect_cb (NMModem *self, + GError *error, + gpointer user_data) { - GError *error = NULL; - - if (!NM_MODEM_GET_CLASS (self)->disconnect_finish (self, res, &error)) { - g_simple_async_result_take_error (ctx->result, error); - deactivate_context_complete (ctx); - return; - } - - /* Go on */ - ctx->step++; - deactivate_step (ctx); + deactivate_context_complete (user_data, error); } static void -ppp_manager_stop_ready (NMPPPManager *ppp_manager, - NMPPPManagerStopHandle *handle, - gboolean was_cancelled, - gpointer user_data) +_deactivate_call_disconnect (DeactivateContext *ctx) { - DeactivateContext *ctx = user_data; - - nm_assert (ctx->ppp_stop_handle == handle); - ctx->ppp_stop_handle = NULL; - - if (ctx->ppp_stop_cancellable_id) { - g_cancellable_disconnect (ctx->cancellable, - nm_steal_int (&ctx->ppp_stop_cancellable_id)); - } - - if (was_cancelled) - return; - - ctx->step++; - deactivate_step (ctx); + NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->self, + FALSE, + ctx->cancellable, + _deactivate_call_disconnect_cb, + ctx); } static void -ppp_manager_stop_cancelled (GCancellable *cancellable, - gpointer user_data) +_deactivate_ppp_manager_stop_cb (NMPPPManager *ppp_manager, + NMPPPManagerStopHandle *handle, + gboolean was_cancelled, + gpointer user_data) { DeactivateContext *ctx = user_data; - nm_ppp_manager_stop_cancel (ctx->ppp_stop_handle); -} - -static void -deactivate_step (DeactivateContext *ctx) -{ - NMModem *self = ctx->self; - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - GError *error = NULL; + g_object_unref (ppp_manager); - /* Check cancellable in each step */ - if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { - g_simple_async_result_take_error (ctx->result, error); - deactivate_context_complete (ctx); - return; - } - - switch (ctx->step) { - case DEACTIVATE_CONTEXT_STEP_FIRST: - ctx->step++; - /* fall through */ - case DEACTIVATE_CONTEXT_STEP_CLEANUP: - /* Make sure we keep a ref to the PPP manager if there is one */ - if (priv->ppp_manager) - ctx->ppp_manager = g_object_ref (priv->ppp_manager); - /* Run cleanup */ - NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, ctx->device); - ctx->step++; - /* fall through */ - case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP: - /* If we have a PPP manager, stop it */ - if (ctx->ppp_manager) { - nm_assert (!ctx->ppp_stop_handle); - if (ctx->cancellable) { - ctx->ppp_stop_cancellable_id = g_cancellable_connect (ctx->cancellable, - G_CALLBACK (ppp_manager_stop_cancelled), - ctx, - NULL); - } - ctx->ppp_stop_handle = nm_ppp_manager_stop (ctx->ppp_manager, - ppp_manager_stop_ready, - ctx); - return; - } - ctx->step++; - /* fall through */ - case DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT: - /* Disconnect asynchronously */ - NM_MODEM_GET_CLASS (self)->disconnect (self, - FALSE, - ctx->cancellable, - (GAsyncReadyCallback) disconnect_ready, - ctx); - return; + if (was_cancelled) { + gs_free_error GError *error = NULL; - case DEACTIVATE_CONTEXT_STEP_LAST: - _LOGD ("modem deactivation finished"); - deactivate_context_complete (ctx); + if (!g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) + nm_assert_not_reached (); + deactivate_context_complete (ctx, error); return; } - g_assert_not_reached (); + nm_assert (!g_cancellable_is_cancelled (ctx->cancellable)); + _deactivate_call_disconnect (ctx); } void nm_modem_deactivate_async (NMModem *self, NMDevice *device, GCancellable *cancellable, - GAsyncReadyCallback callback, + NMModemDeactivateCallback callback, gpointer user_data) { + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); DeactivateContext *ctx; + NMPPPManager *ppp_manager; + + g_return_if_fail (NM_IS_MODEM (self)); + g_return_if_fail (NM_IS_DEVICE (device)); + g_return_if_fail (G_IS_CANCELLABLE (cancellable)); - ctx = g_slice_new0 (DeactivateContext); + ctx = g_slice_new (DeactivateContext); ctx->self = g_object_ref (self); ctx->device = g_object_ref (device); - ctx->result = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - nm_modem_deactivate_async); - /* FIXME(shutdown): we always require a cancellable, otherwise we cannot - * do a coordinated shutdown. */ - ctx->cancellable = nm_g_object_ref (cancellable); + ctx->cancellable = g_object_ref (cancellable); + ctx->callback = callback; + ctx->callback_user_data = user_data; + + ppp_manager = nm_g_object_ref (priv->ppp_manager); + + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, ctx->device, FALSE); + + if (ppp_manager) { + /* If we have a PPP manager, stop it. + * + * Pass on the reference in @ppp_manager. */ + nm_ppp_manager_stop (ppp_manager, + ctx->cancellable, + _deactivate_ppp_manager_stop_cb, + ctx); + return; + } - /* Start */ - ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST; - deactivate_step (ctx); + _deactivate_call_disconnect (ctx); } /*****************************************************************************/ @@ -1348,7 +1271,7 @@ void nm_modem_deactivate (NMModem *self, NMDevice *device) { /* First cleanup */ - NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, device); + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, device, TRUE); /* Then disconnect without waiting */ NM_MODEM_GET_CLASS (self)->disconnect (self, FALSE, NULL, NULL, NULL); } @@ -1387,7 +1310,7 @@ nm_modem_device_state_changed (NMModem *self, if (new_state == NM_DEVICE_STATE_FAILED || new_state == NM_DEVICE_STATE_DISCONNECTED) warn = FALSE; /* First cleanup */ - NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, NULL); + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, NULL, TRUE); NM_MODEM_GET_CLASS (self)->disconnect (self, warn, NULL, NULL, NULL); } break; diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index c73745cef3..f7b6bfe959 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -109,6 +109,10 @@ struct _NMModem { typedef struct _NMModem NMModem; +typedef void (*_NMModemDisconnectCallback) (NMModem *modem, + GError *error, + gpointer user_data); + typedef struct { GObjectClass parent; @@ -149,13 +153,12 @@ typedef struct { void (*disconnect) (NMModem *self, gboolean warn, GCancellable *cancellable, - GAsyncReadyCallback callback, + _NMModemDisconnectCallback callback, gpointer user_data); - gboolean (*disconnect_finish) (NMModem *self, - GAsyncResult *res, - GError **error); - void (*deactivate_cleanup) (NMModem *self, NMDevice *device); + void (*deactivate_cleanup) (NMModem *self, + NMDevice *device, + gboolean stop_ppp_manager); gboolean (*owns_port) (NMModem *self, const char *iface); } NMModemClass; @@ -236,14 +239,15 @@ void nm_modem_get_secrets (NMModem *modem, void nm_modem_deactivate (NMModem *modem, NMDevice *device); +typedef void (*NMModemDeactivateCallback) (NMModem *self, + GError *error, + gpointer user_data); + void nm_modem_deactivate_async (NMModem *self, NMDevice *device, GCancellable *cancellable, - GAsyncReadyCallback callback, + NMModemDeactivateCallback callback, gpointer user_data); -gboolean nm_modem_deactivate_async_finish (NMModem *self, - GAsyncResult *res, - GError **error); void nm_modem_device_state_changed (NMModem *modem, NMDeviceState new_state, diff --git a/src/ppp/nm-ppp-manager-call.c b/src/ppp/nm-ppp-manager-call.c index 3d6fee49a0..8f6584167a 100644 --- a/src/ppp/nm-ppp-manager-call.c +++ b/src/ppp/nm-ppp-manager-call.c @@ -126,12 +126,13 @@ nm_ppp_manager_start (NMPPPManager *self, NMPPPManagerStopHandle * nm_ppp_manager_stop (NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data) { g_return_val_if_fail (ppp_ops, NULL); - return ppp_ops->stop (self, callback, user_data); + return ppp_ops->stop (self, cancellable, callback, user_data); } void diff --git a/src/ppp/nm-ppp-manager-call.h b/src/ppp/nm-ppp-manager-call.h index daf8a82e68..a93ed11fc0 100644 --- a/src/ppp/nm-ppp-manager-call.h +++ b/src/ppp/nm-ppp-manager-call.h @@ -40,6 +40,7 @@ gboolean nm_ppp_manager_start (NMPPPManager *self, GError **error); NMPPPManagerStopHandle *nm_ppp_manager_stop (NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data); diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index b231ff2059..1595961f45 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -137,9 +137,12 @@ G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, NM_TYPE_DBUS_OBJECT) static void _ppp_cleanup (NMPPPManager *self); static NMPPPManagerStopHandle *_ppp_manager_stop (NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data); +static void _ppp_manager_stop_cancel (NMPPPManagerStopHandle *handle); + /*****************************************************************************/ static void @@ -791,7 +794,7 @@ pppd_timed_out (gpointer data) NMPPPManager *self = NM_PPP_MANAGER (data); _LOGW ("pppd timed out or didn't initialize our dbus module"); - _ppp_manager_stop (self, NULL, NULL); + _ppp_manager_stop (self, NULL, NULL, NULL); g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); @@ -1170,6 +1173,10 @@ struct _NMPPPManagerStopHandle { * pppd process terminated. */ GObject *shutdown_waitobj; + GCancellable *cancellable; + + gulong cancellable_id; + guint idle_id; }; @@ -1179,6 +1186,13 @@ _stop_handle_complete (NMPPPManagerStopHandle *handle, gboolean was_cancelled) gs_unref_object NMPPPManager *self = NULL; NMPPPManagerStopCallback callback; + if (handle->cancellable_id) { + g_cancellable_disconnect (handle->cancellable, + nm_steal_int (&handle->cancellable_id)); + } + + g_clear_object (&handle->cancellable); + self = g_steal_pointer (&handle->self); if (!self) return; @@ -1219,8 +1233,20 @@ _stop_idle_cb (gpointer user_data) return G_SOURCE_REMOVE; } +static void +_stop_cancelled_cb (GCancellable *cancellable, + gpointer user_data) +{ + NMPPPManagerStopHandle *handle = user_data; + + nm_clear_g_signal_handler (handle->cancellable, + &handle->cancellable_id); + _ppp_manager_stop_cancel (handle); +} + static NMPPPManagerStopHandle * _ppp_manager_stop (NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data) { @@ -1246,6 +1272,13 @@ _ppp_manager_stop (NMPPPManager *self, handle->self = g_object_ref (self); handle->callback = callback; handle->user_data = user_data; + if (cancellable) { + handle->cancellable = g_object_ref (cancellable); + handle->cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (_stop_cancelled_cb), + handle, + NULL); + } if (!priv->pid) { /* No PID. There is nothing to kill, however, invoke the callback in @@ -1272,6 +1305,8 @@ _ppp_manager_stop (NMPPPManager *self, return handle; } +/*****************************************************************************/ + static void _ppp_manager_stop_cancel (NMPPPManagerStopHandle *handle) { @@ -1360,7 +1395,7 @@ dispose (GObject *object) * still stop. */ g_warn_if_fail (!priv->pid); g_warn_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); - _ppp_manager_stop (self, NULL, NULL); + _ppp_manager_stop (self, NULL, NULL, NULL); g_clear_object (&priv->act_req); diff --git a/src/ppp/nm-ppp-plugin-api.h b/src/ppp/nm-ppp-plugin-api.h index 558de2c2c2..95ddd21191 100644 --- a/src/ppp/nm-ppp-plugin-api.h +++ b/src/ppp/nm-ppp-plugin-api.h @@ -40,6 +40,7 @@ typedef const struct { GError **err); NMPPPManagerStopHandle *(*stop) (NMPPPManager *manager, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data); |