diff --git a/libfprint/drivers/virtual-device-private.h b/libfprint/drivers/virtual-device-private.h index 6049d66b..5f2371d8 100644 --- a/libfprint/drivers/virtual-device-private.h +++ b/libfprint/drivers/virtual-device-private.h @@ -76,6 +76,8 @@ struct _FpDeviceVirtualDevice GPtrArray *pending_commands; GHashTable *prints_storage; + + guint wait_command_id; }; /* Not really final here, but we can do this to share the FpDeviceVirtualDevice @@ -91,3 +93,5 @@ G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_st char * process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError **error); +gboolean should_wait_for_command (FpDeviceVirtualDevice *self, + GError *error); diff --git a/libfprint/drivers/virtual-device-storage.c b/libfprint/drivers/virtual-device-storage.c index aae0f33e..26d44970 100644 --- a/libfprint/drivers/virtual-device-storage.c +++ b/libfprint/drivers/virtual-device-storage.c @@ -36,14 +36,16 @@ G_DEFINE_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, static void dev_identify (FpDevice *dev) { + g_autoptr(GError) error = NULL; FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); GPtrArray *prints; - GError *error = NULL; g_autofree char *scan_id = NULL; fpi_device_get_identify_data (dev, &prints); scan_id = process_cmds (self, TRUE, &error); + if (should_wait_for_command (self, error)) + return; if (scan_id) { @@ -71,7 +73,7 @@ dev_identify (FpDevice *dev) NULL); } - fpi_device_identify_complete (dev, error); + fpi_device_identify_complete (dev, g_steal_pointer (&error)); } struct ListData diff --git a/libfprint/drivers/virtual-device.c b/libfprint/drivers/virtual-device.c index 5c143b19..1c131299 100644 --- a/libfprint/drivers/virtual-device.c +++ b/libfprint/drivers/virtual-device.c @@ -41,8 +41,34 @@ G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE) #define LIST_CMD "LIST" +static void +maybe_continue_current_action (FpDeviceVirtualDevice *self) +{ + FpDevice *dev = FP_DEVICE (self); + + switch (fpi_device_get_current_action (dev)) + { + case FPI_DEVICE_ACTION_ENROLL: + FP_DEVICE_GET_CLASS (self)->enroll (dev); + break; + + case FPI_DEVICE_ACTION_VERIFY: + FP_DEVICE_GET_CLASS (self)->verify (dev); + break; + + case FPI_DEVICE_ACTION_IDENTIFY: + FP_DEVICE_GET_CLASS (self)->identify (dev); + break; + + default: + break; + } +} + char * -process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError * *error) +process_cmds (FpDeviceVirtualDevice * self, + gboolean scan, + GError * *error) { while (self->pending_commands->len > 0) { @@ -96,7 +122,7 @@ process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError * *error) } /* No commands left, throw a timeout error. */ - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands left that can be run!"); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No commands left that can be run!"); return NULL; } @@ -120,7 +146,7 @@ recv_instruction_cb (GObject *source_object, gsize bytes; bytes = fp_device_virtual_listener_read_finish (listener, res, &error); - fp_dbg ("Got instructions of length %ld\n", bytes); + fp_dbg ("Got instructions of length %ld", bytes); if (error) { @@ -139,6 +165,7 @@ recv_instruction_cb (GObject *source_object, self = FP_DEVICE_VIRTUAL_DEVICE (user_data); cmd = g_strndup (self->recv_buf, bytes); + fp_dbg ("Received command %s", cmd); if (g_str_has_prefix (cmd, LIST_CMD)) { @@ -148,6 +175,9 @@ recv_instruction_cb (GObject *source_object, else { g_ptr_array_add (self->pending_commands, g_steal_pointer (&cmd)); + g_clear_handle_id (&self->wait_command_id, g_source_remove); + + maybe_continue_current_action (self); } } @@ -204,17 +234,46 @@ dev_init (FpDevice *dev) fpi_device_open_complete (dev, NULL); } +static gboolean +wait_for_command_timeout (gpointer data) +{ + FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data); + GError *error = NULL; + + self->wait_command_id = 0; + error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!"); + fpi_device_action_error (FP_DEVICE (self), error); + + return FALSE; +} + +gboolean +should_wait_for_command (FpDeviceVirtualDevice *self, + GError *error) +{ + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return FALSE; + + if (self->wait_command_id) + return FALSE; + + self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self); + return TRUE; +} + static void dev_verify (FpDevice *dev) { + g_autoptr(GError) error = NULL; FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); FpPrint *print; - GError *error = NULL; g_autofree char *scan_id = NULL; fpi_device_get_verify_data (dev, &print); scan_id = process_cmds (self, TRUE, &error); + if (should_wait_for_command (self, error)) + return; if (scan_id) { @@ -240,23 +299,25 @@ dev_verify (FpDevice *dev) } else { - g_debug ("Virtual device scann failed with error: %s", error->message); + g_debug ("Virtual device scan failed with error: %s", error->message); } - fpi_device_verify_complete (dev, error); + fpi_device_verify_complete (dev, g_steal_pointer (&error)); } static void dev_enroll (FpDevice *dev) { + g_autoptr(GError) error = NULL; FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); - GError *error = NULL; FpPrint *print = NULL; g_autofree char *id = NULL; fpi_device_get_enroll_data (dev, &print); id = process_cmds (self, TRUE, &error); + if (should_wait_for_command (self, error)) + return; if (id) { @@ -272,11 +333,11 @@ dev_enroll (FpDevice *dev) fpi_print_set_device_stored (print, TRUE); } - fpi_device_enroll_complete (dev, g_object_ref (print), error); + fpi_device_enroll_complete (dev, g_object_ref (print), NULL); } else { - fpi_device_enroll_complete (dev, NULL, error); + fpi_device_enroll_complete (dev, NULL, g_steal_pointer (&error)); } } @@ -285,6 +346,7 @@ dev_deinit (FpDevice *dev) { FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); + g_clear_handle_id (&self->wait_command_id, g_source_remove); g_cancellable_cancel (self->cancellable); g_clear_object (&self->cancellable); g_clear_object (&self->listener);