From 6dc8b57ca4abe704b43ad6afa9385e3207df9202 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 14 Oct 2019 11:12:53 -0700 Subject: [PATCH] GUACAMOLE-249: Update RAIL (RemoteApp) support to FreeRDP 2.0.0 API. --- src/protocols/rdp/Makefile.am | 4 +- src/protocols/rdp/rail.c | 136 +++++++++++++++++++++++ src/protocols/rdp/{rdp_rail.h => rail.h} | 34 ++---- src/protocols/rdp/rdp.c | 29 +---- src/protocols/rdp/rdp_rail.c | 97 ---------------- 5 files changed, 151 insertions(+), 149 deletions(-) create mode 100644 src/protocols/rdp/rail.c rename src/protocols/rdp/{rdp_rail.h => rail.h} (54%) delete mode 100644 src/protocols/rdp/rdp_rail.c diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am index a1d3600a..6cb60167 100644 --- a/src/protocols/rdp/Makefile.am +++ b/src/protocols/rdp/Makefile.am @@ -43,6 +43,7 @@ libguac_client_rdp_la_SOURCES = \ input.c \ keyboard.c \ ptr_string.c \ + rail.c \ rdp.c \ rdp_bitmap.c \ rdp_color.c \ @@ -52,7 +53,6 @@ libguac_client_rdp_la_SOURCES = \ rdp_keymap.c \ rdp_print_job.c \ rdp_pointer.c \ - rdp_rail.c \ rdp_settings.c \ rdp_stream.c \ resolution.c \ @@ -111,6 +111,7 @@ noinst_HEADERS = \ input.h \ keyboard.h \ ptr_string.h \ + rail.h \ rdp.h \ rdp_bitmap.h \ rdp_color.h \ @@ -120,7 +121,6 @@ noinst_HEADERS = \ rdp_keymap.h \ rdp_pointer.h \ rdp_print_job.h \ - rdp_rail.h \ rdp_settings.h \ rdp_status.h \ rdp_stream.h \ diff --git a/src/protocols/rdp/rail.c b/src/protocols/rdp/rail.c new file mode 100644 index 00000000..5f06155e --- /dev/null +++ b/src/protocols/rdp/rail.c @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" + +#include "channels.h" +#include "client.h" +#include "rail.h" +#include "rdp.h" +#include "rdp_settings.h" + +#include +#include +#include +#include + +#include + +/** + * Callback which is invoked when a Server System Parameters Update PDU is + * received from the RDP server. The Server System Parameters Update PDU, also + * referred to as a "sysparam order", is used by the server to update system + * parameters for RemoteApp. + * + * @param rail + * The RailClientContext structure used by FreeRDP to handle the RAIL + * channel for the current RDP session. + * + * @param sysparam + * The RAIL_SYSPARAM_ORDER structure representing the Server System + * Parameters Update PDU that was received. + * + * @return + * CHANNEL_RC_OK (zero) if the PDU was handled successfully, an error code + * (non-zero) otherwise. + */ +static UINT guac_rdp_rail_sysparam(RailClientContext* rail, + const RAIL_SYSPARAM_ORDER* sysparam) { + + guac_client* client = (guac_client*) rail->custom; + guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; + + RAIL_SYSPARAM_ORDER response = { + .workArea = { + .left = 0, + .top = 0, + .right = rdp_client->settings->width, + .bottom = rdp_client->settings->height + }, + .dragFullWindows = FALSE + }; + + return rail->ClientSystemParam(rail, &response); + +} + +/** + * Callback which associates handlers specific to Guacamole with the + * RailClientContext instance allocated by FreeRDP to deal with received + * RAIL (RemoteApp) messages. + * + * This function is called whenever a channel connects via the PubSub event + * system within FreeRDP, but only has any effect if the connected channel is + * the RAIL channel. This specific callback is registered with the PubSub + * system of the relevant rdpContext when guac_rdp_rail_load_plugin() is + * called. + * + * @param context + * The rdpContext associated with the active RDP session. + * + * @param e + * Event-specific arguments, mainly the name of the channel, and a + * reference to the associated plugin loaded for that channel by FreeRDP. + */ +static void guac_rdp_rail_channel_connected(rdpContext* context, + ChannelConnectedEventArgs* e) { + + guac_client* client = ((rdp_freerdp_context*) context)->client; + + /* Ignore connection event if it's not for the RAIL channel */ + if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) != 0) + return; + + /* The structure pointed to by pInterface is guaranteed to be a + * RailClientContext if the channel is RAIL */ + RailClientContext* rail = (RailClientContext*) e->pInterface; + + /* Init FreeRDP RAIL context, ensuring the guac_client can be accessed from + * within any RAIL-specific callbacks */ + rail->custom = client; + rail->ServerSystemParam = guac_rdp_rail_sysparam; + + guac_client_log(client, GUAC_LOG_DEBUG, "RAIL (RemoteApp) channel " + "connected."); + +} + +void guac_rdp_rail_load_plugin(rdpContext* context) { + + guac_client* client = ((rdp_freerdp_context*) context)->client; + + /* Attempt to load FreeRDP support for the RAIL channel */ + if (guac_freerdp_channels_load_plugin(context->channels, context->settings, "rail", context->settings)) { + guac_client_log(client, GUAC_LOG_WARNING, + "Support for the RAIL channel (RemoteApp) could not be " + "loaded. This support normally takes the form of a plugin " + "which is built into FreeRDP. Lacking this support, " + "RemoteApp will not work."); + return; + } + + /* Complete RDP side of initialization when channel is connected */ + PubSub_SubscribeChannelConnected(context->pubSub, + (pChannelConnectedEventHandler) guac_rdp_rail_channel_connected); + + guac_client_log(client, GUAC_LOG_DEBUG, "Support for RAIL (RemoteApp) " + "registered. Awaiting channel connection."); + +} + diff --git a/src/protocols/rdp/rdp_rail.h b/src/protocols/rdp/rail.h similarity index 54% rename from src/protocols/rdp/rdp_rail.h rename to src/protocols/rdp/rail.h index e19f25fc..718c62b3 100644 --- a/src/protocols/rdp/rdp_rail.h +++ b/src/protocols/rdp/rail.h @@ -17,37 +17,23 @@ * under the License. */ - -#ifndef __GUAC_RDP_RDP_RAIL_H -#define __GUAC_RDP_RDP_RAIL_H +#ifndef GUAC_RDP_RAIL_H +#define GUAC_RDP_RAIL_H #include "config.h" -#include -#include - /** - * Dispatches a given RAIL event to the appropriate handler. + * Initializes RemoteApp support for RDP and handling of the RAIL channel. If + * failures occur, messages noting the specifics of those failures will be + * logged, and RemoteApp support will not be functional. * - * @param client - * The guac_client associated with the current RDP session. + * This MUST be called within the PreConnect callback of the freerdp instance + * for RAIL support to be loaded. * - * @param event - * The RAIL event to process. + * @param rdpContext + * The rdpContext associated with the FreeRDP side of the RDP connection. */ -void guac_rdp_process_rail_event(guac_client* client, wMessage* event); - -/** - * Handles the event sent when updating system parameters. The event given - * MUST be a SYSPARAM event. - * - * @param client - * The guac_client associated with the current RDP session. - * - * @param event - * The system parameter event to process. - */ -void guac_rdp_process_rail_get_sysparam(guac_client* client, wMessage* event); +void guac_rdp_rail_load_plugin(rdpContext* context); #endif diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index 0923a53c..b41527c4 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -29,6 +29,7 @@ #include "disp.h" #include "error.h" #include "keyboard.h" +#include "rail.h" #include "rdp.h" #include "rdp_bitmap.h" #include "rdp_fs.h" @@ -36,7 +37,6 @@ #include "rdp_gdi.h" #include "rdp_glyph.h" #include "rdp_pointer.h" -#include "rdp_rail.h" #include "rdp_stream.h" #if 0 #include "rdp_svc.h" @@ -128,15 +128,8 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) { } /* Load RAIL plugin if RemoteApp in use */ - if (settings->remote_app != NULL) { - - /* Attempt to load rail */ - if (guac_freerdp_channels_load_plugin(channels, instance->settings, - "rail", instance->settings)) - guac_client_log(client, GUAC_LOG_WARNING, - "Failed to load rail plugin. RemoteApp will not work."); - - } + if (settings->remote_app != NULL) + guac_rdp_rail_load_plugin(context); #if 0 /* Load SVC plugin instances for all static channels */ @@ -476,22 +469,6 @@ static int guac_rdp_handle_connection(guac_client* client) { } - /* Check for channel events */ -#if 0 - wMessage* event = freerdp_channels_pop_event(channels); - if (event) { - - /* Handle channel events (clipboard and RAIL) */ - if (GetMessageClass(event->id) == CliprdrChannel_Class) - guac_rdp_process_cliprdr_event(client, event); - else if (GetMessageClass(event->id) == RailChannel_Class) - guac_rdp_process_rail_event(client, event); - - freerdp_event_free(event); - - } -#endif - pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Calculate time remaining in frame */ diff --git a/src/protocols/rdp/rdp_rail.c b/src/protocols/rdp/rdp_rail.c deleted file mode 100644 index b351ea6f..00000000 --- a/src/protocols/rdp/rdp_rail.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include "client.h" -#include "rdp.h" -#include "rdp_rail.h" -#include "rdp_settings.h" - -#include -#include -#include -#include -#include - -#include - -void guac_rdp_process_rail_event(guac_client* client, wMessage* event) { - - switch (GetMessageType(event->id)) { - - /* Get system parameters */ - case RailChannel_GetSystemParam: - guac_rdp_process_rail_get_sysparam(client, event); - break; - - /* Currently ignored events */ - case RailChannel_ServerSystemParam: - case RailChannel_ServerExecuteResult: - case RailChannel_ServerMinMaxInfo: - case RailChannel_ServerLocalMoveSize: - case RailChannel_ServerGetAppIdResponse: - case RailChannel_ServerLanguageBarInfo: - break; - - default: - guac_client_log(client, GUAC_LOG_INFO, - "Unknown rail event type: 0x%x", - GetMessageType(event->id)); - - } - -} - -void guac_rdp_process_rail_get_sysparam(guac_client* client, wMessage* event) { -#if 0 - wMessage* response; - RAIL_SYSPARAM_ORDER* sysparam; - - /* Get channels */ - guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; - rdpChannels* channels = rdp_client->rdp_inst->context->channels; - - /* Get sysparam structure */ - sysparam = (RAIL_SYSPARAM_ORDER*) event->wParam; - - response = freerdp_event_new(RailChannel_Class, - RailChannel_ClientSystemParam, - NULL, - sysparam); - - /* Work area */ - sysparam->workArea.left = 0; - sysparam->workArea.top = 0; - sysparam->workArea.right = rdp_client->settings->width; - sysparam->workArea.bottom = rdp_client->settings->height; - - /* Taskbar */ - sysparam->taskbarPos.left = 0; - sysparam->taskbarPos.top = 0; - sysparam->taskbarPos.right = 0; - sysparam->taskbarPos.bottom = 0; - - sysparam->dragFullWindows = FALSE; - - /* Send response */ - freerdp_channels_send_event(channels, response); -#endif -} -