diff --git a/include/freerdp/extension.h b/include/freerdp/extension.h index 91f1235ea..e34f69405 100644 --- a/include/freerdp/extension.h +++ b/include/freerdp/extension.h @@ -20,14 +20,14 @@ #ifndef __RDP_EXTENSION_H #define __RDP_EXTENSION_H -#include #include #include +#include /* Extensions ought to check for it to ensure compatibility */ -#define RDPEXT_API 1 +#define FREERDP_EXT_API 1 -#define RDPEXT_EXPORT_FUNC_NAME "FreeRDPExtensionEntry" +#define FREERDP_EXT_EXPORT_FUNC_NAME "FreeRDPExtensionEntry" typedef struct rdp_ext_plugin rdpExtPlugin; @@ -52,6 +52,7 @@ struct _FREERDP_EXTENSION_ENTRY_POINTS PREGISTERPOSTCONNECTHOOK pRegisterPostConnectHook; void* data; }; + typedef struct _FREERDP_EXTENSION_ENTRY_POINTS FREERDP_EXTENSION_ENTRY_POINTS; typedef FREERDP_EXTENSION_ENTRY_POINTS* PFREERDP_EXTENSION_ENTRY_POINTS; diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt index e0d326e36..939a9cf52 100644 --- a/libfreerdp-core/CMakeLists.txt +++ b/libfreerdp-core/CMakeLists.txt @@ -24,6 +24,8 @@ include_directories(${ZLIB_INCLUDE_DIRS}) set(LIBFREERDP_CORE_SRCS activation.c activation.h + extension.c + extension.h ber.c ber.h gcc.c diff --git a/libfreerdp-core/extension.c b/libfreerdp-core/extension.c new file mode 100644 index 000000000..ab2414000 --- /dev/null +++ b/libfreerdp-core/extension.c @@ -0,0 +1,202 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Extension Plugin Interface + * + * Copyright 2010-2011 Vic Lee + * Copyright 2011 Marc-Andre Moreau + * + * Licensed 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 +#include +#include +#include +#include + +#include "rdp.h" +#include "extension.h" + +#ifdef _WIN32 +#define DLOPEN(f) LoadLibraryA(f) +#define DLSYM(f, n) GetProcAddress(f, n) +#define DLCLOSE(f) FreeLibrary(f) +#define PATH_SEPARATOR '\\' +#define PLUGIN_EXT "dll" +#else +#include +#define DLOPEN(f) dlopen(f, RTLD_LOCAL | RTLD_LAZY) +#define DLSYM(f, n) dlsym(f, n) +#define DLCLOSE(f) dlclose(f) +#define PATH_SEPARATOR '/' +#define PLUGIN_EXT "so" +#endif + +static uint32 FREERDP_CC freerdp_ext_register_extension(rdpExtPlugin* plugin) +{ + rdpExt* ext = (rdpExt*) plugin->ext; + + if (ext->num_plugins >= FREERDP_EXT_MAX_COUNT) + { + printf("freerdp_ext_register_extension: maximum number of plugins reached.\n"); + return 1; + } + + ext->plugins[ext->num_plugins++] = plugin; + return 0; +} + +static uint32 FREERDP_CC freerdp_ext_register_pre_connect_hook(rdpExtPlugin* plugin, PFREERDP_EXTENSION_HOOK hook) +{ + rdpExt* ext = (rdpExt*) plugin->ext; + + if (ext->num_pre_connect_hooks >= FREERDP_EXT_MAX_COUNT) + { + printf("freerdp_ext_register_pre_connect_hook: maximum plugin reached.\n"); + return 1; + } + + ext->pre_connect_hooks[ext->num_pre_connect_hooks] = hook; + ext->pre_connect_hooks_instances[ext->num_pre_connect_hooks] = plugin; + ext->num_pre_connect_hooks++; + return 0; +} + +static uint32 FREERDP_CC freerdp_ext_register_post_connect_hook(rdpExtPlugin* plugin, PFREERDP_EXTENSION_HOOK hook) +{ + rdpExt* ext = (rdpExt*) plugin->ext; + + if (ext->num_post_connect_hooks >= FREERDP_EXT_MAX_COUNT) + { + printf("freerdp_ext_register_post_connect_hook: maximum plugin reached.\n"); + return 1; + } + + ext->post_connect_hooks[ext->num_post_connect_hooks] = hook; + ext->post_connect_hooks_instances[ext->num_post_connect_hooks] = plugin; + ext->num_post_connect_hooks++; + + return 0; +} + +static int freerdp_ext_load_plugins(rdpExt* ext) +{ + int i; + void* han; + char path[256]; + rdpSettings* settings; + PFREERDP_EXTENSION_ENTRY entry; + FREERDP_EXTENSION_ENTRY_POINTS entryPoints; + + settings = ext->instance->settings; + + entryPoints.ext = ext; + entryPoints.pRegisterExtension = freerdp_ext_register_extension; + entryPoints.pRegisterPreConnectHook = freerdp_ext_register_pre_connect_hook; + entryPoints.pRegisterPostConnectHook = freerdp_ext_register_post_connect_hook; + + for (i = 0; settings->extensions[i].name[0]; i++) + { + if (strchr(settings->extensions[i].name, PATH_SEPARATOR) == NULL) + snprintf(path, sizeof(path), EXT_PATH "/%s." PLUGIN_EXT, settings->extensions[i].name); + else + snprintf(path, sizeof(path), "%s", settings->extensions[i].name); + + han = DLOPEN(path); + printf("freerdp_ext_load_plugins: %s\n", path); + if (han == NULL) + { + printf("freerdp_ext_load_plugins: failed to load %s\n", path); + continue; + } + + entry = (PFREERDP_EXTENSION_ENTRY) DLSYM(han, FREERDP_EXT_EXPORT_FUNC_NAME); + if (entry == NULL) + { + DLCLOSE(han); + printf("freerdp_ext_load_plugins: failed to find export function in %s\n", path); + continue; + } + + entryPoints.data = ext->instance->settings->extensions[i].data; + if (entry(&entryPoints) != 0) + { + DLCLOSE(han); + printf("freerdp_ext_load_plugins: %s entry returns error.\n", path); + continue; + } + } + + return 0; +} + +static int freerdp_ext_call_init(rdpExt* ext) +{ + int i; + + for (i = 0; i < ext->num_plugins; i++) + ext->plugins[i]->init(ext->plugins[i], ext->instance); + + return 0; +} + +static int freerdp_ext_call_uninit(rdpExt* ext) +{ + int i; + + for (i = 0; i < ext->num_plugins; i++) + ext->plugins[i]->uninit(ext->plugins[i], ext->instance); + + return 0; +} + + +int freerdp_ext_pre_connect(rdpExt* ext) +{ + int i; + + for (i = 0; i < ext->num_pre_connect_hooks; i++) + ext->pre_connect_hooks[i](ext->pre_connect_hooks_instances[i], ext->instance); + + return 0; +} + +int freerdp_ext_post_connect(rdpExt* ext) +{ + int i; + + for (i = 0; i < ext->num_post_connect_hooks; i++) + ext->post_connect_hooks[i](ext->post_connect_hooks_instances[i], ext->instance); + + return 0; +} + +rdpExt* freerdp_ext_new(rdpRdp* rdp) +{ + rdpExt* ext; + + ext = xnew(rdpExt); + + ext->instance = rdp->instance; + + freerdp_ext_load_plugins(ext); + freerdp_ext_call_init(ext); + + return ext; +} + +void freerdp_ext_free(rdpExt* ext) +{ + freerdp_ext_call_uninit(ext); + xfree(ext); +} diff --git a/libfreerdp-core/extension.h b/libfreerdp-core/extension.h new file mode 100644 index 000000000..3a5c5a514 --- /dev/null +++ b/libfreerdp-core/extension.h @@ -0,0 +1,52 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Extension Plugin Interface + * + * Copyright 2010-2011 Vic Lee + * Copyright 2011 Marc-Andre Moreau + * + * Licensed 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. + */ + +#ifndef __EXTENSION_H +#define __EXTENSION_H + +#include +#include + +#include "rdp.h" + +#define FREERDP_EXT_MAX_COUNT 16 + +struct rdp_ext +{ + freerdp* instance; + rdpExtPlugin* plugins[FREERDP_EXT_MAX_COUNT]; + int num_plugins; + PFREERDP_EXTENSION_HOOK pre_connect_hooks[FREERDP_EXT_MAX_COUNT]; + rdpExtPlugin* pre_connect_hooks_instances[FREERDP_EXT_MAX_COUNT]; + int num_pre_connect_hooks; + PFREERDP_EXTENSION_HOOK post_connect_hooks[FREERDP_EXT_MAX_COUNT]; + rdpExtPlugin* post_connect_hooks_instances[FREERDP_EXT_MAX_COUNT]; + int num_post_connect_hooks; +}; +typedef struct rdp_ext rdpExt; + +int freerdp_ext_pre_connect(rdpExt* ext); +int freerdp_ext_post_connect(rdpExt* ext); + +rdpExt* freerdp_ext_new(rdpRdp* rdp); +void freerdp_ext_free(rdpExt* ext); + +#endif /* __EXTENSION_H */ +