GUACAMOLE-559: Merge fix race condition in receipt of clipboard data by terminal.
This commit is contained in:
commit
427c4c8b44
@ -24,6 +24,7 @@
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -37,6 +38,8 @@ guac_common_clipboard* guac_common_clipboard_alloc(int size) {
|
||||
clipboard->length = 0;
|
||||
clipboard->available = size;
|
||||
|
||||
pthread_mutex_init(&(clipboard->lock), NULL);
|
||||
|
||||
return clipboard;
|
||||
|
||||
}
|
||||
@ -108,18 +111,37 @@ static void* __send_user_clipboard(guac_user* user, void* data) {
|
||||
}
|
||||
|
||||
void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) {
|
||||
|
||||
pthread_mutex_lock(&(clipboard->lock));
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcasting clipboard to all connected users.");
|
||||
guac_client_foreach_user(client, __send_user_clipboard, clipboard);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcast of clipboard complete.");
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_reset(guac_common_clipboard* clipboard, const char* mimetype) {
|
||||
void guac_common_clipboard_reset(guac_common_clipboard* clipboard,
|
||||
const char* mimetype) {
|
||||
|
||||
pthread_mutex_lock(&(clipboard->lock));
|
||||
|
||||
/* Clear clipboard contents */
|
||||
clipboard->length = 0;
|
||||
|
||||
/* Assign given mimetype */
|
||||
strncpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype) - 1);
|
||||
clipboard->mimetype[sizeof(clipboard->mimetype) - 1] = '\0';
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char* data, int length) {
|
||||
|
||||
pthread_mutex_lock(&(clipboard->lock));
|
||||
|
||||
/* Truncate data to available length */
|
||||
int remaining = clipboard->available - clipboard->length;
|
||||
if (remaining < length)
|
||||
@ -131,5 +153,7 @@ void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char*
|
||||
/* Update length */
|
||||
clipboard->length += length;
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to send in an individual blob when
|
||||
@ -35,6 +36,13 @@
|
||||
*/
|
||||
typedef struct guac_common_clipboard {
|
||||
|
||||
/**
|
||||
* Lock which restricts simultaneous access to the clipboard, guaranteeing
|
||||
* ordered modifications to the clipboard and that changes to the clipboard
|
||||
* are not allowed while the clipboard is being broadcast to all users.
|
||||
*/
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/**
|
||||
* The mimetype of the contained clipboard data.
|
||||
*/
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "common/recording.h"
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "ssh.h"
|
||||
@ -42,6 +43,9 @@ int guac_client_init(guac_client* client) {
|
||||
guac_ssh_client* ssh_client = calloc(1, sizeof(guac_ssh_client));
|
||||
client->data = ssh_client;
|
||||
|
||||
/* Init clipboard */
|
||||
ssh_client->clipboard = guac_common_clipboard_alloc(GUAC_SSH_CLIPBOARD_MAX_LENGTH);
|
||||
|
||||
/* Set handlers */
|
||||
client->join_handler = guac_ssh_user_join_handler;
|
||||
client->free_handler = guac_ssh_client_free_handler;
|
||||
@ -106,6 +110,7 @@ int guac_ssh_client_free_handler(guac_client* client) {
|
||||
guac_ssh_settings_free(ssh_client->settings);
|
||||
|
||||
/* Free client structure */
|
||||
guac_common_clipboard_free(ssh_client->clipboard);
|
||||
free(ssh_client);
|
||||
|
||||
guac_common_ssh_uninit();
|
||||
|
@ -22,6 +22,11 @@
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow within the clipboard.
|
||||
*/
|
||||
#define GUAC_SSH_CLIPBOARD_MAX_LENGTH 262144
|
||||
|
||||
/**
|
||||
* Handler which is invoked when the SSH client needs to be disconnected (if
|
||||
* connected) and freed. This can happen if initialization fails, or all users
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "clipboard.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "ssh.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
@ -32,7 +33,7 @@ int guac_ssh_clipboard_handler(guac_user* user, guac_stream* stream,
|
||||
/* Clear clipboard and prepare for new data */
|
||||
guac_client* client = user->client;
|
||||
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
||||
guac_terminal_clipboard_reset(ssh_client->term, mimetype);
|
||||
guac_common_clipboard_reset(ssh_client->clipboard, mimetype);
|
||||
|
||||
/* Set handlers for clipboard stream */
|
||||
stream->blob_handler = guac_ssh_clipboard_blob_handler;
|
||||
@ -47,7 +48,7 @@ int guac_ssh_clipboard_blob_handler(guac_user* user, guac_stream* stream,
|
||||
/* Append new data */
|
||||
guac_client* client = user->client;
|
||||
guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;
|
||||
guac_terminal_clipboard_append(ssh_client->term, data, length);
|
||||
guac_common_clipboard_append(ssh_client->clipboard, data, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ void* ssh_client_thread(void* data) {
|
||||
}
|
||||
|
||||
/* Create terminal */
|
||||
ssh_client->term = guac_terminal_create(client,
|
||||
ssh_client->term = guac_terminal_create(client, ssh_client->clipboard,
|
||||
settings->font_name, settings->font_size,
|
||||
settings->resolution, settings->width, settings->height,
|
||||
settings->color_scheme, settings->backspace);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/clipboard.h"
|
||||
#include "common/recording.h"
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "common-ssh/ssh.h"
|
||||
@ -89,6 +90,11 @@ typedef struct guac_ssh_client {
|
||||
*/
|
||||
pthread_mutex_t term_channel_lock;
|
||||
|
||||
/**
|
||||
* The current clipboard contents.
|
||||
*/
|
||||
guac_common_clipboard* clipboard;
|
||||
|
||||
/**
|
||||
* The terminal which will render all output from the SSH client.
|
||||
*/
|
||||
|
@ -42,6 +42,9 @@ int guac_client_init(guac_client* client) {
|
||||
guac_telnet_client* telnet_client = calloc(1, sizeof(guac_telnet_client));
|
||||
client->data = telnet_client;
|
||||
|
||||
/* Init clipboard */
|
||||
telnet_client->clipboard = guac_common_clipboard_alloc(GUAC_TELNET_CLIPBOARD_MAX_LENGTH);
|
||||
|
||||
/* Init telnet client */
|
||||
telnet_client->socket_fd = -1;
|
||||
telnet_client->naws_enabled = 0;
|
||||
@ -89,6 +92,7 @@ int guac_telnet_client_free_handler(guac_client* client) {
|
||||
if (telnet_client->settings != NULL)
|
||||
guac_telnet_settings_free(telnet_client->settings);
|
||||
|
||||
guac_common_clipboard_free(telnet_client->clipboard);
|
||||
free(telnet_client);
|
||||
return 0;
|
||||
|
||||
|
@ -29,6 +29,11 @@
|
||||
|
||||
#include <libtelnet.h>
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow within the clipboard.
|
||||
*/
|
||||
#define GUAC_TELNET_CLIPBOARD_MAX_LENGTH 262144
|
||||
|
||||
/**
|
||||
* Free handler. Required by libguac and called when the guac_client is
|
||||
* disconnected and must be cleaned up.
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "clipboard.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "telnet.h"
|
||||
#include "terminal/terminal.h"
|
||||
|
||||
@ -32,7 +33,7 @@ int guac_telnet_clipboard_handler(guac_user* user, guac_stream* stream,
|
||||
/* Clear clipboard and prepare for new data */
|
||||
guac_client* client = user->client;
|
||||
guac_telnet_client* telnet_client = (guac_telnet_client*) client->data;
|
||||
guac_terminal_clipboard_reset(telnet_client->term, mimetype);
|
||||
guac_common_clipboard_reset(telnet_client->clipboard, mimetype);
|
||||
|
||||
/* Set handlers for clipboard stream */
|
||||
stream->blob_handler = guac_telnet_clipboard_blob_handler;
|
||||
@ -47,7 +48,7 @@ int guac_telnet_clipboard_blob_handler(guac_user* user, guac_stream* stream,
|
||||
/* Append new data */
|
||||
guac_client* client = user->client;
|
||||
guac_telnet_client* telnet_client = (guac_telnet_client*) client->data;
|
||||
guac_terminal_clipboard_append(telnet_client->term, data, length);
|
||||
guac_common_clipboard_append(telnet_client->clipboard, data, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -478,6 +478,7 @@ void* guac_telnet_client_thread(void* data) {
|
||||
|
||||
/* Create terminal */
|
||||
telnet_client->term = guac_terminal_create(client,
|
||||
telnet_client->clipboard,
|
||||
settings->font_name, settings->font_size,
|
||||
settings->resolution, settings->width, settings->height,
|
||||
settings->color_scheme, settings->backspace);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define GUAC_TELNET_H
|
||||
|
||||
#include "config.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "common/recording.h"
|
||||
#include "settings.h"
|
||||
#include "terminal/terminal.h"
|
||||
@ -66,6 +67,11 @@ typedef struct guac_telnet_client {
|
||||
*/
|
||||
int echo_enabled;
|
||||
|
||||
/**
|
||||
* The current clipboard contents.
|
||||
*/
|
||||
guac_common_clipboard* clipboard;
|
||||
|
||||
/**
|
||||
* The terminal which will render all output from the telnet client.
|
||||
*/
|
||||
|
@ -502,6 +502,7 @@ static void guac_terminal_parse_color_scheme(guac_client* client,
|
||||
}
|
||||
|
||||
guac_terminal* guac_terminal_create(guac_client* client,
|
||||
guac_common_clipboard* clipboard,
|
||||
const char* font_name, int font_size, int dpi,
|
||||
int width, int height, const char* color_scheme,
|
||||
const int backspace) {
|
||||
@ -582,6 +583,7 @@ guac_terminal* guac_terminal_create(guac_client* client,
|
||||
/* Init terminal state */
|
||||
term->current_attributes = default_char.attributes;
|
||||
term->default_char = default_char;
|
||||
term->clipboard = clipboard;
|
||||
|
||||
/* Set pixel size */
|
||||
term->width = width;
|
||||
@ -632,9 +634,6 @@ guac_terminal* guac_terminal_create(guac_client* client,
|
||||
term->current_cursor = GUAC_TERMINAL_CURSOR_BLANK;
|
||||
guac_common_cursor_set_blank(term->cursor);
|
||||
|
||||
/* Allocate clipboard */
|
||||
term->clipboard = guac_common_clipboard_alloc(GUAC_TERMINAL_CLIPBOARD_MAX_LENGTH);
|
||||
|
||||
/* Start terminal thread */
|
||||
if (pthread_create(&(term->thread), NULL,
|
||||
guac_terminal_thread, (void*) term)) {
|
||||
@ -682,9 +681,6 @@ void guac_terminal_free(guac_terminal* term) {
|
||||
/* Free buffer */
|
||||
guac_terminal_buffer_free(term->buffer);
|
||||
|
||||
/* Free clipboard */
|
||||
guac_common_clipboard_free(term->clipboard);
|
||||
|
||||
/* Free scrollbar */
|
||||
guac_terminal_scrollbar_free(term->scrollbar);
|
||||
|
||||
@ -2028,14 +2024,6 @@ void guac_terminal_scroll_handler(guac_terminal_scrollbar* scrollbar, int value)
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_clipboard_reset(guac_terminal* term, const char* mimetype) {
|
||||
guac_common_clipboard_reset(term->clipboard, mimetype);
|
||||
}
|
||||
|
||||
void guac_terminal_clipboard_append(guac_terminal* term, const void* data, int length) {
|
||||
guac_common_clipboard_append(term->clipboard, data, length);
|
||||
}
|
||||
|
||||
int guac_terminal_sendf(guac_terminal* term, const char* format, ...) {
|
||||
|
||||
int written;
|
||||
|
@ -58,11 +58,6 @@
|
||||
*/
|
||||
#define GUAC_TERMINAL_WHEEL_SCROLL_AMOUNT 3
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow within the clipboard.
|
||||
*/
|
||||
#define GUAC_TERMINAL_CLIPBOARD_MAX_LENGTH 262144
|
||||
|
||||
/**
|
||||
* The name of the color scheme having black foreground and white background.
|
||||
*/
|
||||
@ -443,7 +438,10 @@ struct guac_terminal {
|
||||
guac_terminal_cursor_type current_cursor;
|
||||
|
||||
/**
|
||||
* The current contents of the clipboard.
|
||||
* The current contents of the clipboard. This clipboard instance is
|
||||
* maintained externally (will not be freed when this terminal is freed)
|
||||
* and will be updated both internally by the terminal and externally
|
||||
* through received clipboard instructions.
|
||||
*/
|
||||
guac_common_clipboard* clipboard;
|
||||
|
||||
@ -461,6 +459,13 @@ struct guac_terminal {
|
||||
* @param client
|
||||
* The client to which the terminal will be rendered.
|
||||
*
|
||||
* @param clipboard
|
||||
* The guac_common_clipboard which will contain the current clipboard
|
||||
* state. It is expected that this clipboard instance will be updated
|
||||
* both internally by the terminal and externally through received
|
||||
* clipboard instructions. This clipboard will not be automatically
|
||||
* freed when this terminal is freed.
|
||||
*
|
||||
* @param font_name
|
||||
* The name of the font to use when rendering glyphs.
|
||||
*
|
||||
@ -493,6 +498,7 @@ struct guac_terminal {
|
||||
* which renders all text to the given client.
|
||||
*/
|
||||
guac_terminal* guac_terminal_create(guac_client* client,
|
||||
guac_common_clipboard* clipboard,
|
||||
const char* font_name, int font_size, int dpi,
|
||||
int width, int height, const char* color_scheme,
|
||||
const int backspace);
|
||||
@ -592,17 +598,6 @@ int guac_terminal_send_mouse(guac_terminal* term, guac_user* user,
|
||||
*/
|
||||
void guac_terminal_scroll_handler(guac_terminal_scrollbar* scrollbar, int value);
|
||||
|
||||
/**
|
||||
* Clears the current clipboard contents and sets the mimetype for future
|
||||
* contents.
|
||||
*/
|
||||
void guac_terminal_clipboard_reset(guac_terminal* term, const char* mimetype);
|
||||
|
||||
/**
|
||||
* Appends the given data to the current clipboard.
|
||||
*/
|
||||
void guac_terminal_clipboard_append(guac_terminal* term, const void* data, int length);
|
||||
|
||||
/**
|
||||
* Replicates the current display state to a user that has just joined the
|
||||
* connection. All instructions necessary to replicate state are sent over the
|
||||
|
Loading…
Reference in New Issue
Block a user