diff --git a/src/device.c b/src/device.c index df26f3a..0151ca7 100644 --- a/src/device.c +++ b/src/device.c @@ -69,6 +69,20 @@ static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev, const char *username, DBusGMethodInvocation *context); +/* device opening/closing happens in an async manner, so we need + * some data to keep track of things */ + +typedef void (*DeviceAsyncCallback) (FprintDevice *rdev, + DBusGMethodInvocation *dbus_invocation, + gpointer user_data); +struct DeviceAsyncData { + FprintDevice *rdev; + DBusGMethodInvocation *dbus_invocation; + DeviceAsyncCallback callback; + gpointer user_data; +}; +typedef struct DeviceAsyncData DeviceAsyncData; + #include "device-dbus-glue.h" typedef enum { @@ -78,22 +92,10 @@ typedef enum { ACTION_ENROLL } FprintDeviceAction; -struct session_data { - /* finger being enrolled */ - int enroll_finger; - - /* method invocation for async ClaimDevice() */ - DBusGMethodInvocation *context_claim_device; - - /* method invocation for async ReleaseDevice() */ - DBusGMethodInvocation *context_release_device; -}; - struct FprintDevicePrivate { guint32 id; struct fp_dscv_dev *ddev; struct fp_dev *dev; - struct session_data *session; PolkitAuthority *auth; @@ -523,6 +525,31 @@ static void action_stop_cb(struct fp_dev *dev, void *user_data) *done = TRUE; } +static void action_stop(struct fp_dev *dev, FprintDeviceAction action) +{ + gboolean done = FALSE; + + switch (action) { + case ACTION_NONE: + break; + case ACTION_IDENTIFY: + fp_async_identify_stop(dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + break; + case ACTION_VERIFY: + fp_async_verify_stop(dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + break; + case ACTION_ENROLL: + fp_async_enroll_stop(dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + break; + } +} + static void _fprint_device_client_vanished (GDBusConnection *connection, const char *name, @@ -532,36 +559,21 @@ _fprint_device_client_vanished (GDBusConnection *connection, /* Was that the client that claimed the device? */ if (g_strcmp0 (priv->sender, name) == 0) { - gboolean done = FALSE; - switch (priv->current_action) { - case ACTION_NONE: - break; - case ACTION_IDENTIFY: - fp_async_identify_stop(priv->dev, action_stop_cb, &done); - while (done == FALSE) - g_main_context_iteration (NULL, TRUE); - break; - case ACTION_VERIFY: - fp_async_verify_stop(priv->dev, action_stop_cb, &done); - while (done == FALSE) - g_main_context_iteration (NULL, TRUE); - break; - case ACTION_ENROLL: - fp_async_enroll_stop(priv->dev, action_stop_cb, &done); - while (done == FALSE) - g_main_context_iteration (NULL, TRUE); - break; - } - priv->current_action = ACTION_NONE; - done = FALSE; - /* Close the claimed device as well */ + /* Stop any ongoing action and then close the claimed + * device as well, if opened */ if (priv->dev) { + gboolean done = FALSE; + + action_stop(priv->dev, priv->current_action); + fp_async_dev_close (priv->dev, action_stop_cb, &done); while (done == FALSE) g_main_context_iteration (NULL, TRUE); } + priv->current_action = ACTION_NONE; + g_free (priv->sender); priv->sender = NULL; g_free (priv->username); @@ -596,26 +608,86 @@ _fprint_device_add_client (FprintDevice *rdev, const char *sender) static void dev_open_cb(struct fp_dev *dev, int status, void *user_data) { - FprintDevice *rdev = user_data; + DeviceAsyncData *ctx = user_data; + FprintDevice *rdev = ctx->rdev; FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); - struct session_data *session = priv->session; - g_message("device %d claim status %d", priv->id, status); + g_message("device %d open status %d", priv->id, status); if (status != 0) { - GError *error; + GError *error = NULL; g_free (priv->sender); priv->sender = NULL; g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, "Open failed with error %d", status); - dbus_g_method_return_error(session->context_claim_device, error); - return; + dbus_g_method_return_error(ctx->dbus_invocation, error); + g_error_free (error); + + } else if (priv->current_action == ACTION_NONE) { + GError *error = NULL; + + /* we have successfully opened the device, but + * the action that started the opening process + * got stopped midway or the client vanished + * in the latter case (sender == NULL) we close + * the device again. */ + + if (priv->sender == NULL) { + gboolean done = FALSE; + fp_async_dev_close(dev, action_stop_cb, ctx); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + } + + g_set_error_literal(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, + "Action got interrupted"); + + dbus_g_method_return_error(ctx->dbus_invocation, error); + g_error_free (error); + + } else { + priv->dev = dev; + ctx->callback(rdev, ctx->dbus_invocation, ctx->user_data); + } + + g_slice_free(DeviceAsyncData, ctx); +} + +static gboolean fprint_device_open_start(FprintDevice *rdev, + DBusGMethodInvocation *context, + DeviceAsyncCallback callback, + gpointer user_data, + GError **error) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + DeviceAsyncData *async_data; + int r; + + /* if we are already open, we call back immediately */ + if (priv->dev != NULL) { + callback(rdev, context, user_data); + return TRUE; + } + + g_message("opening the device: %d", priv->id); + + async_data = g_slice_new0(DeviceAsyncData); + async_data->user_data = user_data; + async_data->callback = callback; + async_data->dbus_invocation = context; + async_data->rdev = rdev; + + r = fp_async_dev_open(priv->ddev, dev_open_cb, async_data); + if (r < 0) { + g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, + "Could not attempt device open, error %d", r); + g_slice_free(DeviceAsyncData, async_data); + return FALSE; } - priv->dev = dev; - dbus_g_method_return(session->context_claim_device); + return TRUE; } static void fprint_device_claim(FprintDevice *rdev, @@ -625,7 +697,6 @@ static void fprint_device_claim(FprintDevice *rdev, FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); GError *error = NULL; char *sender, *user; - int r; /* Is it already claimed? */ if (priv->sender != NULL) { @@ -666,37 +737,20 @@ static void fprint_device_claim(FprintDevice *rdev, priv->username = user; priv->sender = sender; - g_message ("user '%s' claiming the device: %d", priv->username, priv->id); - - priv->session = g_slice_new0(struct session_data); - priv->session->context_claim_device = context; - - r = fp_async_dev_open(priv->ddev, dev_open_cb, rdev); - if (r < 0) { - g_slice_free(struct session_data, priv->session); - priv->session = NULL; - - g_free (priv->username); - priv->username = NULL; - g_free (priv->sender); - priv->sender = NULL; - - g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, - "Could not attempt device open, error %d", r); - dbus_g_method_return_error(context, error); - } + g_message("user '%s' claiming the device: %d", priv->username, priv->id); + dbus_g_method_return(context); } static void dev_close_cb(struct fp_dev *dev, void *user_data) { - FprintDevice *rdev = user_data; + DeviceAsyncData *data = user_data; + FprintDevice *rdev = data->rdev; FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); - struct session_data *session = priv->session; - DBusGMethodInvocation *context = session->context_release_device; + DBusGMethodInvocation *context = data->dbus_invocation; + + g_slice_free(DeviceAsyncData, data); priv->dev = NULL; - g_slice_free(struct session_data, session); - priv->session = NULL; g_free (priv->sender); priv->sender = NULL; @@ -712,7 +766,6 @@ static void fprint_device_release(FprintDevice *rdev, DBusGMethodInvocation *context) { FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); - struct session_data *session = priv->session; GError *error = NULL; if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { @@ -729,11 +782,19 @@ static void fprint_device_release(FprintDevice *rdev, return; } - session->context_release_device = context; - if (priv->dev) - fp_async_dev_close(priv->dev, dev_close_cb, rdev); + if (priv->dev) { + DeviceAsyncData *async_data; + + async_data = g_slice_new0(DeviceAsyncData); + async_data->dbus_invocation = context; + async_data->rdev = rdev; + fp_async_dev_close(priv->dev, dev_close_cb, async_data); + } else { + dbus_g_method_return(context); + } } +/* fingerprint verification */ static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img, void *user_data) { @@ -785,42 +846,16 @@ static void identify_cb(struct fp_dev *dev, int r, } } -static void fprint_device_verify_start(FprintDevice *rdev, - const char *finger_name, DBusGMethodInvocation *context) +static void verify_open_done(FprintDevice *rdev, + DBusGMethodInvocation *context, gpointer user_data) { FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); struct fp_print_data **gallery = NULL; struct fp_print_data *data = NULL; GError *error = NULL; - guint finger_num = finger_name_to_num (finger_name); + guint finger_num = GPOINTER_TO_UINT(user_data); int r; - if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - if (priv->current_action != ACTION_NONE) { - if (priv->current_action == ACTION_ENROLL) { - g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, - "Enrollment in progress"); - } else { - g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, - "Verification already in progress"); - } - dbus_g_method_return_error(context, error); - g_error_free (error); - return; - } - priv->action_done = FALSE; - if (finger_num == -1) { GSList *prints; @@ -914,6 +949,49 @@ static void fprint_device_verify_start(FprintDevice *rdev, dbus_g_method_return(context); } +static void fprint_device_verify_start(FprintDevice *rdev, + const char *finger_name, DBusGMethodInvocation *context) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + GError *error = NULL; + guint finger_num = finger_name_to_num (finger_name); + + if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + if (priv->current_action != ACTION_NONE) { + if (priv->current_action == ACTION_ENROLL) { + g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, + "Enrollment in progress"); + } else { + g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, + "Verification already in progress"); + } + dbus_g_method_return_error(context, error); + g_error_free (error); + return; + } + + priv->current_action = ACTION_VERIFY; + priv->action_done = FALSE; + + if (fprint_device_open_start (rdev, context, verify_open_done, + GUINT_TO_POINTER(finger_num), &error) == FALSE) { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } +} + static void verify_stop_cb(struct fp_dev *dev, void *user_data) { dbus_g_method_return((DBusGMethodInvocation *) user_data); @@ -941,6 +1019,15 @@ static void fprint_device_verify_stop(FprintDevice *rdev, return; } + /* device has not been opened yet, i.e. verification + * process has not started yet, indicate that we don't + * want to start it and we are done. */ + if (priv->dev == NULL) { + priv->current_action = ACTION_NONE; + dbus_g_method_return(context); + return; + } + if (priv->current_action == ACTION_VERIFY) { if (priv->verify_data) { fp_print_data_free (priv->verify_data); @@ -982,12 +1069,19 @@ static void fprint_device_verify_stop(FprintDevice *rdev, priv->current_action = ACTION_NONE; } +/* fingerprint enrollment */ +struct EnrollData { + FprintDevice *rdev; + int finger_num; +}; +typedef struct EnrollData EnrollData; + static void enroll_stage_cb(struct fp_dev *dev, int result, struct fp_print_data *print, struct fp_img *img, void *user_data) { - struct FprintDevice *rdev = user_data; + EnrollData *data = user_data; + struct FprintDevice *rdev = data->rdev; FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); - struct session_data *session = priv->session; const char *name = enroll_result_to_name (result); int r; @@ -997,13 +1091,15 @@ static void enroll_stage_cb(struct fp_dev *dev, int result, g_message("enroll_stage_cb: result %d", result); if (result == FP_ENROLL_COMPLETE) { - r = store.print_data_save(print, session->enroll_finger, priv->username); + r = store.print_data_save(print, data->finger_num, priv->username); if (r < 0) result = FP_ENROLL_FAIL; } - if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0) + if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0) { priv->action_done = TRUE; + g_slice_free(EnrollData, data); + } set_disconnected (priv, name); g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, priv->action_done); @@ -1012,14 +1108,37 @@ static void enroll_stage_cb(struct fp_dev *dev, int result, fp_print_data_free(print); } +static void enroll_open_done(FprintDevice *rdev, + DBusGMethodInvocation *context, gpointer user_data) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + EnrollData *data; + GError *error = NULL; + int r; + + data = g_slice_new0(EnrollData); + data->rdev = rdev; + data->finger_num = GPOINTER_TO_INT(user_data); + r = fp_async_enroll_start(priv->dev, enroll_stage_cb, data); + if (r < 0) { + g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, + "Enroll start failed with error %d", r); + dbus_g_method_return_error(context, error); + g_slice_free(EnrollData, data); + return; + } + + priv->current_action = ACTION_ENROLL; + + dbus_g_method_return(context); +} + static void fprint_device_enroll_start(FprintDevice *rdev, const char *finger_name, DBusGMethodInvocation *context) { FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); - struct session_data *session = priv->session; int finger_num = finger_name_to_num (finger_name); GError *error = NULL; - int r; if (finger_num == -1) { g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME, @@ -1053,20 +1172,15 @@ static void fprint_device_enroll_start(FprintDevice *rdev, } g_message("start enrollment device %d finger %d", priv->id, finger_num); - session->enroll_finger = finger_num; priv->action_done = FALSE; - - r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev); - if (r < 0) { - g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, - "Enroll start failed with error %d", r); - dbus_g_method_return_error(context, error); - return; - } - priv->current_action = ACTION_ENROLL; - dbus_g_method_return(context); + if (fprint_device_open_start (rdev, context, enroll_open_done, + GUINT_TO_POINTER(finger_num), &error) == FALSE) { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } } static void enroll_stop_cb(struct fp_dev *dev, void *user_data) @@ -1091,6 +1205,15 @@ static void fprint_device_enroll_stop(FprintDevice *rdev, return; } + /* device has not been opened yet, i.e. verification + * process has not started yet, indicate that we don't + * want to start it and we are done. */ + if (priv->dev == NULL) { + priv->current_action = ACTION_NONE; + dbus_g_method_return(context); + return; + } + if (priv->current_action != ACTION_ENROLL) { g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS, "No enrollment in progress");