From 6f2b12447259c370076497f90fd22acfffe6ff07 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 21 Dec 2019 17:44:43 -0800 Subject: [PATCH] GUACAMOLE-249: Migrate RDPSND support to FreeRDP 2.0.0 plugin API. --- src/protocols/rdp/Makefile.am | 40 +-- .../rdp/guac_rdpsnd/rdpsnd_messages.c | 41 +-- .../rdp/guac_rdpsnd/rdpsnd_messages.h | 14 +- .../rdp/guac_rdpsnd/rdpsnd_service.c | 311 ++++++++++++++---- .../rdp/guac_rdpsnd/rdpsnd_service.h | 72 ++-- 5 files changed, 333 insertions(+), 145 deletions(-) diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am index 10029c14..a5eb77f2 100644 --- a/src/protocols/rdp/Makefile.am +++ b/src/protocols/rdp/Makefile.am @@ -130,9 +130,9 @@ libguac_client_rdp_la_LIBADD = \ freerdp_LTLIBRARIES = \ libguacai-client.la \ + libguacsnd-client.la \ libguacsvc-client.la # libguacdr-client.la -# libguacsnd-client.la freerdpdir = ${libdir}/freerdp2 @@ -200,25 +200,25 @@ libguacai_client_la_LIBADD = \ # RDPSND # -#libguacsnd_client_la_SOURCES = \ -# guac_rdpsnd/rdpsnd_messages.c \ -# guac_rdpsnd/rdpsnd_service.c -# -#libguacsnd_client_la_CFLAGS = \ -# -Werror -Wall -Iinclude \ -# @COMMON_INCLUDE@ \ -# @COMMON_SSH_INCLUDE@ \ -# @LIBGUAC_INCLUDE@ \ -# @RDP_CFLAGS@ -# -#libguacsnd_client_la_LDFLAGS = \ -# -module -avoid-version -shared \ -# @PTHREAD_LIBS@ \ -# @RDP_LIBS@ -# -#libguacsnd_client_la_LIBADD = \ -# @COMMON_LTLIB@ \ -# @LIBGUAC_LTLIB@ +libguacsnd_client_la_SOURCES = \ + guac_rdpsnd/rdpsnd_messages.c \ + guac_rdpsnd/rdpsnd_service.c + +libguacsnd_client_la_CFLAGS = \ + -Werror -Wall -Iinclude \ + @COMMON_INCLUDE@ \ + @COMMON_SSH_INCLUDE@ \ + @LIBGUAC_INCLUDE@ \ + @RDP_CFLAGS@ + +libguacsnd_client_la_LDFLAGS = \ + -module -avoid-version -shared \ + @PTHREAD_LIBS@ \ + @RDP_LIBS@ + +libguacsnd_client_la_LIBADD = \ + @COMMON_LTLIB@ \ + @LIBGUAC_LTLIB@ # # Static Virtual Channels diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c b/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c index 4893ad49..90c59a18 100644 --- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c +++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -34,7 +33,7 @@ /* MESSAGE HANDLERS */ -void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_formats_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header) { int server_format_count; @@ -182,8 +181,9 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd, Stream_SetPointer(output_stream, output_stream_end); /* Send accepted formats */ - pthread_mutex_lock(&(rdp_client->rdp_lock)); - svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream); + rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle, + rdpsnd->open_handle, Stream_Buffer(output_stream), + Stream_GetPosition(output_stream), output_stream); /* If version greater than 6, must send Quality Mode PDU */ if (server_version >= 6) { @@ -196,24 +196,21 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd, Stream_Write_UINT16(output_stream, HIGH_QUALITY); Stream_Write_UINT16(output_stream, 0); - svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream); - } + rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle, + rdpsnd->open_handle, Stream_Buffer(output_stream), + Stream_GetPosition(output_stream), output_stream); - pthread_mutex_unlock(&(rdp_client->rdp_lock)); + } } /* server is getting a feel of the round trip time */ -void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_training_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header) { int data_size; wStream* output_stream; - /* Get associated client data */ - guac_client* client = rdpsnd->client; - guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; - /* Read timestamp and data size */ Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp); Stream_Read_UINT16(input_stream, data_size); @@ -226,13 +223,13 @@ void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd, Stream_Write_UINT16(output_stream, rdpsnd->server_timestamp); Stream_Write_UINT16(output_stream, data_size); - pthread_mutex_lock(&(rdp_client->rdp_lock)); - svc_plugin_send((rdpSvcPlugin*) rdpsnd, output_stream); - pthread_mutex_unlock(&(rdp_client->rdp_lock)); + rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle, + rdpsnd->open_handle, Stream_Buffer(output_stream), + Stream_GetPosition(output_stream), output_stream); } -void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_wave_info_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header) { int format; @@ -270,11 +267,9 @@ void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd, } -void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_wave_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header) { - rdpSvcPlugin* plugin = (rdpSvcPlugin*)rdpsnd; - /* Get associated client data */ guac_client* client = rdpsnd->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; @@ -307,16 +302,16 @@ void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd, Stream_Write_UINT8(output_stream, 0); /* Send Wave Confirmation PDU */ - pthread_mutex_lock(&(rdp_client->rdp_lock)); - svc_plugin_send(plugin, output_stream); - pthread_mutex_unlock(&(rdp_client->rdp_lock)); + rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle, + rdpsnd->open_handle, Stream_Buffer(output_stream), + Stream_GetPosition(output_stream), output_stream); /* We no longer expect to receive wave data */ rdpsnd->next_pdu_is_wave = FALSE; } -void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_close_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header) { /* Do nothing */ diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.h b/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.h index 5fceca77..700c41b6 100644 --- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.h +++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.h @@ -18,8 +18,8 @@ */ -#ifndef __GUAC_RDPSND_MESSAGES_H -#define __GUAC_RDPSND_MESSAGES_H +#ifndef GUAC_RDPSND_MESSAGES_H +#define GUAC_RDPSND_MESSAGES_H #include "config.h" @@ -128,7 +128,7 @@ typedef struct guac_rdpsnd_pdu_header { * The header content of the SNDC_FORMATS PDU. All RDPSND messages contain * the same header information. */ -void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_formats_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header); /** @@ -149,7 +149,7 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd, * The header content of the SNDC_TRAINING PDU. All RDPSND messages contain * the same header information. */ -void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_training_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header); /** @@ -172,7 +172,7 @@ void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd, * The header content of the SNDC_WAVE PDU. All RDPSND messages contain * the same header information. */ -void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_wave_info_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header); /** @@ -191,7 +191,7 @@ void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd, * The header content of the SNDWAV PDU. All RDPSND messages contain * the same header information. */ -void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_wave_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header); /** @@ -211,7 +211,7 @@ void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd, * The header content of the SNDC_CLOSE PDU. All RDPSND messages contain * the same header information. */ -void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd, +void guac_rdpsnd_close_handler(guac_rdpsnd* rdpsnd, wStream* input_stream, guac_rdpsnd_pdu_header* header); #endif diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c index d3bce560..b18a2652 100644 --- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c +++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c @@ -26,74 +26,23 @@ #include #include -#include #include #include /** - * Entry point for RDPSND virtual channel. + * Processes data received along the RDPSND channel via a + * CHANNEL_EVENT_DATA_RECEIVED event, forwarding the data along an established, + * outbound pipe stream to the Guacamole client. + * + * @param rdpsnd + * The guac_rdpsnd structure representing the RDPSND channel. + * + * @param input_stream + * The data that was received. */ -int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) { - - /* Allocate plugin */ - guac_rdpsndPlugin* rdpsnd = - (guac_rdpsndPlugin*) calloc(1, sizeof(guac_rdpsndPlugin)); - - /* Init channel def */ - strcpy(rdpsnd->plugin.channel_def.name, "rdpsnd"); - rdpsnd->plugin.channel_def.options = - CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP; - - /* Set callbacks */ - rdpsnd->plugin.connect_callback = guac_rdpsnd_process_connect; - rdpsnd->plugin.receive_callback = guac_rdpsnd_process_receive; - rdpsnd->plugin.event_callback = guac_rdpsnd_process_event; - rdpsnd->plugin.terminate_callback = guac_rdpsnd_process_terminate; - - /* Finish init */ - svc_plugin_init((rdpSvcPlugin*) rdpsnd, pEntryPoints); - return 1; - -} - -/* - * Service Handlers - */ - -void guac_rdpsnd_process_connect(rdpSvcPlugin* plugin) { - - guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin; - - /* Get client from plugin parameters */ - guac_client* client = rdpsnd->client = - (guac_client*) plugin->channel_entry_points.pExtendedData; - - /* NULL out pExtendedData so we don't lose our guac_client due to an - * automatic free() within libfreerdp */ - plugin->channel_entry_points.pExtendedData = NULL; - -#ifdef RDPSVCPLUGIN_INTERVAL_MS - /* Update every 10 ms */ - plugin->interval_ms = 10; -#endif - - /* Log that sound has been loaded */ - guac_client_log(client, GUAC_LOG_INFO, "guacsnd connected."); - -} - -void guac_rdpsnd_process_terminate(rdpSvcPlugin* plugin) { - free(plugin); -} - -void guac_rdpsnd_process_event(rdpSvcPlugin* plugin, wMessage* event) { - freerdp_event_free(event); -} - -void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin, +static void guac_rdpsnd_process_receive(guac_rdpsnd* rdpsnd, wStream* input_stream) { - guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin; guac_rdpsnd_pdu_header header; /* Read RDPSND PDU header */ @@ -137,3 +86,243 @@ void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin, } +/** + * Event handler for events which deal with data transmitted over the RDPSND + * channel. This specific implementation of the event handler currently + * handles only the CHANNEL_EVENT_DATA_RECEIVED event, delegating actual + * handling of that event to guac_rdpsnd_process_receive(). + * + * The FreeRDP requirements for this function follow those of the + * VirtualChannelOpenEventEx callback defined within Microsoft's RDP API: + * + * https://docs.microsoft.com/en-us/previous-versions/windows/embedded/aa514754%28v%3dmsdn.10%29 + * + * @param user_param + * The pointer to arbitrary data originally passed via the first parameter + * of the pVirtualChannelInitEx() function call when the associated channel + * was initialized. The pVirtualChannelInitEx() function is exposed within + * the channel entry points structure. + * + * @param open_handle + * The handle which identifies the channel itself, typically referred to + * within the FreeRDP source as OpenHandle. + * + * @param event + * An integer representing the event that should be handled. This will be + * either CHANNEL_EVENT_DATA_RECEIVED, CHANNEL_EVENT_WRITE_CANCELLED, or + * CHANNEL_EVENT_WRITE_COMPLETE. + * + * @param data + * The data received, for CHANNEL_EVENT_DATA_RECEIVED events, and the value + * passed as user data to pVirtualChannelWriteEx() for + * CHANNEL_EVENT_WRITE_* events (note that user data for + * pVirtualChannelWriteEx() as implemented by FreeRDP MUST either be NULL + * or a wStream containing the data written). + * + * @param data_length + * The number of bytes of event-specific data. + * + * @param total_length + * The total number of bytes written to the RDP server in a single write + * operation. + * + * NOTE: The meaning of total_length is unclear. The above description was + * written mainly through referencing the documentation in MSDN. Real-world + * use will need to be consulted, likely within the FreeRDP source, before + * this value can be reliably used. The current implementation of this + * handler ignores this parameter. + * + * @param data_flags + * The result of a bitwise OR of the CHANNEL_FLAG_* flags which apply to + * the data received. This value is relevant only to + * CHANNEL_EVENT_DATA_RECEIVED events. Valid flags are CHANNEL_FLAG_FIRST, + * CHANNEL_FLAG_LAST, and CHANNEL_FLAG_ONLY. The flag CHANNEL_FLAG_MIDDLE + * is not itself a flag, but the absence of both CHANNEL_FLAG_FIRST and + * CHANNEL_FLAG_LAST. + */ +static VOID guac_rdpsnd_handle_open_event(LPVOID user_param, + DWORD open_handle, UINT event, LPVOID data, UINT32 data_length, + UINT32 total_length, UINT32 data_flags) { + + /* Ignore all events except for received data */ + if (event != CHANNEL_EVENT_DATA_RECEIVED) + return; + + guac_rdpsnd* rdpsnd = (guac_rdpsnd*) user_param; + + /* Validate relevant handle matches that of the RDPSND channel */ + if (open_handle != rdpsnd->open_handle) { + guac_client_log(rdpsnd->client, GUAC_LOG_WARNING, "%i bytes of data " + "received from within the remote desktop session for the " + "RDPSND channel are being dropped because the relevant open " + "handle (0x%X) does not match the open handle of RDPSND " + "(0x%X).", data_length, rdpsnd->channel_def.name, open_handle, + rdpsnd->open_handle); + return; + } + + wStream* input_stream = Stream_New(data, data_length); + guac_rdpsnd_process_receive(rdpsnd, input_stream); + Stream_Free(input_stream, FALSE); + +} + +/** + * Processes a CHANNEL_EVENT_CONNECTED event, completing the + * connection/initialization process of the RDPSND channel. + * + * @param rdpsnd + * The guac_rdpsnd structure representing the RDPSND channel. + */ +static void guac_rdpsnd_process_connect(guac_rdpsnd* rdpsnd) { + + /* Open FreeRDP side of connected channel */ + UINT32 open_status = + rdpsnd->entry_points.pVirtualChannelOpenEx(rdpsnd->init_handle, + &rdpsnd->open_handle, rdpsnd->channel_def.name, + guac_rdpsnd_handle_open_event); + + /* Warn if the channel cannot be opened after all */ + if (open_status != CHANNEL_RC_OK) { + guac_client_log(rdpsnd->client, GUAC_LOG_WARNING, "RDPSND channel " + "could not be opened: %s (error %i)", + WTSErrorToString(open_status), open_status); + return; + } + + /* Log that sound has been loaded */ + guac_client_log(rdpsnd->client, GUAC_LOG_INFO, "RDPSND channel " + "connected."); + +} + +/** + * Processes a CHANNEL_EVENT_TERMINATED event, freeing all resources associated + * with the RDPSND channel. + * + * @param rdpsnd + * The guac_rdpsnd structure representing the RDPSND channel. + */ +static void guac_rdpsnd_process_terminate(guac_rdpsnd* rdpsnd) { + guac_client_log(rdpsnd->client, GUAC_LOG_INFO, "RDPSND channel disconnected."); + free(rdpsnd); +} + +/** + * Event handler for events which deal with the overall lifecycle of the RDPSND + * channel. This specific implementation of the event handler currently + * handles only CHANNEL_EVENT_CONNECTED and CHANNEL_EVENT_TERMINATED events, + * delegating actual handling of those events to guac_rdpsnd_process_connect() + * and guac_rdpsnd_process_terminate() respectively. + * + * The FreeRDP requirements for this function follow those of the + * VirtualChannelInitEventEx callback defined within Microsoft's RDP API: + * + * https://docs.microsoft.com/en-us/previous-versions/windows/embedded/aa514727%28v%3dmsdn.10%29 + * + * @param user_param + * The pointer to arbitrary data originally passed via the first parameter + * of the pVirtualChannelInitEx() function call when the associated channel + * was initialized. The pVirtualChannelInitEx() function is exposed within + * the channel entry points structure. + * + * @param init_handle + * The handle which identifies the client connection, typically referred to + * within the FreeRDP source as pInitHandle. + * + * @param event + * An integer representing the event that should be handled. This will be + * either CHANNEL_EVENT_CONNECTED, CHANNEL_EVENT_DISCONNECTED, + * CHANNEL_EVENT_INITIALIZED, CHANNEL_EVENT_TERMINATED, or + * CHANNEL_EVENT_V1_CONNECTED. + * + * @param data + * NULL in all cases except the CHANNEL_EVENT_CONNECTED event, in which + * case this is a null-terminated string containing the name of the server. + * + * @param data_length + * The number of bytes of data, if any. + */ +static VOID guac_rdpsnd_handle_init_event(LPVOID user_param, + LPVOID init_handle, UINT event, LPVOID data, UINT data_length) { + + guac_rdpsnd* rdpsnd = (guac_rdpsnd*) user_param; + + /* Validate relevant handle matches that of the RDPSND channel */ + if (init_handle != rdpsnd->init_handle) { + guac_client_log(rdpsnd->client, GUAC_LOG_WARNING, "An init event " + "(#%i) for the RDPSND channel has been dropped because the " + "relevant init handle (0x%X) does not match the init handle " + "of the RDPSND channel (0x%X).", event, init_handle, + rdpsnd->init_handle); + return; + } + + switch (event) { + + /* The RDPSND channel has been connected */ + case CHANNEL_EVENT_CONNECTED: + guac_rdpsnd_process_connect(rdpsnd); + break; + + /* The RDPSND channel has disconnected and now must be cleaned up */ + case CHANNEL_EVENT_TERMINATED: + guac_rdpsnd_process_terminate(rdpsnd); + break; + + } + +} + +/** + * Entry point for FreeRDP plugins. This function is automatically invoked when + * the plugin is loaded. + * + * @param entry_points + * Functions and data specific to the FreeRDP side of the virtual channel + * and plugin. This structure must be copied within implementation-specific + * storage such that the functions it references can be invoked when + * needed. + * + * @param init_handle + * The handle which identifies the client connection, typically referred to + * within the FreeRDP source as pInitHandle. This handle is also provided + * to the channel init event handler. The handle must eventually be used + * within the channel open event handler to obtain a handle to the channel + * itself. + * + * @return + * TRUE if the plugin has initialized successfully, FALSE otherwise. + */ +BOOL VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS entry_points, + PVOID init_handle) { + + CHANNEL_ENTRY_POINTS_FREERDP_EX* entry_points_ex = + (CHANNEL_ENTRY_POINTS_FREERDP_EX*) entry_points; + + /* Allocate plugin */ + guac_rdpsnd* rdpsnd = (guac_rdpsnd*) calloc(1, sizeof(guac_rdpsnd)); + + /* Init channel def */ + strcpy(rdpsnd->channel_def.name, "rdpsnd"); + rdpsnd->channel_def.options = CHANNEL_OPTION_INITIALIZED + | CHANNEL_OPTION_ENCRYPT_RDP; + + /* Maintain reference to associated guac_client */ + rdpsnd->client = (guac_client*) entry_points_ex->pExtendedData; + + /* Copy FreeRDP data into RDPSND structure for future reference */ + rdpsnd->entry_points = *entry_points_ex; + rdpsnd->init_handle = init_handle; + + /* Complete initialization */ + if (rdpsnd->entry_points.pVirtualChannelInitEx(rdpsnd, rdpsnd, init_handle, + &rdpsnd->channel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + guac_rdpsnd_handle_init_event) != CHANNEL_RC_OK) { + return FALSE; + } + + return TRUE; + +} + diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h index 7a4aff52..de615ab0 100644 --- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h +++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h @@ -18,14 +18,15 @@ */ -#ifndef __GUAC_RDPSND_SERVICE_H -#define __GUAC_RDPSND_SERVICE_H +#ifndef GUAC_RDPSND_SERVICE_H +#define GUAC_RDPSND_SERVICE_H #include "config.h" -#include +#include #include #include +#include /** * The maximum number of PCM formats to accept during the initial RDPSND @@ -62,14 +63,7 @@ typedef struct guac_pcm_format { * Structure representing the current state of the Guacamole RDPSND plugin for * FreeRDP. */ -typedef struct guac_rdpsndPlugin { - - /** - * The FreeRDP parts of this plugin. This absolutely MUST be first. - * FreeRDP depends on accessing this structure as if it were an instance - * of rdpSvcPlugin. - */ - rdpSvcPlugin plugin; +typedef struct guac_rdpsnd { /** * The Guacamole client associated with the guac_audio_stream that this @@ -77,6 +71,38 @@ typedef struct guac_rdpsndPlugin { */ guac_client* client; + /** + * The definition of this virtual channel (RDPSND). + */ + CHANNEL_DEF channel_def; + + /** + * Functions and data specific to the FreeRDP side of the virtual channel + * and plugin. + */ + CHANNEL_ENTRY_POINTS_FREERDP_EX entry_points; + + /** + * Handle which identifies the client connection, typically referred to + * within the FreeRDP source as pInitHandle. This handle is provided to the + * channel entry point and the channel init event handler. The handle must + * eventually be used within the channel open event handler to obtain a + * handle to the channel itself. + */ + PVOID init_handle; + + /** + * Handle which identifies the channel itself, typically referred to within + * the FreeRDP source as OpenHandle. This handle is obtained through a call + * to entry_points.pVirtualChannelOpenEx() in response to receiving a + * CHANNEL_EVENT_CONNECTED event via the init event handler. + * + * Data is received in CHANNEL_EVENT_DATA_RECEIVED events via the open + * event handler, and data is written through calls to + * entry_points.pVirtualChannelWriteEx(). + */ + DWORD open_handle; + /** * The block number of the last SNDC_WAVE (WaveInfo) PDU received. */ @@ -118,29 +144,7 @@ typedef struct guac_rdpsndPlugin { */ int format_count; -} guac_rdpsndPlugin; - -/** - * Handler called when this plugin is loaded by FreeRDP. - */ -void guac_rdpsnd_process_connect(rdpSvcPlugin* plugin); - -/** - * Handler called when this plugin receives data along its designated channel. - */ -void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin, - wStream* input_stream); - -/** - * Handler called when this plugin is being unloaded. - */ -void guac_rdpsnd_process_terminate(rdpSvcPlugin* plugin); - -/** - * Handler called when this plugin receives an event. For the sake of RDPSND, - * all events will be ignored and simply free'd. - */ -void guac_rdpsnd_process_event(rdpSvcPlugin* plugin, wMessage* event); +} guac_rdpsnd; #endif