Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUACAMOLE-1026: Use LoadChannels callback method to load plugins with FreeRDP3. #546

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,30 @@ then
[AC_MSG_RESULT([no])])
fi

if test "x${have_freerdp}" = "xyes"
then
AC_MSG_CHECKING([whether freerdp instance supports LoadChannels])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <freerdp/freerdp.h>

/* Mock LoadChannels function with the expected signature */
BOOL load_channels(freerdp* instance) {
return TRUE;
}

int main() {
freerdp* instance = freerdp_new();
instance->LoadChannels = load_channels;
freerdp_free(instance);
return 0;
}
]])],
[AC_MSG_RESULT([yes])]
[AC_DEFINE([RDP_INST_HAS_LOAD_CHANNELS],,
[Defined if freerdp instance supports LoadChannels])],
[AC_MSG_RESULT([no])])
fi

# Restore CPPFLAGS, removing FreeRDP-specific options needed for testing
CPPFLAGS="$OLDCPPFLAGS"

Expand Down
103 changes: 80 additions & 23 deletions src/protocols/rdp/rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,29 @@
#include <stdlib.h>
#include <time.h>

BOOL rdp_freerdp_pre_connect(freerdp* instance) {

/**
* Initializes and loads the necessary FreeRDP plugins based on the current
* RDP session settings. This function is designed to work in environments
* where the FreeRDP instance expects a LoadChannels callback to be set
* otherwise it can becalled directly from our pre_connect callback. It
* configures various features such as display resizing, multi-touch support,
* audio input, clipboard synchronization, device redirection, and graphics
* pipeline, by loading their corresponding plugins if they are enabled in the
* session settings.
*
* @param instance
* The FreeRDP instance to be prepared, containing all context and
* settings for the session.
*
* @return
* Always TRUE.
*/
static BOOL rdp_freerdp_load_channels(freerdp* instance) {
rdpContext* context = GUAC_RDP_CONTEXT(instance);
rdpGraphics* graphics = context->graphics;

guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_settings* settings = rdp_client->settings;

/* Push desired settings to FreeRDP */
guac_rdp_push_settings(client, settings, instance);

/* Init FreeRDP add-in provider */
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);

/* Load "disp" plugin for display update */
if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
guac_rdp_disp_load_plugin(context);
Expand Down Expand Up @@ -125,6 +133,53 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
guac_rdpsnd_load_plugin(context);
}

/* Load "rdpgfx" plugin for Graphics Pipeline Extension */
if (settings->enable_gfx)
guac_rdp_rdpgfx_load_plugin(context);

/* Load plugin providing Dynamic Virtual Channel support, if required */
if (freerdp_settings_get_bool(GUAC_RDP_CONTEXT(instance)->settings, FreeRDP_SupportDynamicChannels) &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
GUAC_RDP_CONTEXT(instance)->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
}

return TRUE;
}

/**
* Prepares the FreeRDP instance for connection by setting up session-specific
* configurations like graphics, plugins, and RDP settings. This involves
* integrating Guacamole's custom rendering handlers (for bitmaps, glyphs,
* and pointers). If using a freerdp instance that does not expect a
* LoadChannels callback then this function manually loads RDP channels.
*
* @param instance
* The FreeRDP instance to be prepared, containing all context and
* settings for the session.
*
* @return
* Returns TRUE if the pre-connection process completes successfully.
* Returns FALSE if an error occurs during the initialization of the
* FreeRDP GDI system.
*/
static BOOL rdp_freerdp_pre_connect(freerdp* instance) {

rdpContext* context = GUAC_RDP_CONTEXT(instance);
rdpGraphics* graphics = context->graphics;

guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_settings* settings = rdp_client->settings;

/* Push desired settings to FreeRDP */
guac_rdp_push_settings(client, settings, instance);

/* Init FreeRDP add-in provider */
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);

/* Load RAIL plugin if RemoteApp in use */
if (settings->remote_app != NULL)
guac_rdp_rail_load_plugin(context);
Expand Down Expand Up @@ -194,21 +249,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
primary->MemBlt = guac_rdp_gdi_memblt;
primary->OpaqueRect = guac_rdp_gdi_opaquerect;

/* Load "rdpgfx" plugin for Graphics Pipeline Extension */
if (settings->enable_gfx)
guac_rdp_rdpgfx_load_plugin(context);

/* Load plugin providing Dynamic Virtual Channel support, if required */
if (freerdp_settings_get_bool(GUAC_RDP_CONTEXT(instance)->settings, FreeRDP_SupportDynamicChannels) &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
GUAC_RDP_CONTEXT(instance)->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
}
/*
* If the freerdp instance does not have a LoadChannels callback for
* loading plugins we use the PreConnect callback to load plugins instead.
*/
#ifndef RDP_INST_HAS_LOAD_CHANNELS
rdp_freerdp_load_channels(instance);
jmuehlner marked this conversation as resolved.
Show resolved Hide resolved
#endif

return TRUE;

}

/**
Expand Down Expand Up @@ -489,6 +538,14 @@ static int guac_rdp_handle_connection(guac_client* client) {

/* Init client */
freerdp* rdp_inst = freerdp_new();

/*
* If the freerdp instance has a LoadChannels callback for loading plugins
* we use that instead of the PreConnect callback to load plugins.
*/
#ifdef RDP_INST_HAS_LOAD_CHANNELS
rdp_inst->LoadChannels = rdp_freerdp_load_channels;
#endif
rdp_inst->PreConnect = rdp_freerdp_pre_connect;
rdp_inst->Authenticate = rdp_freerdp_authenticate;

Expand Down
Loading