You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by mj...@apache.org on 2016/03/20 03:24:49 UTC

[19/50] incubator-guacamole-server git commit: GUAC-1164: Automatically reconnect when display size changes.

GUAC-1164: Automatically reconnect when display size changes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/fc40e9f1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/fc40e9f1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/fc40e9f1

Branch: refs/heads/master
Commit: fc40e9f14cc3fbd89497000fd45d8332a391676f
Parents: f5f77fe
Author: Michael Jumper <mi...@guac-dev.org>
Authored: Tue Mar 15 21:23:19 2016 -0700
Committer: Michael Jumper <mi...@guac-dev.org>
Committed: Tue Mar 15 21:48:56 2016 -0700

----------------------------------------------------------------------
 src/protocols/rdp/client.c   |  57 +++------------------
 src/protocols/rdp/input.c    |  51 ++++++++++---------
 src/protocols/rdp/rdp.c      | 102 +++++++++++++++++++++++++++++---------
 src/protocols/rdp/rdp.h      |  11 ++--
 src/protocols/rdp/rdp_disp.c |  74 +++++++++++++++++----------
 src/protocols/rdp/rdp_disp.h |  84 ++++++++++++++++++++++++-------
 6 files changed, 231 insertions(+), 148 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/fc40e9f1/src/protocols/rdp/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c
index 940635f..4efb695 100644
--- a/src/protocols/rdp/client.c
+++ b/src/protocols/rdp/client.c
@@ -24,6 +24,7 @@
 
 #include "client.h"
 #include "rdp.h"
+#include "rdp_disp.h"
 #include "rdp_keymap.h"
 #include "user.h"
 
@@ -33,10 +34,6 @@
 #include <guac_ssh_user.h>
 #endif
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-#include "rdp_disp.h"
-#endif
-
 #include <freerdp/cache/cache.h>
 #include <freerdp/channels/channels.h>
 #include <freerdp/freerdp.h>
@@ -66,10 +63,11 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
     guac_rdp_client* rdp_client = calloc(1, sizeof(guac_rdp_client));
     client->data = rdp_client;
 
-    /* Init clipboard and shared mouse */
+    /* Init clipboard */
     rdp_client->clipboard = guac_common_clipboard_alloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH);
-    rdp_client->requested_clipboard_format = CB_FORMAT_TEXT;
-    rdp_client->available_svc = guac_common_list_alloc();
+
+    /* Init display update module */
+    rdp_client->disp = guac_rdp_disp_alloc();
 
     /* Recursive attribute for locks */
     pthread_mutexattr_init(&(rdp_client->attributes));
@@ -98,54 +96,15 @@ int guac_rdp_client_free_handler(guac_client* client) {
     /* Wait for client thread */
     pthread_join(rdp_client->client_thread, NULL);
 
-    freerdp* rdp_inst = rdp_client->rdp_inst;
-    if (rdp_inst != NULL) {
-        rdpChannels* channels = rdp_inst->context->channels;
-
-        /* Clean up RDP client */
-        freerdp_channels_close(channels, rdp_inst);
-        freerdp_channels_free(channels);
-        freerdp_disconnect(rdp_inst);
-        freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv);
-        cache_free(rdp_inst->context->cache);
-        freerdp_free(rdp_inst);
-    }
-
-    /* Clean up filesystem, if allocated */
-    if (rdp_client->filesystem != NULL)
-        guac_rdp_fs_free(rdp_client->filesystem);
-
-#ifdef ENABLE_COMMON_SSH
-    /* Free SFTP filesystem, if loaded */
-    if (rdp_client->sftp_filesystem)
-        guac_common_ssh_destroy_sftp_filesystem(rdp_client->sftp_filesystem);
-
-    /* Free SFTP session */
-    if (rdp_client->sftp_session)
-        guac_common_ssh_destroy_session(rdp_client->sftp_session);
-
-    /* Free SFTP user */
-    if (rdp_client->sftp_user)
-        guac_common_ssh_destroy_user(rdp_client->sftp_user);
-
-    guac_common_ssh_uninit();
-#endif
-
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-    /* Free display update module */
-    guac_rdp_disp_free(rdp_client->disp);
-#endif
-
-    /* Free SVC list */
-    guac_common_list_free(rdp_client->available_svc);
-
     /* Free parsed settings */
     if (rdp_client->settings != NULL)
         guac_rdp_settings_free(rdp_client->settings);
 
+    /* Free display update module */
+    guac_rdp_disp_free(rdp_client->disp);
+
     /* Free client data */
     guac_common_clipboard_free(rdp_client->clipboard);
-    guac_common_display_free(rdp_client->display);
     free(rdp_client);
 
     return 0;

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/fc40e9f1/src/protocols/rdp/input.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/input.c b/src/protocols/rdp/input.c
index e87440a..8a8cbaf 100644
--- a/src/protocols/rdp/input.c
+++ b/src/protocols/rdp/input.c
@@ -25,27 +25,19 @@
 #include "client.h"
 #include "input.h"
 #include "rdp.h"
+#include "rdp_disp.h"
 #include "rdp_keymap.h"
 
 #include <freerdp/freerdp.h>
 #include <freerdp/input.h>
 #include <guacamole/client.h>
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-#include "rdp_disp.h"
-#endif
-
 #include <pthread.h>
 #include <stdlib.h>
 
 int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
 
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
-    freerdp* rdp_inst = rdp_client->rdp_inst;
-
-    /* Skip if not yet connected */
-    if (rdp_inst == NULL)
-        return 0;
 
     /* If keysym can be in lookup table */
     if (GUAC_RDP_KEYSYM_STORABLE(keysym)) {
@@ -75,6 +67,13 @@ int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
             else
                 pressed_flags = KBD_FLAGS_RELEASE;
 
+            /* Skip if not yet connected */
+            freerdp* rdp_inst = rdp_client->rdp_inst;
+            if (rdp_inst == NULL) {
+                pthread_mutex_unlock(&(rdp_client->rdp_lock));
+                return 0;
+            }
+
             /* Send actual key */
             rdp_inst->input->KeyboardEvent(rdp_inst->input, keysym_desc->flags | pressed_flags,
                     keysym_desc->scancode);
@@ -118,6 +117,13 @@ int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
 
         pthread_mutex_lock(&(rdp_client->rdp_lock));
 
+        /* Skip if not yet connected */
+        freerdp* rdp_inst = rdp_client->rdp_inst;
+        if (rdp_inst == NULL) {
+            pthread_mutex_unlock(&(rdp_client->rdp_lock));
+            return 0;
+        }
+
         /* Send Unicode event */
         rdp_inst->input->UnicodeKeyboardEvent(
                 rdp_inst->input,
@@ -156,16 +162,18 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
 
     guac_client* client = user->client;
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
-    freerdp* rdp_inst = rdp_client->rdp_inst;
+
+    pthread_mutex_lock(&(rdp_client->rdp_lock));
 
     /* Store current mouse location */
     guac_common_cursor_move(rdp_client->display->cursor, user, x, y);
 
     /* Skip if not yet connected */
-    if (rdp_inst == NULL)
+    freerdp* rdp_inst = rdp_client->rdp_inst;
+    if (rdp_inst == NULL) {
+        pthread_mutex_unlock(&(rdp_client->rdp_lock));
         return 0;
-
-    pthread_mutex_lock(&(rdp_client->rdp_lock));
+    }
 
     /* If button mask unchanged, just send move event */
     if (mask == rdp_client->mouse_button_mask)
@@ -251,28 +259,19 @@ int guac_rdp_user_key_handler(guac_user* user, int keysym, int pressed) {
 
 int guac_rdp_user_size_handler(guac_user* user, int width, int height) {
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
     guac_client* client = user->client;
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
-
+    guac_rdp_settings* settings = rdp_client->settings;
     freerdp* rdp_inst = rdp_client->rdp_inst;
 
-    /* Skip if not yet connected */
-    if (rdp_inst == NULL)
-        return 0;
-
     /* Convert client pixels to remote pixels */
-    width  = width  * rdp_client->settings->resolution
-                    / user->info.optimal_resolution;
-
-    height = height * rdp_client->settings->resolution
-                    / user->info.optimal_resolution;
+    width  = width  * settings->resolution / user->info.optimal_resolution;
+    height = height * settings->resolution / user->info.optimal_resolution;
 
     /* Send display update */
     pthread_mutex_lock(&(rdp_client->rdp_lock));
-    guac_rdp_disp_set_size(rdp_client->disp, rdp_inst->context, width, height);
+    guac_rdp_disp_set_size(rdp_client->disp, settings, rdp_inst, width, height);
     pthread_mutex_unlock(&(rdp_client->rdp_lock));
-#endif
 
     return 0;
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/fc40e9f1/src/protocols/rdp/rdp.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index 9dea54b..a19e55b 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -29,6 +29,7 @@
 #include "rdp.h"
 #include "rdp_bitmap.h"
 #include "rdp_cliprdr.h"
+#include "rdp_disp.h"
 #include "rdp_gdi.h"
 #include "rdp_glyph.h"
 #include "rdp_keymap.h"
@@ -43,10 +44,6 @@
 #include <guac_ssh_user.h>
 #endif
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-#include "rdp_disp.h"
-#endif
-
 #include <freerdp/cache/bitmap.h>
 #include <freerdp/cache/brush.h>
 #include <freerdp/cache/glyph.h>
@@ -183,8 +180,8 @@ static void guac_rdp_channel_connected(rdpContext* context,
         guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
 
         /* Init module with current display size */
-        guac_rdp_disp_set_size(rdp_client->disp, context,
-                guac_rdp_get_width(context->instance),
+        guac_rdp_disp_set_size(rdp_client->disp, rdp_client->settings,
+                context->instance, guac_rdp_get_width(context->instance),
                 guac_rdp_get_height(context->instance));
 
         /* Store connected channel */
@@ -223,17 +220,14 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
             (pChannelConnectedEventHandler) guac_rdp_channel_connected);
 #endif
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
     /* Load virtual channel management plugin */
     if (freerdp_channels_load_plugin(channels, instance->settings,
                 "drdynvc", instance->settings))
         guac_client_log(client, GUAC_LOG_WARNING,
                 "Failed to load drdynvc plugin.");
 
-    /* Init display update plugin */
-    rdp_client->disp = guac_rdp_disp_alloc();
+    /* Init display update plugin (if available) */
     guac_rdp_disp_load_plugin(instance->context);
-#endif
 
     /* Load clipboard plugin */
     if (freerdp_channels_load_plugin(channels, instance->settings,
@@ -691,9 +685,8 @@ static int rdp_guac_client_wait_for_messages(guac_client* client,
 
 }
 
-void* guac_rdp_client_thread(void* data) {
+static int guac_rdp_handle_connection(guac_client* client) {
 
-    guac_client* client = (guac_client*) data;
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     guac_rdp_settings* settings = rdp_client->settings;
 
@@ -715,6 +708,9 @@ void* guac_rdp_client_thread(void* data) {
 
     rdp_client->current_surface = rdp_client->display->default_surface;
 
+    rdp_client->requested_clipboard_format = CB_FORMAT_TEXT;
+    rdp_client->available_svc = guac_common_list_alloc();
+
 #ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT
     freerdp_channels_global_init();
 #endif
@@ -750,7 +746,7 @@ void* guac_rdp_client_thread(void* data) {
 
         /* Abort if username is missing */
         if (settings->sftp_username == NULL)
-            return NULL;
+            return 1;
 
         guac_client_log(client, GUAC_LOG_DEBUG,
                 "Connecting via SSH for SFTP filesystem access.");
@@ -769,7 +765,7 @@ void* guac_rdp_client_thread(void* data) {
                         settings->sftp_private_key,
                         settings->sftp_passphrase)) {
                 guac_common_ssh_destroy_user(rdp_client->sftp_user);
-                return NULL;
+                return 1;
             }
 
         }
@@ -794,7 +790,7 @@ void* guac_rdp_client_thread(void* data) {
         if (rdp_client->sftp_session == NULL) {
             /* Already aborted within guac_common_ssh_create_session() */
             guac_common_ssh_destroy_user(rdp_client->sftp_user);
-            return NULL;
+            return 1;
         }
 
         /* Load and expose filesystem */
@@ -811,7 +807,7 @@ void* guac_rdp_client_thread(void* data) {
         if (rdp_client->sftp_filesystem == NULL) {
             guac_common_ssh_destroy_session(rdp_client->sftp_session);
             guac_common_ssh_destroy_user(rdp_client->sftp_user);
-            return NULL;
+            return 1;
         }
 
         guac_client_log(client, GUAC_LOG_DEBUG,
@@ -833,7 +829,7 @@ void* guac_rdp_client_thread(void* data) {
     if (!freerdp_connect(rdp_inst)) {
         guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
                 "Error connecting to RDP server");
-        return NULL;
+        return 1;
     }
 
     /* Connection complete */
@@ -842,15 +838,17 @@ void* guac_rdp_client_thread(void* data) {
 
     guac_timestamp last_frame_end = guac_timestamp_current();
 
+    /* Signal that reconnect has been completed */
+    guac_rdp_disp_reconnect_complete(rdp_client->disp);
+
     /* Handle messages from RDP server while client is running */
-    while (client->state == GUAC_CLIENT_RUNNING) {
+    while (client->state == GUAC_CLIENT_RUNNING
+            && !guac_rdp_disp_reconnect_needed(rdp_client->disp)) {
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
         /* Update remote display size */
         pthread_mutex_lock(&(rdp_client->rdp_lock));
-        guac_rdp_disp_update_size(rdp_client->disp, rdp_inst->context);
+        guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst);
         pthread_mutex_unlock(&(rdp_client->rdp_lock));
-#endif
 
         /* Wait for data and construct a reasonable frame */
         int wait_result = rdp_guac_client_wait_for_messages(client,
@@ -873,7 +871,7 @@ void* guac_rdp_client_thread(void* data) {
                     guac_client_log(client, GUAC_LOG_DEBUG,
                             "Error handling RDP file descriptors");
                     pthread_mutex_unlock(&(rdp_client->rdp_lock));
-                    return NULL;
+                    return 1;
                 }
 
                 /* Check channel fds */
@@ -881,7 +879,7 @@ void* guac_rdp_client_thread(void* data) {
                     guac_client_log(client, GUAC_LOG_DEBUG,
                             "Error handling RDP channel file descriptors");
                     pthread_mutex_unlock(&(rdp_client->rdp_lock));
-                    return NULL;
+                    return 1;
                 }
 
                 /* Check for channel events */
@@ -910,7 +908,7 @@ void* guac_rdp_client_thread(void* data) {
                     guac_client_log(client, GUAC_LOG_INFO,
                             "RDP server closed connection");
                     pthread_mutex_unlock(&(rdp_client->rdp_lock));
-                    return NULL;
+                    return 1;
                 }
 
                 pthread_mutex_unlock(&(rdp_client->rdp_lock));
@@ -955,6 +953,62 @@ void* guac_rdp_client_thread(void* data) {
     }
 
     guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected");
+
+    pthread_mutex_lock(&(rdp_client->rdp_lock));
+
+    /* Clean up RDP client */
+    freerdp_channels_close(channels, rdp_inst);
+    freerdp_channels_free(channels);
+    freerdp_disconnect(rdp_inst);
+    freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv);
+    cache_free(rdp_inst->context->cache);
+    freerdp_free(rdp_inst);
+
+    /* Clean up filesystem, if allocated */
+    if (rdp_client->filesystem != NULL)
+        guac_rdp_fs_free(rdp_client->filesystem);
+
+#ifdef ENABLE_COMMON_SSH
+    /* Free SFTP filesystem, if loaded */
+    if (rdp_client->sftp_filesystem)
+        guac_common_ssh_destroy_sftp_filesystem(rdp_client->sftp_filesystem);
+
+    /* Free SFTP session */
+    if (rdp_client->sftp_session)
+        guac_common_ssh_destroy_session(rdp_client->sftp_session);
+
+    /* Free SFTP user */
+    if (rdp_client->sftp_user)
+        guac_common_ssh_destroy_user(rdp_client->sftp_user);
+
+    guac_common_ssh_uninit();
+#endif
+
+    /* Free SVC list */
+    guac_common_list_free(rdp_client->available_svc);
+
+    /* Free display */
+    guac_common_display_free(rdp_client->display);
+
+    /* Mark FreeRDP instance as freed */
+    rdp_client->rdp_inst = NULL;
+
+    pthread_mutex_unlock(&(rdp_client->rdp_lock));
+    return 0;
+
+}
+
+void* guac_rdp_client_thread(void* data) {
+
+    guac_client* client = (guac_client*) data;
+
+    while (client->state == GUAC_CLIENT_RUNNING) {
+
+        if (guac_rdp_handle_connection(client))
+            return NULL;
+
+    }
+
     return NULL;
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/fc40e9f1/src/protocols/rdp/rdp.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp.h b/src/protocols/rdp/rdp.h
index b648216..fac0435 100644
--- a/src/protocols/rdp/rdp.h
+++ b/src/protocols/rdp/rdp.h
@@ -29,6 +29,7 @@
 #include "guac_display.h"
 #include "guac_surface.h"
 #include "guac_list.h"
+#include "rdp_disp.h"
 #include "rdp_fs.h"
 #include "rdp_keymap.h"
 #include "rdp_settings.h"
@@ -44,10 +45,6 @@
 #include "guac_ssh_user.h"
 #endif
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
-#include "rdp_disp.h"
-#endif
-
 #include <pthread.h>
 #include <stdint.h>
 
@@ -148,12 +145,10 @@ typedef struct guac_rdp_client {
     guac_common_ssh_sftp_filesystem* sftp_filesystem;
 #endif
 
-#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
     /**
      * Display size update module.
      */
     guac_rdp_disp* disp;
-#endif
 
     /**
      * List of all available static virtual channels.
@@ -161,7 +156,9 @@ typedef struct guac_rdp_client {
     guac_common_list* available_svc;
 
     /**
-     * Lock which is locked and unlocked for each RDP message.
+     * Lock which is locked and unlocked for each RDP message, and for each
+     * part of the RDP client instance which may be dynamically freed and
+     * reallocated during reconnection.
      */
     pthread_mutex_t rdp_lock;
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/fc40e9f1/src/protocols/rdp/rdp_disp.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_disp.c b/src/protocols/rdp/rdp_disp.c
index a94d594..ea65289 100644
--- a/src/protocols/rdp/rdp_disp.c
+++ b/src/protocols/rdp/rdp_disp.c
@@ -24,6 +24,7 @@
 #include "client.h"
 #include "rdp.h"
 #include "rdp_disp.h"
+#include "rdp_settings.h"
 
 #include <freerdp/freerdp.h>
 #include <freerdp/client/disp.h>
@@ -41,6 +42,7 @@ guac_rdp_disp* guac_rdp_disp_alloc() {
     disp->last_request = 0;
     disp->requested_width  = 0;
     disp->requested_height = 0;
+    disp->reconnect_needed = 0;
 
     return disp;
 
@@ -52,6 +54,7 @@ void guac_rdp_disp_free(guac_rdp_disp* disp) {
 
 void guac_rdp_disp_load_plugin(rdpContext* context) {
 
+#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
 #ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL
     context->settings->SupportDisplayControl = TRUE;
 #endif
@@ -62,6 +65,7 @@ void guac_rdp_disp_load_plugin(rdpContext* context) {
     args->argv = malloc(sizeof(char**) * 1);
     args->argv[0] = strdup("disp");
     freerdp_dynamic_channel_collection_add(context->settings, args);
+#endif
 
 }
 
@@ -111,8 +115,8 @@ static void guac_rdp_disp_fit(int* a, int* b) {
 
 }
 
-void guac_rdp_disp_set_size(guac_rdp_disp* disp, rdpContext* context,
-        int width, int height) {
+void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings,
+        freerdp* rdp_inst, int width, int height) {
 
     /* Fit width within bounds, adjusting height to maintain aspect ratio */
     guac_rdp_disp_fit(&width, &height);
@@ -129,21 +133,47 @@ void guac_rdp_disp_set_size(guac_rdp_disp* disp, rdpContext* context,
     disp->requested_height = height;
 
     /* Send display update notification if possible */
-    guac_rdp_disp_update_size(disp, context);
+    guac_rdp_disp_update_size(disp, settings, rdp_inst);
 
 }
 
-void guac_rdp_disp_update_size(guac_rdp_disp* disp, rdpContext* context) {
+void guac_rdp_disp_update_size(guac_rdp_disp* disp,
+        guac_rdp_settings* settings, freerdp* rdp_inst) {
 
-    guac_client* client = ((rdp_freerdp_context*) context)->client;
+    int width = disp->requested_width;
+    int height = disp->requested_height;
 
-    /* Send display update notification if display channel is connected */
-    if (disp->disp == NULL)
+    /* Do not update size if no requests have been received */
+    if (width == 0 || height == 0)
         return;
 
-    int width = disp->requested_width;
-    int height = disp->requested_height;
+    guac_timestamp now = guac_timestamp_current();
+
+    /* Limit display update frequency */
+    if (disp->last_request != 0
+            && now - disp->last_request <= GUAC_RDP_DISP_UPDATE_INTERVAL)
+        return;
+
+    /* Do NOT send requests unless the size will change */
+    if (rdp_inst != NULL
+            && width == guac_rdp_get_width(rdp_inst)
+            && height == guac_rdp_get_height(rdp_inst))
+        return;
+
+    disp->last_request = now;
+
+    if (1) {
+        /* Update settings with new dimensions */
+        settings->width = width;
+        settings->height = height;
 
+        /* Signal reconnect */
+        disp->reconnect_needed = 1;
+        disp->disp = NULL;
+        return;
+    }
+
+#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
     DISPLAY_CONTROL_MONITOR_LAYOUT monitors[1] = {{
         .Flags  = 0x1, /* DISPLAYCONTROL_MONITOR_PRIMARY */
         .Left = 0,
@@ -157,24 +187,18 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp, rdpContext* context) {
         .DeviceScaleFactor = 0
     }};
 
-    guac_timestamp now = guac_timestamp_current();
-
-    /* Limit display update frequency */
-    if (disp->last_request != 0
-            && now - disp->last_request <= GUAC_RDP_DISP_UPDATE_INTERVAL)
-        return;
-
-    /* Do NOT send requests unless the size will change */
-    if (width == guac_rdp_get_width(context->instance)
-            && height == guac_rdp_get_height(context->instance))
-        return;
+    /* Send display update notification if display channel is connected */
+    if (disp->disp != NULL)
+        disp->disp->SendMonitorLayout(disp->disp, 1, monitors);
+#endif
 
-    guac_client_log(client, GUAC_LOG_DEBUG,
-            "Resizing remote display to %ix%i",
-            width, height);
+}
 
-    disp->last_request = now;
-    disp->disp->SendMonitorLayout(disp->disp, 1, monitors);
+int guac_rdp_disp_reconnect_needed(guac_rdp_disp* disp) {
+    return disp->reconnect_needed;
+}
 
+void guac_rdp_disp_reconnect_complete(guac_rdp_disp* disp) {
+    disp->reconnect_needed = 0;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/fc40e9f1/src/protocols/rdp/rdp_disp.h
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_disp.h b/src/protocols/rdp/rdp_disp.h
index 375f476..eb33047 100644
--- a/src/protocols/rdp/rdp_disp.h
+++ b/src/protocols/rdp/rdp_disp.h
@@ -23,6 +23,8 @@
 #ifndef GUAC_RDP_DISP_H
 #define GUAC_RDP_DISP_H
 
+#include "rdp_settings.h"
+
 #include <freerdp/client/disp.h>
 #include <freerdp/freerdp.h>
 
@@ -68,6 +70,12 @@ typedef struct guac_rdp_disp {
      */
     int requested_height;
 
+    /**
+     * Whether the size has changed and the RDP connection must be closed and
+     * reestablished.
+     */
+    int reconnect_needed;
+
 } guac_rdp_disp;
 
 /**
@@ -113,30 +121,72 @@ void guac_rdp_disp_connect(guac_rdp_disp* guac_disp, DispClientContext* disp);
  * be automatically altered to comply with the restrictions imposed by the
  * display update channel.
  *
- * @param disp The display update module which should maintain the requested
- *             size, sending the corresponding display update request when
- *             appropriate.
- * @param context The rdpContext associated with the active RDP session.
- * @param width The desired display width, in pixels. Due to the restrictions
- *              of the RDP display update channel, this will be contrained to
- *              the range of 200 through 8192 inclusive, and rounded down to
- *              the nearest even number.
- * @param height The desired display height, in pixels. Due to the restrictions
- *               of the RDP display update channel, this will be contrained to
- *               the range of 200 through 8192 inclusive.
+ * @param disp
+ *     The display update module which should maintain the requested size,
+ *     sending the corresponding display update request when appropriate.
+ *
+ * @param settings
+ *     The RDP client settings associated with the current or pending RDP
+ *     session. These settings will be automatically adjusted to match the new
+ *     screen size.
+ *
+ * @param rdp_inst
+ *     The FreeRDP instance associated with the current or pending RDP session,
+ *     if any. If no RDP session is active, this should be NULL.
+ *
+ * @param width
+ *     The desired display width, in pixels. Due to the restrictions of the RDP
+ *     display update channel, this will be contrained to the range of 200
+ *     through 8192 inclusive, and rounded down to the nearest even number.
+ *
+ * @param height
+ *     The desired display height, in pixels. Due to the restrictions of the
+ *     RDP display update channel, this will be contrained to the range of 200
+ *     through 8192 inclusive.
  */
-void guac_rdp_disp_set_size(guac_rdp_disp* disp, rdpContext* context,
-        int width, int height);
+void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings,
+        freerdp* rdp_inst, int width, int height);
 
 /**
  * Sends an actual display update request to the RDP server based on previous
  * calls to guac_rdp_disp_set_size(). If an update was recently sent, the
- * update may be delayed until a future call to this function.
+ * update may be delayed until a future call to this function. If the RDP
+ * session has not yet been established, the request will be delayed until the
+ * session exists.
  *
- * @param disp The display update module which should track the update request.
- * @param context The rdpContext associated with the active RDP session.
+ * @param disp
+ *     The display update module which should track the update request.
+ *
+ * @param settings
+ *     The RDP client settings associated with the current or pending RDP
+ *     session. These settings will be automatically adjusted to match the new
+ *     screen size.
+ *
+ * @param rdp_inst
+ *     The FreeRDP instance associated with the current or pending RDP session,
+ *     if any. If no RDP session is active, this should be NULL.
+ */
+void guac_rdp_disp_update_size(guac_rdp_disp* disp,
+        guac_rdp_settings* settings, freerdp* rdp_inst);
+
+/**
+ * Signals the given display update module that the requested reconnect has
+ * been performed.
+ *
+ * @param disp
+ *     The display update module that should be signaled regarding the state
+ *     of reconnection.
+ */
+void guac_rdp_disp_reconnect_complete(guac_rdp_disp* disp);
+
+/**
+ * Returns whether a full RDP reconnect is required for display update changes
+ * to take effect.
+ *
+ * @return
+ *     Non-zero if a reconnect is needed, zero otherwise.
  */
-void guac_rdp_disp_update_size(guac_rdp_disp* disp, rdpContext* context);
+int guac_rdp_disp_reconnect_needed(guac_rdp_disp* disp);
 
 #endif