GUACAMOLE-1283: Merge add synchronization around absolutely all outbound RDP messages.
This commit is contained in:
commit
e90e438cf6
@ -31,9 +31,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc() {
|
||||
guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc(guac_client* client) {
|
||||
guac_rdp_audio_buffer* buffer = calloc(1, sizeof(guac_rdp_audio_buffer));
|
||||
pthread_mutex_init(&(buffer->lock), NULL);
|
||||
buffer->client = client;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -270,8 +271,8 @@ void guac_rdp_audio_buffer_write(guac_rdp_audio_buffer* audio_buffer,
|
||||
|
||||
/* Only actually invoke if defined */
|
||||
if (audio_buffer->flush_handler)
|
||||
audio_buffer->flush_handler(audio_buffer->packet,
|
||||
audio_buffer->bytes_written, audio_buffer->data);
|
||||
audio_buffer->flush_handler(audio_buffer,
|
||||
audio_buffer->bytes_written);
|
||||
|
||||
/* Reset buffer in all cases */
|
||||
audio_buffer->bytes_written = 0;
|
||||
|
@ -24,24 +24,27 @@
|
||||
#include <guacamole/user.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* A buffer of arbitrary audio data. Received audio data can be written to this
|
||||
* buffer, and will automatically be flushed via a given handler once the
|
||||
* internal buffer reaches capacity.
|
||||
*/
|
||||
typedef struct guac_rdp_audio_buffer guac_rdp_audio_buffer;
|
||||
|
||||
/**
|
||||
* Handler which is invoked when a guac_rdp_audio_buffer's internal packet
|
||||
* buffer has reached capacity and must be flushed.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer which needs to be flushed as an audio packet.
|
||||
* @param audio_buffer
|
||||
* The guac_rdp_audio_buffer that has reached capacity and needs to be
|
||||
* flushed.
|
||||
*
|
||||
* @param length
|
||||
* The number of bytes stored within the buffer. This is guaranteed to be
|
||||
* identical to the packet_size value specified when the audio buffer was
|
||||
* initialized.
|
||||
*
|
||||
* @param data
|
||||
* The arbitrary data pointer provided when the audio buffer was
|
||||
* initialized.
|
||||
*/
|
||||
typedef void guac_rdp_audio_buffer_flush_handler(char* buffer, int length,
|
||||
void* data);
|
||||
typedef void guac_rdp_audio_buffer_flush_handler(guac_rdp_audio_buffer* audio_buffer, int length);
|
||||
|
||||
/**
|
||||
* A description of an arbitrary PCM audio format.
|
||||
@ -66,12 +69,7 @@ typedef struct guac_rdp_audio_format {
|
||||
|
||||
} guac_rdp_audio_format;
|
||||
|
||||
/**
|
||||
* A buffer of arbitrary audio data. Received audio data can be written to this
|
||||
* buffer, and will automatically be flushed via a given handler once the
|
||||
* internal buffer reaches capacity.
|
||||
*/
|
||||
typedef struct guac_rdp_audio_buffer {
|
||||
struct guac_rdp_audio_buffer {
|
||||
|
||||
/**
|
||||
* Lock which is acquired/released to ensure accesses to the audio buffer
|
||||
@ -79,6 +77,11 @@ typedef struct guac_rdp_audio_buffer {
|
||||
*/
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/**
|
||||
* The guac_client instance handling the relevant RDP connection.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The user from which this audio buffer will receive data. If no user has
|
||||
* yet opened an associated audio stream, this will be NULL.
|
||||
@ -145,17 +148,20 @@ typedef struct guac_rdp_audio_buffer {
|
||||
*/
|
||||
void* data;
|
||||
|
||||
} guac_rdp_audio_buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocates a new audio buffer. The new audio buffer will ignore any received
|
||||
* data until guac_rdp_audio_buffer_begin() is invoked, and will resume
|
||||
* ignoring received data once guac_rdp_audio_buffer_end() is invoked.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client instance handling the relevant RDP connection.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated audio buffer.
|
||||
*/
|
||||
guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc();
|
||||
guac_rdp_audio_buffer* guac_rdp_audio_buffer_alloc(guac_client* client);
|
||||
|
||||
/**
|
||||
* Associates the given audio buffer with the underlying audio stream which
|
||||
|
@ -76,6 +76,9 @@ static UINT guac_rdp_cliprdr_send_format_list(CliprdrClientContext* cliprdr) {
|
||||
guac_rdp_clipboard* clipboard = (guac_rdp_clipboard*) cliprdr->custom;
|
||||
assert(clipboard != NULL);
|
||||
|
||||
guac_client* client = clipboard->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
/* We support CP-1252 and UTF-16 text */
|
||||
CLIPRDR_FORMAT_LIST format_list = {
|
||||
.msgType = CB_FORMAT_LIST,
|
||||
@ -86,10 +89,12 @@ static UINT guac_rdp_cliprdr_send_format_list(CliprdrClientContext* cliprdr) {
|
||||
.numFormats = 2
|
||||
};
|
||||
|
||||
guac_client_log(clipboard->client, GUAC_LOG_TRACE, "CLIPRDR: Sending "
|
||||
"format list");
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Sending format list");
|
||||
|
||||
return cliprdr->ClientFormatList(cliprdr, &format_list);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
int retval = cliprdr->ClientFormatList(cliprdr, &format_list);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@ -107,6 +112,17 @@ static UINT guac_rdp_cliprdr_send_format_list(CliprdrClientContext* cliprdr) {
|
||||
*/
|
||||
static UINT guac_rdp_cliprdr_send_capabilities(CliprdrClientContext* cliprdr) {
|
||||
|
||||
/* This function is only invoked within FreeRDP-specific handlers for
|
||||
* CLIPRDR, which are not assigned, and thus not callable, until after the
|
||||
* relevant guac_rdp_clipboard structure is allocated and associated with
|
||||
* the CliprdrClientContext */
|
||||
guac_rdp_clipboard* clipboard = (guac_rdp_clipboard*) cliprdr->custom;
|
||||
assert(clipboard != NULL);
|
||||
|
||||
guac_client* client = clipboard->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
/* We support CP-1252 and UTF-16 text */
|
||||
CLIPRDR_GENERAL_CAPABILITY_SET cap_set = {
|
||||
.capabilitySetType = CB_CAPSTYPE_GENERAL, /* CLIPRDR specification requires that this is CB_CAPSTYPE_GENERAL, the only defined set type */
|
||||
.capabilitySetLength = 12, /* The size of the capability set within the PDU - for CB_CAPSTYPE_GENERAL, this is ALWAYS 12 bytes */
|
||||
@ -119,7 +135,11 @@ static UINT guac_rdp_cliprdr_send_capabilities(CliprdrClientContext* cliprdr) {
|
||||
.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &cap_set
|
||||
};
|
||||
|
||||
return cliprdr->ClientCapabilities(cliprdr, &caps);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
int retval = cliprdr->ClientCapabilities(cliprdr, &caps);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@ -190,6 +210,9 @@ static UINT guac_rdp_cliprdr_send_format_data_request(
|
||||
guac_rdp_clipboard* clipboard = (guac_rdp_clipboard*) cliprdr->custom;
|
||||
assert(clipboard != NULL);
|
||||
|
||||
guac_client* client = clipboard->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
/* Create new data request */
|
||||
CLIPRDR_FORMAT_DATA_REQUEST data_request = {
|
||||
.requestedFormatId = format
|
||||
@ -199,11 +222,14 @@ static UINT guac_rdp_cliprdr_send_format_data_request(
|
||||
* data is received via a Format Data Response PDU */
|
||||
clipboard->requested_format = format;
|
||||
|
||||
guac_client_log(clipboard->client, GUAC_LOG_TRACE, "CLIPRDR: Sending "
|
||||
"format data request.");
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Sending format data request.");
|
||||
|
||||
/* Send request */
|
||||
return cliprdr->ClientFormatDataRequest(cliprdr, &data_request);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
int retval = cliprdr->ClientFormatDataRequest(cliprdr, &data_request);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@ -265,15 +291,19 @@ static UINT guac_rdp_cliprdr_format_list(CliprdrClientContext* cliprdr,
|
||||
guac_rdp_clipboard* clipboard = (guac_rdp_clipboard*) cliprdr->custom;
|
||||
assert(clipboard != NULL);
|
||||
|
||||
guac_client_log(clipboard->client, GUAC_LOG_TRACE, "CLIPRDR: Received "
|
||||
"format list.");
|
||||
guac_client* client = clipboard->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Received format list.");
|
||||
|
||||
CLIPRDR_FORMAT_LIST_RESPONSE format_list_response = {
|
||||
.msgFlags = CB_RESPONSE_OK
|
||||
};
|
||||
|
||||
/* Report successful processing of format list */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
cliprdr->ClientFormatListResponse(cliprdr, &format_list_response);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
/* Prefer Unicode (in this case, UTF-16) */
|
||||
if (guac_rdp_cliprdr_format_supported(format_list, CF_UNICODETEXT))
|
||||
@ -284,9 +314,9 @@ static UINT guac_rdp_cliprdr_format_list(CliprdrClientContext* cliprdr,
|
||||
return guac_rdp_cliprdr_send_format_data_request(cliprdr, CF_TEXT);
|
||||
|
||||
/* Ignore any unsupported data */
|
||||
guac_client_log(clipboard->client, GUAC_LOG_DEBUG, "Ignoring unsupported "
|
||||
"clipboard data. Only Unicode and text clipboard formats are "
|
||||
"currently supported.");
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Ignoring unsupported clipboard "
|
||||
"data. Only Unicode and text clipboard formats are currently "
|
||||
"supported.");
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
@ -320,8 +350,10 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr,
|
||||
guac_rdp_clipboard* clipboard = (guac_rdp_clipboard*) cliprdr->custom;
|
||||
assert(clipboard != NULL);
|
||||
|
||||
guac_client_log(clipboard->client, GUAC_LOG_TRACE, "CLIPRDR: Received "
|
||||
"format data request.");
|
||||
guac_client* client = clipboard->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Received format data request.");
|
||||
|
||||
guac_iconv_write* writer;
|
||||
const char* input = clipboard->clipboard->buffer;
|
||||
@ -341,11 +373,11 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr,
|
||||
/* Warn if clipboard data cannot be sent as intended due to a violation
|
||||
* of the CLIPRDR spec */
|
||||
default:
|
||||
guac_client_log(clipboard->client, GUAC_LOG_WARNING, "Received "
|
||||
"clipboard data cannot be sent to the RDP server because "
|
||||
"the RDP server has requested a clipboard format which "
|
||||
"was not declared as available. This violates the "
|
||||
"specification for the CLIPRDR channel.");
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "Received clipboard "
|
||||
"data cannot be sent to the RDP server because the RDP "
|
||||
"server has requested a clipboard format which was not "
|
||||
"declared as available. This violates the specification "
|
||||
"for the CLIPRDR channel.");
|
||||
free(output);
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
@ -363,10 +395,12 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr,
|
||||
.msgFlags = CB_RESPONSE_OK
|
||||
};
|
||||
|
||||
guac_client_log(clipboard->client, GUAC_LOG_TRACE, "CLIPRDR: Sending "
|
||||
"format data response.");
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Sending format data response.");
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
UINT result = cliprdr->ClientFormatDataResponse(cliprdr, &data_response);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
free(start);
|
||||
return result;
|
||||
|
||||
@ -407,9 +441,9 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
|
||||
|
||||
/* Ignore received data if copy has been disabled */
|
||||
if (settings->disable_copy) {
|
||||
guac_client_log(clipboard->client, GUAC_LOG_DEBUG, "Ignoring received "
|
||||
"clipboard data as copying from within the remote desktop has "
|
||||
"been explicitly disabled.");
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Ignoring received clipboard "
|
||||
"data as copying from within the remote desktop has been "
|
||||
"explicitly disabled.");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -439,9 +473,8 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
|
||||
* here. The values which may be stored within requested_format are
|
||||
* completely within our control. */
|
||||
default:
|
||||
guac_client_log(clipboard->client, GUAC_LOG_DEBUG, "Requested "
|
||||
"clipboard data in unsupported format (0x%X).",
|
||||
clipboard->requested_format);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Requested clipboard data "
|
||||
"in unsupported format (0x%X).", clipboard->requested_format);
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
}
|
||||
@ -453,7 +486,7 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
|
||||
int length = strnlen(received_data, sizeof(received_data));
|
||||
guac_common_clipboard_reset(clipboard->clipboard, "text/plain");
|
||||
guac_common_clipboard_append(clipboard->clipboard, received_data, length);
|
||||
guac_common_clipboard_send(clipboard->clipboard, clipboard->client);
|
||||
guac_common_clipboard_send(clipboard->clipboard, client);
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
|
@ -89,12 +89,16 @@ void guac_rdp_common_svc_write(guac_rdp_common_svc* svc,
|
||||
return;
|
||||
}
|
||||
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) svc->client->data;
|
||||
|
||||
/* NOTE: The wStream sent via pVirtualChannelWriteEx will automatically be
|
||||
* freed later with a call to Stream_Free() when handling the
|
||||
* corresponding write cancel/completion event. */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
svc->_entry_points.pVirtualChannelWriteEx(svc->_init_handle,
|
||||
svc->_open_handle, Stream_Buffer(output_stream),
|
||||
Stream_GetPosition(output_stream), output_stream);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
guac_rdp_disp* guac_rdp_disp_alloc() {
|
||||
guac_rdp_disp* guac_rdp_disp_alloc(guac_client* client) {
|
||||
|
||||
guac_rdp_disp* disp = malloc(sizeof(guac_rdp_disp));
|
||||
disp->client = client;
|
||||
|
||||
/* Not yet connected */
|
||||
disp->disp = NULL;
|
||||
@ -220,8 +221,17 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp,
|
||||
}};
|
||||
|
||||
/* Send display update notification if display channel is connected */
|
||||
if (disp->disp != NULL)
|
||||
if (disp->disp != NULL) {
|
||||
|
||||
guac_client* client = disp->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
disp->disp->SendMonitorLayout(disp->disp, 1, monitors);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -48,6 +48,11 @@
|
||||
*/
|
||||
typedef struct guac_rdp_disp {
|
||||
|
||||
/**
|
||||
* The guac_client instance handling the relevant RDP connection.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* Display control interface.
|
||||
*/
|
||||
@ -81,10 +86,13 @@ typedef struct guac_rdp_disp {
|
||||
* Allocates a new display update module, which will ultimately control the
|
||||
* display update channel once connected.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client instance handling the relevant RDP connection.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated display update module.
|
||||
*/
|
||||
guac_rdp_disp* guac_rdp_disp_alloc();
|
||||
guac_rdp_disp* guac_rdp_disp_alloc(guac_client* client);
|
||||
|
||||
/**
|
||||
* Frees the resources associated with support for the RDP Display Update
|
||||
|
@ -86,7 +86,10 @@ static UINT guac_rdp_rail_complete_handshake(RailClientContext* rail) {
|
||||
};
|
||||
|
||||
/* Send client handshake response */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
status = rail->ClientHandshake(rail, &handshake);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
return status;
|
||||
|
||||
@ -95,7 +98,10 @@ static UINT guac_rdp_rail_complete_handshake(RailClientContext* rail) {
|
||||
};
|
||||
|
||||
/* Send client status */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
status = rail->ClientInformation(rail, &client_status);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
return status;
|
||||
|
||||
@ -139,7 +145,10 @@ static UINT guac_rdp_rail_complete_handshake(RailClientContext* rail) {
|
||||
};
|
||||
|
||||
/* Send client system parameters */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
status = rail->ClientSystemParam(rail, &sysparam);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
return status;
|
||||
|
||||
@ -151,7 +160,11 @@ static UINT guac_rdp_rail_complete_handshake(RailClientContext* rail) {
|
||||
};
|
||||
|
||||
/* Execute desired RemoteApp command */
|
||||
return rail->ClientExecute(rail, &exec);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
status = rail->ClientExecute(rail, &exec);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
guac_rdp_rdpei* guac_rdp_rdpei_alloc() {
|
||||
guac_rdp_rdpei* guac_rdp_rdpei_alloc(guac_client* client) {
|
||||
|
||||
guac_rdp_rdpei* rdpei = malloc(sizeof(guac_rdp_rdpei));
|
||||
rdpei->client = client;
|
||||
|
||||
/* Not yet connected */
|
||||
rdpei->rdpei = NULL;
|
||||
@ -107,6 +108,9 @@ void guac_rdp_rdpei_load_plugin(rdpContext* context) {
|
||||
int guac_rdp_rdpei_touch_update(guac_rdp_rdpei* rdpei, int id, int x, int y,
|
||||
double force) {
|
||||
|
||||
guac_client* client = rdpei->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
int contact_id; /* Ignored */
|
||||
|
||||
/* Track touches only if channel is connected */
|
||||
@ -149,20 +153,31 @@ int guac_rdp_rdpei_touch_update(guac_rdp_rdpei* rdpei, int id, int x, int y,
|
||||
if (!touch->active)
|
||||
return 1;
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
context->TouchEnd(context, id, x, y, &contact_id);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
touch->active = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Signal the start of a touch if this is the first we've seen it */
|
||||
else if (!touch->active) {
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
context->TouchBegin(context, id, x, y, &contact_id);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
touch->active = 1;
|
||||
|
||||
}
|
||||
|
||||
/* Established touches need only be updated */
|
||||
else
|
||||
else {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
context->TouchUpdate(context, id, x, y, &contact_id);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -66,6 +66,11 @@ typedef struct guac_rdp_rdpei_touch {
|
||||
*/
|
||||
typedef struct guac_rdp_rdpei {
|
||||
|
||||
/**
|
||||
* The guac_client instance handling the relevant RDP connection.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* RDPEI control interface.
|
||||
*/
|
||||
@ -83,10 +88,13 @@ typedef struct guac_rdp_rdpei {
|
||||
* channel once connected. The RDPEI channel allows multi-touch input
|
||||
* events to be sent to the RDP server.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client instance handling the relevant RDP connection.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated RDPEI module.
|
||||
*/
|
||||
guac_rdp_rdpei* guac_rdp_rdpei_alloc();
|
||||
guac_rdp_rdpei* guac_rdp_rdpei_alloc(guac_client* client);
|
||||
|
||||
/**
|
||||
* Frees the resources associated with support for the RDPEI channel. Only
|
||||
|
@ -145,10 +145,10 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
rdp_client->clipboard = guac_rdp_clipboard_alloc(client);
|
||||
|
||||
/* Init display update module */
|
||||
rdp_client->disp = guac_rdp_disp_alloc();
|
||||
rdp_client->disp = guac_rdp_disp_alloc(client);
|
||||
|
||||
/* Init multi-touch support module (RDPEI) */
|
||||
rdp_client->rdpei = guac_rdp_rdpei_alloc();
|
||||
rdp_client->rdpei = guac_rdp_rdpei_alloc(client);
|
||||
|
||||
/* Redirect FreeRDP log messages to guac_client_log() */
|
||||
guac_rdp_redirect_wlog(client);
|
||||
@ -158,8 +158,9 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
pthread_mutexattr_settype(&(rdp_client->attributes),
|
||||
PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
/* Initalize the lock */
|
||||
/* Init required locks */
|
||||
pthread_rwlock_init(&(rdp_client->lock), NULL);
|
||||
pthread_mutex_init(&(rdp_client->message_lock), &(rdp_client->attributes));
|
||||
|
||||
/* Set handlers */
|
||||
client->join_handler = guac_rdp_user_join_handler;
|
||||
@ -226,6 +227,7 @@ int guac_rdp_client_free_handler(guac_client* client) {
|
||||
guac_rdp_audio_buffer_free(rdp_client->audio_input);
|
||||
|
||||
pthread_rwlock_destroy(&(rdp_client->lock));
|
||||
pthread_mutex_destroy(&(rdp_client->message_lock));
|
||||
|
||||
/* Free client data */
|
||||
free(rdp_client);
|
||||
|
@ -54,8 +54,11 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
guac_common_recording_report_mouse(rdp_client->recording, x, y, mask);
|
||||
|
||||
/* If button mask unchanged, just send move event */
|
||||
if (mask == rdp_client->mouse_button_mask)
|
||||
if (mask == rdp_client->mouse_button_mask) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_MOVE, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
/* Otherwise, send events describing button change */
|
||||
else {
|
||||
@ -75,7 +78,9 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
if (released_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
|
||||
if (released_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->MouseEvent(rdp_inst->input, flags, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
@ -91,7 +96,9 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
if (pressed_mask & 0x10) flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88;
|
||||
|
||||
/* Send event */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->MouseEvent(rdp_inst->input, flags, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
@ -99,18 +106,18 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
if (pressed_mask & 0x18) {
|
||||
|
||||
/* Down */
|
||||
if (pressed_mask & 0x08)
|
||||
rdp_inst->input->MouseEvent(
|
||||
rdp_inst->input,
|
||||
PTR_FLAGS_WHEEL | 0x78,
|
||||
x, y);
|
||||
if (pressed_mask & 0x08) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_WHEEL | 0x78, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
/* Up */
|
||||
if (pressed_mask & 0x10)
|
||||
rdp_inst->input->MouseEvent(
|
||||
rdp_inst->input,
|
||||
PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88,
|
||||
x, y);
|
||||
if (pressed_mask & 0x10) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,9 @@ static void guac_rdp_send_key_event(guac_rdp_client* rdp_client,
|
||||
return;
|
||||
|
||||
/* Send actual key */
|
||||
rdp_inst->input->KeyboardEvent(rdp_inst->input,
|
||||
flags | pressed_flags, scancode);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->KeyboardEvent(rdp_inst->input, flags | pressed_flags, scancode);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
@ -132,9 +133,9 @@ static void guac_rdp_send_unicode_event(guac_rdp_client* rdp_client,
|
||||
return;
|
||||
|
||||
/* Send Unicode event */
|
||||
rdp_inst->input->UnicodeKeyboardEvent(
|
||||
rdp_inst->input,
|
||||
0, codepoint);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->UnicodeKeyboardEvent(rdp_inst->input, 0, codepoint);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
@ -161,7 +162,9 @@ static void guac_rdp_send_synchronize_event(guac_rdp_client* rdp_client,
|
||||
return;
|
||||
|
||||
/* Synchronize lock key states */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
rdp_inst->input->SynchronizeEvent(rdp_inst->input, flags);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
|
@ -247,6 +247,8 @@ static void guac_rdp_ai_send_formatchange(IWTSVirtualChannel* channel,
|
||||
void guac_rdp_ai_process_version(guac_client* client,
|
||||
IWTSVirtualChannel* channel, wStream* stream) {
|
||||
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
/* Verify we have at least 4 bytes available (UINT32) */
|
||||
if (Stream_GetRemainingLength(stream) < 4) {
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "Audio input Versoin PDU "
|
||||
@ -269,8 +271,9 @@ void guac_rdp_ai_process_version(guac_client* client,
|
||||
Stream_Write_UINT32(response, 1); /* Version */
|
||||
|
||||
/* Send response */
|
||||
channel->Write(channel, (UINT32) Stream_GetPosition(response),
|
||||
Stream_Buffer(response), NULL);
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
channel->Write(channel, (UINT32) Stream_GetPosition(response), Stream_Buffer(response), NULL);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
Stream_Free(response, TRUE);
|
||||
|
||||
}
|
||||
@ -313,26 +316,34 @@ void guac_rdp_ai_process_formats(guac_client* client,
|
||||
format.channels, format.bps / 8);
|
||||
|
||||
/* Accept single format */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
guac_rdp_ai_send_incoming_data(channel);
|
||||
guac_rdp_ai_send_formats(channel, &format, 1);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* No formats available */
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "AUDIO_INPUT: No WAVE format.");
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
guac_rdp_ai_send_incoming_data(channel);
|
||||
guac_rdp_ai_send_formats(channel, NULL, 0);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
void guac_rdp_ai_flush_packet(char* buffer, int length, void* data) {
|
||||
void guac_rdp_ai_flush_packet(guac_rdp_audio_buffer* audio_buffer, int length) {
|
||||
|
||||
IWTSVirtualChannel* channel = (IWTSVirtualChannel*) data;
|
||||
guac_client* client = audio_buffer->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
IWTSVirtualChannel* channel = (IWTSVirtualChannel*) audio_buffer->data;
|
||||
|
||||
/* Send data over channel */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
guac_rdp_ai_send_incoming_data(channel);
|
||||
guac_rdp_ai_send_data(channel, buffer, length);
|
||||
guac_rdp_ai_send_data(channel, audio_buffer->packet, length);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
@ -363,8 +374,10 @@ void guac_rdp_ai_process_open(guac_client* client,
|
||||
audio_buffer->out_format.bps);
|
||||
|
||||
/* Success */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
guac_rdp_ai_send_formatchange(channel, initial_format);
|
||||
guac_rdp_ai_send_open_reply(channel, 0);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
/* Begin receiving audio data */
|
||||
guac_rdp_audio_buffer_begin(audio_buffer, packet_frames,
|
||||
|
@ -107,7 +107,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
||||
|
||||
/* Load "AUDIO_INPUT" plugin for audio input*/
|
||||
if (settings->enable_audio_input) {
|
||||
rdp_client->audio_input = guac_rdp_audio_buffer_alloc();
|
||||
rdp_client->audio_input = guac_rdp_audio_buffer_alloc(client);
|
||||
guac_rdp_audio_load_plugin(instance->context);
|
||||
}
|
||||
|
||||
@ -564,13 +564,16 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
||||
guac_timestamp frame_end;
|
||||
int frame_remaining;
|
||||
|
||||
/* Check the libfreerdp fds */
|
||||
if (!freerdp_check_event_handles(rdp_inst->context)) {
|
||||
/* Handle any queued FreeRDP events (this may result in RDP
|
||||
* messages being sent) */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
int event_result = freerdp_check_event_handles(rdp_inst->context);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
/* Flag connection failure */
|
||||
/* Abort if FreeRDP event handling fails */
|
||||
if (!event_result) {
|
||||
wait_result = -1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Calculate time remaining in frame */
|
||||
@ -634,7 +637,9 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
||||
}
|
||||
|
||||
/* Disconnect client and channels */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
freerdp_disconnect(rdp_inst);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
/* Clean up FreeRDP internal GDI implementation */
|
||||
gdi_free(rdp_inst);
|
||||
|
@ -172,6 +172,12 @@ typedef struct guac_rdp_client {
|
||||
*/
|
||||
pthread_rwlock_t lock;
|
||||
|
||||
/**
|
||||
* Lock which synchronizes the sending of each RDP message, ensuring
|
||||
* attempts to send RDP messages never overlap.
|
||||
*/
|
||||
pthread_mutex_t message_lock;
|
||||
|
||||
} guac_rdp_client;
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user