[gnome-remote-desktop] session-rdp: Add API to subscribe to DVC creation statuses
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-remote-desktop] session-rdp: Add API to subscribe to DVC creation statuses
- Date: Mon, 1 Aug 2022 17:34:42 +0000 (UTC)
commit a15d73d0bdb7523b3f6bbe2b952f7a9c764ba692
Author: Pascal Nowack <Pascal Nowack gmx de>
Date: Tue Jun 7 08:36:36 2022 +0200
session-rdp: Add API to subscribe to DVC creation statuses
Opening a dynamic virtual channel (DVC) is not an instant action.
Instead, the server side sends a DVC Create Request PDU
(DYNVC_CREATE_REQ) and the client side answer with a DVC Create
Response PDU (DYNVC_CREATE_RSP).
Only if the creation status value is non-negative, the creation was
successful.
With the latest FreeRDP stable update, it is now possible to get
notified of that creation status.
So, use that API in FreeRDP to add an API in gnome-remote-desktop to
allow DVCs to subscribe to their creation status.
This API will later be used by DVCs implemented in
gnome-remote-desktop.
src/grd-session-rdp.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/grd-session-rdp.h | 12 +++
2 files changed, 252 insertions(+)
---
diff --git a/src/grd-session-rdp.c b/src/grd-session-rdp.c
index 63e0bfc5..26a4df57 100644
--- a/src/grd-session-rdp.c
+++ b/src/grd-session-rdp.c
@@ -74,6 +74,23 @@ typedef enum _PauseKeyState
PAUSE_KEY_STATE_CTRL_UP,
} PauseKeyState;
+typedef struct _DVCSubscription
+{
+ gboolean notified;
+
+ GrdRdpDVCCreationStatusCallback callback;
+ gpointer user_data;
+} DVCSubscription;
+
+typedef struct _DVCNotification
+{
+ int32_t creation_status;
+ gboolean pending_status;
+
+ GHashTable *subscriptions;
+ uint32_t next_subscription_id;
+} DVCNotification;
+
typedef struct _Pointer
{
uint8_t *bitmap;
@@ -134,6 +151,10 @@ struct _GrdSessionRdp
GThread *graphics_thread;
GMainContext *graphics_context;
+ GMutex dvc_notification_mutex;
+ GHashTable *dvc_table;
+ GSource *dvc_notification_source;
+
GrdRdpSurface *rdp_surface;
Pointer *last_pointer;
GHashTable *pointer_cache;
@@ -650,6 +671,110 @@ grd_session_rdp_notify_error (GrdSessionRdp *session_rdp,
maybe_queue_close_session_idle (session_rdp);
}
+static DVCNotification *
+dvc_notification_new (void)
+{
+ DVCNotification *dvc_notification;
+
+ dvc_notification = g_new0 (DVCNotification, 1);
+ dvc_notification->pending_status = TRUE;
+ dvc_notification->subscriptions = g_hash_table_new_full (NULL, NULL,
+ NULL, g_free);
+
+ return dvc_notification;
+}
+
+static uint32_t
+get_next_free_dvc_subscription_id (DVCNotification *dvc_notification)
+{
+ uint32_t subscription_id = dvc_notification->next_subscription_id;
+
+ while (g_hash_table_contains (dvc_notification->subscriptions,
+ GUINT_TO_POINTER (subscription_id)))
+ ++subscription_id;
+
+ dvc_notification->next_subscription_id = subscription_id + 1;
+
+ return subscription_id;
+}
+
+static uint32_t
+dvc_notification_add_subscription (DVCNotification *dvc_notification,
+ DVCSubscription *dvc_subscription)
+{
+ uint32_t subscription_id;
+
+ subscription_id = get_next_free_dvc_subscription_id (dvc_notification);
+ g_hash_table_insert (dvc_notification->subscriptions,
+ GUINT_TO_POINTER (subscription_id), dvc_subscription);
+
+ return subscription_id;
+}
+
+uint32_t
+grd_session_rdp_subscribe_dvc_creation_status (GrdSessionRdp *session_rdp,
+ uint32_t channel_id,
+ GrdRdpDVCCreationStatusCallback callback,
+ gpointer callback_user_data)
+{
+ DVCNotification *dvc_notification;
+ g_autofree DVCSubscription *dvc_subscription = NULL;
+ uint32_t subscription_id;
+ gboolean pending_notification = FALSE;
+
+ dvc_subscription = g_new0 (DVCSubscription, 1);
+ dvc_subscription->callback = callback;
+ dvc_subscription->user_data = callback_user_data;
+
+ g_mutex_lock (&session_rdp->dvc_notification_mutex);
+ if (g_hash_table_lookup_extended (session_rdp->dvc_table,
+ GUINT_TO_POINTER (channel_id),
+ NULL, (gpointer *) &dvc_notification))
+ {
+ subscription_id =
+ dvc_notification_add_subscription (dvc_notification,
+ g_steal_pointer (&dvc_subscription));
+
+ if (!dvc_notification->pending_status)
+ pending_notification = TRUE;
+ }
+ else
+ {
+ dvc_notification = dvc_notification_new ();
+
+ subscription_id =
+ dvc_notification_add_subscription (dvc_notification,
+ g_steal_pointer (&dvc_subscription));
+
+ g_hash_table_insert (session_rdp->dvc_table,
+ GUINT_TO_POINTER (channel_id), dvc_notification);
+ }
+ g_mutex_unlock (&session_rdp->dvc_notification_mutex);
+
+ if (pending_notification)
+ g_source_set_ready_time (session_rdp->dvc_notification_source, 0);
+
+ return subscription_id;
+}
+
+void
+grd_session_rdp_unsubscribe_dvc_creation_status (GrdSessionRdp *session_rdp,
+ uint32_t channel_id,
+ uint32_t subscription_id)
+{
+ DVCNotification *dvc_notification;
+
+ g_mutex_lock (&session_rdp->dvc_notification_mutex);
+ if (!g_hash_table_lookup_extended (session_rdp->dvc_table,
+ GUINT_TO_POINTER (channel_id),
+ NULL, (gpointer *) &dvc_notification))
+ g_assert_not_reached ();
+
+ g_hash_table_remove (dvc_notification->subscriptions,
+ GUINT_TO_POINTER (subscription_id));
+ g_mutex_unlock (&session_rdp->dvc_notification_mutex);
+}
+
void
grd_session_rdp_tear_down_channel (GrdSessionRdp *session_rdp,
GrdRdpChannel channel)
@@ -1848,6 +1973,56 @@ rdp_peer_context_free (freerdp_peer *peer,
g_mutex_clear (&rdp_peer_context->channel_mutex);
}
+static BOOL
+dvc_creation_status (void *user_data,
+ uint32_t channel_id,
+ int32_t creation_status)
+{
+ RdpPeerContext *rdp_peer_context = user_data;
+ GrdSessionRdp *session_rdp = rdp_peer_context->session_rdp;
+ DVCNotification *dvc_notification;
+ gboolean pending_notification = FALSE;
+
+ g_debug ("[RDP.DRDYNVC] DVC channel id %u creation status: %i",
+ channel_id, creation_status);
+
+ g_mutex_lock (&session_rdp->dvc_notification_mutex);
+ if (g_hash_table_lookup_extended (session_rdp->dvc_table,
+ GUINT_TO_POINTER (channel_id),
+ NULL, (gpointer *) &dvc_notification))
+ {
+ if (dvc_notification->pending_status)
+ {
+ dvc_notification->creation_status = creation_status;
+ dvc_notification->pending_status = FALSE;
+
+ if (g_hash_table_size (dvc_notification->subscriptions) > 0)
+ pending_notification = TRUE;
+ }
+ else
+ {
+ g_warning ("[RDP.DRDYNVC] Status of channel %u already known. "
+ "Discarding result", channel_id);
+ }
+ }
+ else
+ {
+ dvc_notification = dvc_notification_new ();
+
+ dvc_notification->creation_status = creation_status;
+ dvc_notification->pending_status = FALSE;
+
+ g_hash_table_insert (session_rdp->dvc_table,
+ GUINT_TO_POINTER (channel_id), dvc_notification);
+ }
+ g_mutex_unlock (&session_rdp->dvc_notification_mutex);
+
+ if (pending_notification)
+ g_source_set_ready_time (session_rdp->dvc_notification_source, 0);
+
+ return TRUE;
+}
+
static BOOL
rdp_peer_context_new (freerdp_peer *peer,
RdpPeerContext *rdp_peer_context)
@@ -1889,6 +2064,10 @@ rdp_peer_context_new (freerdp_peer *peer,
return FALSE;
}
+ WTSVirtualChannelManagerSetDVCCreationCallback (rdp_peer_context->vcm,
+ dvc_creation_status,
+ rdp_peer_context);
+
return TRUE;
}
@@ -2207,6 +2386,11 @@ clear_session_sources (GrdSessionRdp *session_rdp)
g_source_destroy (session_rdp->pending_encode_source);
g_clear_pointer (&session_rdp->pending_encode_source, g_source_unref);
}
+ if (session_rdp->dvc_notification_source)
+ {
+ g_source_destroy (session_rdp->dvc_notification_source);
+ g_clear_pointer (&session_rdp->dvc_notification_source, g_source_unref);
+ }
}
static gboolean
@@ -2451,6 +2635,7 @@ grd_session_rdp_dispose (GObject *object)
g_clear_pointer (&session_rdp->pressed_unicode_keys, g_hash_table_unref);
g_clear_pointer (&session_rdp->pressed_keys, g_hash_table_unref);
g_clear_pointer (&session_rdp->pointer_cache, g_hash_table_unref);
+ g_clear_pointer (&session_rdp->dvc_table, g_hash_table_unref);
g_clear_pointer (&session_rdp->stop_event, CloseHandle);
@@ -2464,6 +2649,7 @@ grd_session_rdp_finalize (GObject *object)
g_mutex_clear (&session_rdp->monitor_config_mutex);
g_mutex_clear (&session_rdp->close_session_mutex);
+ g_mutex_clear (&session_rdp->dvc_notification_mutex);
g_mutex_clear (&session_rdp->rdp_flags_mutex);
g_mutex_clear (&session_rdp->pending_jobs_mutex);
g_cond_clear (&session_rdp->pending_jobs_cond);
@@ -2471,6 +2657,16 @@ grd_session_rdp_finalize (GObject *object)
G_OBJECT_CLASS (grd_session_rdp_parent_class)->finalize (object);
}
+static void
+dvc_notification_free (gpointer data)
+{
+ DVCNotification *dvc_notification = data;
+
+ g_clear_pointer (&dvc_notification->subscriptions, g_hash_table_unref);
+
+ g_free (dvc_notification);
+}
+
static gboolean
are_pointer_bitmaps_equal (gconstpointer a,
gconstpointer b)
@@ -2497,6 +2693,40 @@ are_pointer_bitmaps_equal (gconstpointer a,
return TRUE;
}
+static gboolean
+notify_channels (gpointer user_data)
+{
+ GrdSessionRdp *session_rdp = user_data;
+ GHashTableIter iter;
+ DVCNotification *dvc_notification;
+
+ g_mutex_lock (&session_rdp->dvc_notification_mutex);
+ g_hash_table_iter_init (&iter, session_rdp->dvc_table);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &dvc_notification))
+ {
+ GHashTableIter iter2;
+ DVCSubscription *dvc_subscription;
+
+ if (dvc_notification->pending_status)
+ continue;
+
+ g_hash_table_iter_init (&iter2, dvc_notification->subscriptions);
+ while (g_hash_table_iter_next (&iter2, NULL, (gpointer *) &dvc_subscription))
+ {
+ if (dvc_subscription->notified)
+ continue;
+
+ dvc_subscription->callback (dvc_subscription->user_data,
+ dvc_notification->creation_status);
+
+ dvc_subscription->notified = TRUE;
+ }
+ }
+ g_mutex_unlock (&session_rdp->dvc_notification_mutex);
+
+ return G_SOURCE_CONTINUE;
+}
+
static gboolean
encode_pending_frames (gpointer user_data)
{
@@ -2550,6 +2780,8 @@ grd_session_rdp_init (GrdSessionRdp *session_rdp)
{
session_rdp->stop_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ session_rdp->dvc_table = g_hash_table_new_full (NULL, NULL,
+ NULL, dvc_notification_free);
session_rdp->pointer_cache = g_hash_table_new (NULL, are_pointer_bitmaps_equal);
session_rdp->pressed_keys = g_hash_table_new (NULL, NULL);
session_rdp->pressed_unicode_keys = g_hash_table_new (NULL, NULL);
@@ -2557,6 +2789,7 @@ grd_session_rdp_init (GrdSessionRdp *session_rdp)
g_cond_init (&session_rdp->pending_jobs_cond);
g_mutex_init (&session_rdp->pending_jobs_mutex);
g_mutex_init (&session_rdp->rdp_flags_mutex);
+ g_mutex_init (&session_rdp->dvc_notification_mutex);
g_mutex_init (&session_rdp->close_session_mutex);
g_mutex_init (&session_rdp->monitor_config_mutex);
@@ -2564,6 +2797,13 @@ grd_session_rdp_init (GrdSessionRdp *session_rdp)
session_rdp->graphics_context = g_main_context_new ();
+ session_rdp->dvc_notification_source = g_source_new (&session_source_funcs,
+ sizeof (GSource));
+ g_source_set_callback (session_rdp->dvc_notification_source,
+ notify_channels, session_rdp, NULL);
+ g_source_set_ready_time (session_rdp->dvc_notification_source, -1);
+ g_source_attach (session_rdp->dvc_notification_source, NULL);
+
session_rdp->pending_encode_source = g_source_new (&session_source_funcs,
sizeof (GSource));
g_source_set_callback (session_rdp->pending_encode_source,
diff --git a/src/grd-session-rdp.h b/src/grd-session-rdp.h
index 9ff709f0..6c750ead 100644
--- a/src/grd-session-rdp.h
+++ b/src/grd-session-rdp.h
@@ -45,6 +45,9 @@ typedef enum _GrdRdpChannel
GRD_RDP_CHANNEL_NONE,
} GrdRdpChannel;
+typedef void (* GrdRdpDVCCreationStatusCallback) (gpointer user_data,
+ int32_t creation_status);
+
GrdSessionRdp *grd_session_rdp_new (GrdRdpServer *rdp_server,
GSocketConnection *connection,
GrdHwAccelNvidia *hwaccel_nvidia);
@@ -52,6 +55,15 @@ GrdSessionRdp *grd_session_rdp_new (GrdRdpServer *rdp_server,
void grd_session_rdp_notify_error (GrdSessionRdp *session_rdp,
GrdSessionRdpError error_info);
+uint32_t grd_session_rdp_subscribe_dvc_creation_status (GrdSessionRdp *session_rdp,
+ uint32_t channel_id,
+ GrdRdpDVCCreationStatusCallback callback,
+ gpointer callback_user_data);
+
+void grd_session_rdp_unsubscribe_dvc_creation_status (GrdSessionRdp *session_rdp,
+ uint32_t channel_id,
+ uint32_t subscription_id);
+
void grd_session_rdp_tear_down_channel (GrdSessionRdp *session_rdp,
GrdRdpChannel channel);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]