GUACAMOLE-249: Dynamically wrap channel entry points (FreeRDP will refuse to associate the same entry point with multiple channels).
This commit is contained in:
parent
664586ea54
commit
875d51c1ed
1
src/protocols/rdp/.gitignore
vendored
1
src/protocols/rdp/.gitignore
vendored
@ -4,5 +4,6 @@ _generated_runner.c
|
|||||||
test_rdp
|
test_rdp
|
||||||
|
|
||||||
# Autogenerated sources
|
# Autogenerated sources
|
||||||
|
_generated_channel_entry_wrappers.c
|
||||||
_generated_keymaps.c
|
_generated_keymaps.c
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ SUBDIRS = . tests
|
|||||||
# Main RDP client library
|
# Main RDP client library
|
||||||
#
|
#
|
||||||
|
|
||||||
nodist_libguac_client_rdp_la_SOURCES = \
|
nodist_libguac_client_rdp_la_SOURCES = \
|
||||||
|
_generated_channel_entry_wrappers.c \
|
||||||
_generated_keymaps.c
|
_generated_keymaps.c
|
||||||
|
|
||||||
libguac_client_rdp_la_SOURCES = \
|
libguac_client_rdp_la_SOURCES = \
|
||||||
@ -200,11 +201,16 @@ libguac_client_rdp_la_LIBADD += @COMMON_SSH_LTLIB@
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# Autogenerate keymaps
|
# Autogenerated keymaps and channel wrapper functions
|
||||||
#
|
#
|
||||||
|
|
||||||
CLEANFILES = _generated_keymaps.c
|
CLEANFILES = \
|
||||||
BUILT_SOURCES = _generated_keymaps.c
|
_generated_channel_entry_wrappers.c \
|
||||||
|
_generated_keymaps.c
|
||||||
|
|
||||||
|
BUILT_SOURCES = \
|
||||||
|
_generated_channel_entry_wrappers.c \
|
||||||
|
_generated_keymaps.c
|
||||||
|
|
||||||
rdp_keymaps = \
|
rdp_keymaps = \
|
||||||
$(srcdir)/keymaps/base.keymap \
|
$(srcdir)/keymaps/base.keymap \
|
||||||
@ -224,9 +230,13 @@ rdp_keymaps = \
|
|||||||
$(srcdir)/keymaps/tr_tr_qwerty.keymap
|
$(srcdir)/keymaps/tr_tr_qwerty.keymap
|
||||||
|
|
||||||
_generated_keymaps.c: $(rdp_keymaps)
|
_generated_keymaps.c: $(rdp_keymaps)
|
||||||
$(srcdir)/keymaps/generate.pl $(rdp_keymaps)
|
$(AM_V_GEN) $(srcdir)/keymaps/generate.pl $(rdp_keymaps)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
_generated_channel_entry_wrappers.c: $(srcdir)/channels.h $(srcdir)/generate-entry-wrappers.pl
|
||||||
$(rdp_keymaps) \
|
$(AM_V_GEN) $(srcdir)/generate-entry-wrappers.pl $(srcdir)/channels.h
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(rdp_keymaps) \
|
||||||
|
generate-entry-wrappers.pl \
|
||||||
keymaps/generate.pl
|
keymaps/generate.pl
|
||||||
|
|
||||||
|
@ -18,12 +18,53 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "channels.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
|
|
||||||
#include <freerdp/channels/channels.h>
|
#include <freerdp/channels/channels.h>
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
int guac_rdp_wrapped_entry_ex_count = 0;
|
||||||
|
|
||||||
|
int guac_rdp_wrapped_entry_count = 0;
|
||||||
|
|
||||||
|
PVIRTUALCHANNELENTRYEX guac_rdp_wrapped_entry_ex[GUAC_RDP_MAX_CHANNELS] = { NULL };
|
||||||
|
|
||||||
|
PVIRTUALCHANNELENTRY guac_rdp_wrapped_entry[GUAC_RDP_MAX_CHANNELS] = { NULL };
|
||||||
|
|
||||||
|
PVIRTUALCHANNELENTRYEX guac_rdp_plugin_wrap_entry_ex(PVIRTUALCHANNELENTRYEX entry_ex) {
|
||||||
|
|
||||||
|
/* Do not wrap if there is insufficient space to store the wrapped
|
||||||
|
* function */
|
||||||
|
if (guac_rdp_wrapped_entry_ex_count == GUAC_RDP_MAX_CHANNELS)
|
||||||
|
return entry_ex;
|
||||||
|
|
||||||
|
/* Generate wrapped version of provided entry point */
|
||||||
|
PVIRTUALCHANNELENTRYEX wrapper = guac_rdp_entry_ex_wrappers[guac_rdp_wrapped_entry_ex_count];
|
||||||
|
guac_rdp_wrapped_entry_ex[guac_rdp_wrapped_entry_ex_count] = entry_ex;
|
||||||
|
guac_rdp_wrapped_entry_ex_count++;
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PVIRTUALCHANNELENTRY guac_rdp_plugin_wrap_entry(PVIRTUALCHANNELENTRY entry) {
|
||||||
|
|
||||||
|
/* Do not wrap if there is insufficient space to store the wrapped
|
||||||
|
* function */
|
||||||
|
if (guac_rdp_wrapped_entry_count == GUAC_RDP_MAX_CHANNELS)
|
||||||
|
return entry;
|
||||||
|
|
||||||
|
/* Generate wrapped version of provided entry point */
|
||||||
|
PVIRTUALCHANNELENTRY wrapper = guac_rdp_entry_wrappers[guac_rdp_wrapped_entry_count];
|
||||||
|
guac_rdp_wrapped_entry[guac_rdp_wrapped_entry_count] = entry;
|
||||||
|
guac_rdp_wrapped_entry_count++;
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int guac_freerdp_channels_load_plugin(rdpChannels* channels,
|
int guac_freerdp_channels_load_plugin(rdpChannels* channels,
|
||||||
rdpSettings* settings, const char* name, void* data) {
|
rdpSettings* settings, const char* name, void* data) {
|
||||||
|
|
||||||
@ -31,15 +72,19 @@ int guac_freerdp_channels_load_plugin(rdpChannels* channels,
|
|||||||
PVIRTUALCHANNELENTRYEX entry_ex = (PVIRTUALCHANNELENTRYEX) (void*) freerdp_load_channel_addin_entry(name,
|
PVIRTUALCHANNELENTRYEX entry_ex = (PVIRTUALCHANNELENTRYEX) (void*) freerdp_load_channel_addin_entry(name,
|
||||||
NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
|
NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
|
||||||
|
|
||||||
if (entry_ex != NULL)
|
if (entry_ex != NULL) {
|
||||||
|
entry_ex = guac_rdp_plugin_wrap_entry_ex(entry_ex);
|
||||||
return freerdp_channels_client_load_ex(channels, settings, entry_ex, data);
|
return freerdp_channels_client_load_ex(channels, settings, entry_ex, data);
|
||||||
|
}
|
||||||
|
|
||||||
/* Lacking the "ex" entry point, attempt to load using the non-ex version */
|
/* Lacking the "ex" entry point, attempt to load using the non-ex version */
|
||||||
PVIRTUALCHANNELENTRY entry = freerdp_load_channel_addin_entry(name,
|
PVIRTUALCHANNELENTRY entry = freerdp_load_channel_addin_entry(name,
|
||||||
NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
|
NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
|
||||||
|
|
||||||
if (entry != NULL)
|
if (entry != NULL) {
|
||||||
|
entry = guac_rdp_plugin_wrap_entry(entry);
|
||||||
return freerdp_channels_client_load(channels, settings, entry, data);
|
return freerdp_channels_client_load(channels, settings, entry, data);
|
||||||
|
}
|
||||||
|
|
||||||
/* The plugin does not exist / cannot be loaded */
|
/* The plugin does not exist / cannot be loaded */
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -25,6 +25,22 @@
|
|||||||
#include <freerdp/channels/channels.h>
|
#include <freerdp/channels/channels.h>
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of static channels supported by Guacamole's RDP support.
|
||||||
|
* This value should be given a value which is at least the value of FreeRDP's
|
||||||
|
* CHANNEL_MAX_COUNT.
|
||||||
|
*
|
||||||
|
* NOTE: The value of this macro must be specified statically (not as a
|
||||||
|
* reference to CHANNEL_MAX_COUNT), as its value is extracted and used by the
|
||||||
|
* entry point wrapper code generator (generate-entry-wrappers.pl).
|
||||||
|
*/
|
||||||
|
#define GUAC_RDP_MAX_CHANNELS 64
|
||||||
|
|
||||||
|
/* Validate GUAC_RDP_MAX_CHANNELS is sane at compile time */
|
||||||
|
#if GUAC_RDP_MAX_CHANNELS < CHANNEL_MAX_COUNT
|
||||||
|
#error "GUAC_RDP_MAX_CHANNELS must not be less than CHANNEL_MAX_COUNT"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the FreeRDP plugin having the given name. This function is a drop-in
|
* Loads the FreeRDP plugin having the given name. This function is a drop-in
|
||||||
* replacement for freerdp_channels_load_plugin() which additionally loads
|
* replacement for freerdp_channels_load_plugin() which additionally loads
|
||||||
@ -105,5 +121,83 @@ int guac_freerdp_channels_load_plugin(rdpChannels* channels,
|
|||||||
void guac_freerdp_dynamic_channel_collection_add(rdpSettings* settings,
|
void guac_freerdp_dynamic_channel_collection_add(rdpSettings* settings,
|
||||||
const char* name, ...);
|
const char* name, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of wrapped channel entry points currently stored within
|
||||||
|
* guac_rdp_wrapped_entry_ex.
|
||||||
|
*/
|
||||||
|
extern int guac_rdp_wrapped_entry_ex_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All currently wrapped entry points that use the PVIRTUALCHANNELENTRYEX
|
||||||
|
* variant.
|
||||||
|
*/
|
||||||
|
extern PVIRTUALCHANNELENTRYEX guac_rdp_wrapped_entry_ex[GUAC_RDP_MAX_CHANNELS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup table of wrapper functions for PVIRTUALCHANNELENTRYEX entry points.
|
||||||
|
* Each function within this array is generated at compile time by the entry
|
||||||
|
* point wrapper code generator (generate-entry-wrappers.pl) and automatically
|
||||||
|
* invokes the corresponding wrapped entry point stored within
|
||||||
|
* guac_rdp_wrapped_entry_ex.
|
||||||
|
*/
|
||||||
|
extern PVIRTUALCHANNELENTRYEX guac_rdp_entry_ex_wrappers[GUAC_RDP_MAX_CHANNELS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided entry point function, returning a different entry point
|
||||||
|
* which simply invokes the original. As long as this function is not invoked
|
||||||
|
* more than GUAC_RDP_MAX_CHANNELS times, each returned entry point will be
|
||||||
|
* unique, even if the provided entry point is not. As FreeRDP will refuse to
|
||||||
|
* load a plugin if its entry point is already loaded, this allows a single
|
||||||
|
* FreeRDP plugin to be loaded multiple times.
|
||||||
|
*
|
||||||
|
* @param entry_ex
|
||||||
|
* The entry point function to wrap.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A wrapped version of the provided entry point, or the unwrapped entry
|
||||||
|
* point if there is insufficient space remaining within
|
||||||
|
* guac_rdp_entry_ex_wrappers to wrap the entry point.
|
||||||
|
*/
|
||||||
|
PVIRTUALCHANNELENTRYEX guac_rdp_plugin_wrap_entry_ex(PVIRTUALCHANNELENTRYEX entry_ex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of wrapped channel entry points currently stored within
|
||||||
|
* guac_rdp_wrapped_entry.
|
||||||
|
*/
|
||||||
|
extern int guac_rdp_wrapped_entry_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All currently wrapped entry points that use the PVIRTUALCHANNELENTRY
|
||||||
|
* variant.
|
||||||
|
*/
|
||||||
|
extern PVIRTUALCHANNELENTRY guac_rdp_wrapped_entry[GUAC_RDP_MAX_CHANNELS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup table of wrapper functions for PVIRTUALCHANNELENTRY entry points.
|
||||||
|
* Each function within this array is generated at compile time by the entry
|
||||||
|
* point wrapper code generator (generate-entry-wrappers.pl) and automatically
|
||||||
|
* invokes the corresponding wrapped entry point stored within
|
||||||
|
* guac_rdp_wrapped_entry.
|
||||||
|
*/
|
||||||
|
extern PVIRTUALCHANNELENTRY guac_rdp_entry_wrappers[GUAC_RDP_MAX_CHANNELS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided entry point function, returning a different entry point
|
||||||
|
* which simply invokes the original. As long as this function is not invoked
|
||||||
|
* more than GUAC_RDP_MAX_CHANNELS times, each returned entry point will be
|
||||||
|
* unique, even if the provided entry point is not. As FreeRDP will refuse to
|
||||||
|
* load a plugin if its entry point is already loaded, this allows a single
|
||||||
|
* FreeRDP plugin to be loaded multiple times.
|
||||||
|
*
|
||||||
|
* @param entry
|
||||||
|
* The entry point function to wrap.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A wrapped version of the provided entry point, or the unwrapped entry
|
||||||
|
* point if there is insufficient space remaining within
|
||||||
|
* guac_rdp_entry_wrappers to wrap the entry point.
|
||||||
|
*/
|
||||||
|
PVIRTUALCHANNELENTRY guac_rdp_plugin_wrap_entry(PVIRTUALCHANNELENTRY entry);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
77
src/protocols/rdp/generate-entry-wrappers.pl
Executable file
77
src/protocols/rdp/generate-entry-wrappers.pl
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# generate-entry-wrappers.pl
|
||||||
|
#
|
||||||
|
# Generates C source which defines wrapper functions for FreeRDP plugin entry
|
||||||
|
# points, allowing multiple instances of the same plugin to be loaded despite
|
||||||
|
# otherwise always having the same entry point.
|
||||||
|
#
|
||||||
|
# The resulting source is stored within "_generated_channel_entry_wrappers.c".
|
||||||
|
#
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
##
|
||||||
|
## The maximum number of static channels supported by Guacamole's RDP support.
|
||||||
|
##
|
||||||
|
my $GUAC_RDP_MAX_CHANNELS;
|
||||||
|
|
||||||
|
# Extract value of GUAC_RDP_MAX_CHANNELS macro from provided source
|
||||||
|
while (<>) {
|
||||||
|
if ((my $value) = m/^\s*#define\s+GUAC_RDP_MAX_CHANNELS\s+(\d+)\s*$/) {
|
||||||
|
$GUAC_RDP_MAX_CHANNELS = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open OUTPUT, ">", "_generated_channel_entry_wrappers.c";
|
||||||
|
|
||||||
|
# Generate required headers
|
||||||
|
print OUTPUT <<"EOF";
|
||||||
|
#include "channels.h"
|
||||||
|
#include <freerdp/channels/channels.h>
|
||||||
|
#include <freerdp/freerdp.h>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generate wrapper definitions for PVIRTUALCHANNELENTRYEX entry point variant
|
||||||
|
print OUTPUT <<"EOF" for (1..$GUAC_RDP_MAX_CHANNELS);
|
||||||
|
static BOOL guac_rdp_plugin_entry_ex_wrapper$_(PCHANNEL_ENTRY_POINTS_EX entry_points_ex, PVOID init_handle) {
|
||||||
|
return guac_rdp_wrapped_entry_ex[$_ - 1](entry_points_ex, init_handle);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generate wrapper definitions for PVIRTUALCHANNELENTRY entry point variant
|
||||||
|
print OUTPUT <<"EOF" for (1..$GUAC_RDP_MAX_CHANNELS);
|
||||||
|
static BOOL guac_rdp_plugin_entry_wrapper$_(PCHANNEL_ENTRY_POINTS entry_points) {
|
||||||
|
return guac_rdp_wrapped_entry[$_ - 1](entry_points);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Populate lookup table of PVIRTUALCHANNELENTRYEX wrapper functions
|
||||||
|
print OUTPUT "PVIRTUALCHANNELENTRYEX guac_rdp_entry_ex_wrappers[$GUAC_RDP_MAX_CHANNELS] = {\n";
|
||||||
|
print OUTPUT " guac_rdp_plugin_entry_ex_wrapper$_,\n" for (1..$GUAC_RDP_MAX_CHANNELS);
|
||||||
|
print OUTPUT "};\n";
|
||||||
|
|
||||||
|
# Populate lookup table of PVIRTUALCHANNELENTRY wrapper functions
|
||||||
|
print OUTPUT "PVIRTUALCHANNELENTRY guac_rdp_entry_wrappers[$GUAC_RDP_MAX_CHANNELS] = {\n";
|
||||||
|
print OUTPUT " guac_rdp_plugin_entry_wrapper$_,\n" for (1..$GUAC_RDP_MAX_CHANNELS);
|
||||||
|
print OUTPUT "};\n";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user