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
|
||||
|
||||
# Autogenerated sources
|
||||
_generated_channel_entry_wrappers.c
|
||||
_generated_keymaps.c
|
||||
|
||||
|
@ -34,6 +34,7 @@ SUBDIRS = . tests
|
||||
#
|
||||
|
||||
nodist_libguac_client_rdp_la_SOURCES = \
|
||||
_generated_channel_entry_wrappers.c \
|
||||
_generated_keymaps.c
|
||||
|
||||
libguac_client_rdp_la_SOURCES = \
|
||||
@ -200,11 +201,16 @@ libguac_client_rdp_la_LIBADD += @COMMON_SSH_LTLIB@
|
||||
endif
|
||||
|
||||
#
|
||||
# Autogenerate keymaps
|
||||
# Autogenerated keymaps and channel wrapper functions
|
||||
#
|
||||
|
||||
CLEANFILES = _generated_keymaps.c
|
||||
BUILT_SOURCES = _generated_keymaps.c
|
||||
CLEANFILES = \
|
||||
_generated_channel_entry_wrappers.c \
|
||||
_generated_keymaps.c
|
||||
|
||||
BUILT_SOURCES = \
|
||||
_generated_channel_entry_wrappers.c \
|
||||
_generated_keymaps.c
|
||||
|
||||
rdp_keymaps = \
|
||||
$(srcdir)/keymaps/base.keymap \
|
||||
@ -224,9 +230,13 @@ rdp_keymaps = \
|
||||
$(srcdir)/keymaps/tr_tr_qwerty.keymap
|
||||
|
||||
_generated_keymaps.c: $(rdp_keymaps)
|
||||
$(srcdir)/keymaps/generate.pl $(rdp_keymaps)
|
||||
$(AM_V_GEN) $(srcdir)/keymaps/generate.pl $(rdp_keymaps)
|
||||
|
||||
_generated_channel_entry_wrappers.c: $(srcdir)/channels.h $(srcdir)/generate-entry-wrappers.pl
|
||||
$(AM_V_GEN) $(srcdir)/generate-entry-wrappers.pl $(srcdir)/channels.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(rdp_keymaps) \
|
||||
generate-entry-wrappers.pl \
|
||||
keymaps/generate.pl
|
||||
|
||||
|
@ -18,12 +18,53 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "channels.h"
|
||||
#include "rdp.h"
|
||||
|
||||
#include <freerdp/channels/channels.h>
|
||||
#include <freerdp/freerdp.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,
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
/* Lacking the "ex" entry point, attempt to load using the non-ex version */
|
||||
PVIRTUALCHANNELENTRY entry = freerdp_load_channel_addin_entry(name,
|
||||
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);
|
||||
}
|
||||
|
||||
/* The plugin does not exist / cannot be loaded */
|
||||
return 1;
|
||||
|
@ -25,6 +25,22 @@
|
||||
#include <freerdp/channels/channels.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
|
||||
* 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,
|
||||
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
|
||||
|
||||
|
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