GUACAMOLE-249: Migrate RDPSND support to FreeRDP 2.0.0 plugin API.
This commit is contained in:
parent
0497a33ece
commit
6f2b124472
@ -130,9 +130,9 @@ libguac_client_rdp_la_LIBADD = \
|
|||||||
|
|
||||||
freerdp_LTLIBRARIES = \
|
freerdp_LTLIBRARIES = \
|
||||||
libguacai-client.la \
|
libguacai-client.la \
|
||||||
|
libguacsnd-client.la \
|
||||||
libguacsvc-client.la
|
libguacsvc-client.la
|
||||||
# libguacdr-client.la
|
# libguacdr-client.la
|
||||||
# libguacsnd-client.la
|
|
||||||
|
|
||||||
freerdpdir = ${libdir}/freerdp2
|
freerdpdir = ${libdir}/freerdp2
|
||||||
|
|
||||||
@ -200,25 +200,25 @@ libguacai_client_la_LIBADD = \
|
|||||||
# RDPSND
|
# RDPSND
|
||||||
#
|
#
|
||||||
|
|
||||||
#libguacsnd_client_la_SOURCES = \
|
libguacsnd_client_la_SOURCES = \
|
||||||
# guac_rdpsnd/rdpsnd_messages.c \
|
guac_rdpsnd/rdpsnd_messages.c \
|
||||||
# guac_rdpsnd/rdpsnd_service.c
|
guac_rdpsnd/rdpsnd_service.c
|
||||||
#
|
|
||||||
#libguacsnd_client_la_CFLAGS = \
|
libguacsnd_client_la_CFLAGS = \
|
||||||
# -Werror -Wall -Iinclude \
|
-Werror -Wall -Iinclude \
|
||||||
# @COMMON_INCLUDE@ \
|
@COMMON_INCLUDE@ \
|
||||||
# @COMMON_SSH_INCLUDE@ \
|
@COMMON_SSH_INCLUDE@ \
|
||||||
# @LIBGUAC_INCLUDE@ \
|
@LIBGUAC_INCLUDE@ \
|
||||||
# @RDP_CFLAGS@
|
@RDP_CFLAGS@
|
||||||
#
|
|
||||||
#libguacsnd_client_la_LDFLAGS = \
|
libguacsnd_client_la_LDFLAGS = \
|
||||||
# -module -avoid-version -shared \
|
-module -avoid-version -shared \
|
||||||
# @PTHREAD_LIBS@ \
|
@PTHREAD_LIBS@ \
|
||||||
# @RDP_LIBS@
|
@RDP_LIBS@
|
||||||
#
|
|
||||||
#libguacsnd_client_la_LIBADD = \
|
libguacsnd_client_la_LIBADD = \
|
||||||
# @COMMON_LTLIB@ \
|
@COMMON_LTLIB@ \
|
||||||
# @LIBGUAC_LTLIB@
|
@LIBGUAC_LTLIB@
|
||||||
|
|
||||||
#
|
#
|
||||||
# Static Virtual Channels
|
# Static Virtual Channels
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <guacamole/audio.h>
|
#include <guacamole/audio.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
@ -34,7 +33,7 @@
|
|||||||
|
|
||||||
/* MESSAGE HANDLERS */
|
/* 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) {
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
|
|
||||||
int server_format_count;
|
int server_format_count;
|
||||||
@ -182,8 +181,9 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
Stream_SetPointer(output_stream, output_stream_end);
|
Stream_SetPointer(output_stream, output_stream_end);
|
||||||
|
|
||||||
/* Send accepted formats */
|
/* Send accepted formats */
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle,
|
||||||
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
|
rdpsnd->open_handle, Stream_Buffer(output_stream),
|
||||||
|
Stream_GetPosition(output_stream), output_stream);
|
||||||
|
|
||||||
/* If version greater than 6, must send Quality Mode PDU */
|
/* If version greater than 6, must send Quality Mode PDU */
|
||||||
if (server_version >= 6) {
|
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, HIGH_QUALITY);
|
||||||
Stream_Write_UINT16(output_stream, 0);
|
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 */
|
/* 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) {
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
|
|
||||||
int data_size;
|
int data_size;
|
||||||
wStream* output_stream;
|
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 */
|
/* Read timestamp and data size */
|
||||||
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
|
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
|
||||||
Stream_Read_UINT16(input_stream, data_size);
|
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, rdpsnd->server_timestamp);
|
||||||
Stream_Write_UINT16(output_stream, data_size);
|
Stream_Write_UINT16(output_stream, data_size);
|
||||||
|
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle,
|
||||||
svc_plugin_send((rdpSvcPlugin*) rdpsnd, output_stream);
|
rdpsnd->open_handle, Stream_Buffer(output_stream),
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
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) {
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
|
|
||||||
int format;
|
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) {
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
|
|
||||||
rdpSvcPlugin* plugin = (rdpSvcPlugin*)rdpsnd;
|
|
||||||
|
|
||||||
/* Get associated client data */
|
/* Get associated client data */
|
||||||
guac_client* client = rdpsnd->client;
|
guac_client* client = rdpsnd->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
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);
|
Stream_Write_UINT8(output_stream, 0);
|
||||||
|
|
||||||
/* Send Wave Confirmation PDU */
|
/* Send Wave Confirmation PDU */
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
rdpsnd->entry_points.pVirtualChannelWriteEx(rdpsnd->init_handle,
|
||||||
svc_plugin_send(plugin, output_stream);
|
rdpsnd->open_handle, Stream_Buffer(output_stream),
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
Stream_GetPosition(output_stream), output_stream);
|
||||||
|
|
||||||
/* We no longer expect to receive wave data */
|
/* We no longer expect to receive wave data */
|
||||||
rdpsnd->next_pdu_is_wave = FALSE;
|
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) {
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
|
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __GUAC_RDPSND_MESSAGES_H
|
#ifndef GUAC_RDPSND_MESSAGES_H
|
||||||
#define __GUAC_RDPSND_MESSAGES_H
|
#define GUAC_RDPSND_MESSAGES_H
|
||||||
|
|
||||||
#include "config.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 header content of the SNDC_FORMATS PDU. All RDPSND messages contain
|
||||||
* the same header information.
|
* 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);
|
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 header content of the SNDC_TRAINING PDU. All RDPSND messages contain
|
||||||
* the same header information.
|
* 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);
|
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 header content of the SNDC_WAVE PDU. All RDPSND messages contain
|
||||||
* the same header information.
|
* 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);
|
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 header content of the SNDWAV PDU. All RDPSND messages contain
|
||||||
* the same header information.
|
* 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);
|
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 header content of the SNDC_CLOSE PDU. All RDPSND messages contain
|
||||||
* the same header information.
|
* 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);
|
wStream* input_stream, guac_rdpsnd_pdu_header* header);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,74 +26,23 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
static void guac_rdpsnd_process_receive(guac_rdpsnd* rdpsnd,
|
||||||
|
|
||||||
/* 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,
|
|
||||||
wStream* input_stream) {
|
wStream* input_stream) {
|
||||||
|
|
||||||
guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
|
|
||||||
guac_rdpsnd_pdu_header header;
|
guac_rdpsnd_pdu_header header;
|
||||||
|
|
||||||
/* Read RDPSND PDU 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -18,14 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __GUAC_RDPSND_SERVICE_H
|
#ifndef GUAC_RDPSND_SERVICE_H
|
||||||
#define __GUAC_RDPSND_SERVICE_H
|
#define GUAC_RDPSND_SERVICE_H
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
#include <freerdp/svc.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
#include <winpr/wtsapi.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of PCM formats to accept during the initial RDPSND
|
* 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
|
* Structure representing the current state of the Guacamole RDPSND plugin for
|
||||||
* FreeRDP.
|
* FreeRDP.
|
||||||
*/
|
*/
|
||||||
typedef struct guac_rdpsndPlugin {
|
typedef struct guac_rdpsnd {
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Guacamole client associated with the guac_audio_stream that this
|
* The Guacamole client associated with the guac_audio_stream that this
|
||||||
@ -77,6 +71,38 @@ typedef struct guac_rdpsndPlugin {
|
|||||||
*/
|
*/
|
||||||
guac_client* client;
|
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.
|
* The block number of the last SNDC_WAVE (WaveInfo) PDU received.
|
||||||
*/
|
*/
|
||||||
@ -118,29 +144,7 @@ typedef struct guac_rdpsndPlugin {
|
|||||||
*/
|
*/
|
||||||
int format_count;
|
int format_count;
|
||||||
|
|
||||||
} guac_rdpsndPlugin;
|
} guac_rdpsnd;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user