core: merge branch 'th/no-gasyncresult'

https://github.com/NetworkManager/NetworkManager/pull/227
This commit is contained in:
Thomas Haller 2018-10-17 13:03:57 +02:00
commit fd7115eeed
25 changed files with 596 additions and 475 deletions

View file

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

View file

@ -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;
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_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;
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;
}
/**

View file

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

View file

@ -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__ */

View file

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

View file

@ -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 {
priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
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);
g_simple_async_result_set_op_res_gpointer (result,
g_strdup (device),
g_free);
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);
g_simple_async_result_complete (result);
g_object_unref (result);
/* 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;
_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));
}
/*****************************************************************************/

View file

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

View file

@ -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,

View file

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

View file

@ -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_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),
bluez_connect_cb, g_object_ref (device));
nm_clear_g_source (&priv->timeout_id);
priv->timeout_id = g_timeout_add_seconds (30, bt_connect_timeout, device);
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);

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}
g_object_unref (task);
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;
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;
task = g_task_new (self, cancellable, callback, user_data);
nm_assert (G_IS_CANCELLABLE (cancellable));
nm_assert (callback);
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;

View file

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

View file

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

View file

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

View file

@ -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,36 +222,18 @@ disconnect (NMModem *modem,
ctx = g_slice_new0 (DisconnectContext);
ctx->self = g_object_ref (self);
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);
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);
ctx->warn = warn;
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;
}
nm_modem_set_state (NM_MODEM (self),
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;

View file

@ -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)
{
NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->self,
FALSE,
ctx->cancellable,
_deactivate_call_disconnect_cb,
ctx);
}
static void
_deactivate_ppp_manager_stop_cb (NMPPPManager *ppp_manager,
NMPPPManagerStopHandle *handle,
gboolean was_cancelled,
gpointer user_data)
{
DeactivateContext *ctx = user_data;
nm_assert (ctx->ppp_stop_handle == handle);
ctx->ppp_stop_handle = NULL;
g_object_unref (ppp_manager);
if (ctx->ppp_stop_cancellable_id) {
g_cancellable_disconnect (ctx->cancellable,
nm_steal_int (&ctx->ppp_stop_cancellable_id));
}
if (was_cancelled) {
gs_free_error GError *error = NULL;
if (was_cancelled)
return;
ctx->step++;
deactivate_step (ctx);
}
static void
ppp_manager_stop_cancelled (GCancellable *cancellable,
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;
/* 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);
if (!g_cancellable_set_error_if_cancelled (ctx->cancellable, &error))
nm_assert_not_reached ();
deactivate_context_complete (ctx, error);
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;
case DEACTIVATE_CONTEXT_STEP_LAST:
_LOGD ("modem deactivation finished");
deactivate_context_complete (ctx);
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;
ctx = g_slice_new0 (DeactivateContext);
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_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;
/* Start */
ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST;
deactivate_step (ctx);
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;
}
_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;

View file

@ -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,

View file

@ -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

View file

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

View file

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

View file

@ -40,6 +40,7 @@ typedef const struct {
GError **err);
NMPPPManagerStopHandle *(*stop) (NMPPPManager *manager,
GCancellable *cancellable,
NMPPPManagerStopCallback callback,
gpointer user_data);