From 1dbdfc155d31de6e1b3ec4a084e72a4f8d7739f3 Mon Sep 17 00:00:00 2001 From: Christian Hofstaedtler Date: Wed, 13 Mar 2013 00:23:59 +0100 Subject: [PATCH] Add the ECHO dynamic virtual channel --- channels/echo/CMakeLists.txt | 23 ++++ channels/echo/ChannelOptions.cmake | 13 ++ channels/echo/client/CMakeLists.txt | 42 +++++++ channels/echo/client/echo_main.c | 186 ++++++++++++++++++++++++++++ channels/echo/client/echo_main.h | 39 ++++++ client/common/cmdline.c | 11 ++ 6 files changed, 314 insertions(+) create mode 100644 channels/echo/CMakeLists.txt create mode 100644 channels/echo/ChannelOptions.cmake create mode 100644 channels/echo/client/CMakeLists.txt create mode 100644 channels/echo/client/echo_main.c create mode 100644 channels/echo/client/echo_main.h diff --git a/channels/echo/CMakeLists.txt b/channels/echo/CMakeLists.txt new file mode 100644 index 000000000..3044e5ee5 --- /dev/null +++ b/channels/echo/CMakeLists.txt @@ -0,0 +1,23 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel("echo") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() + diff --git a/channels/echo/ChannelOptions.cmake b/channels/echo/ChannelOptions.cmake new file mode 100644 index 000000000..47a7d075e --- /dev/null +++ b/channels/echo/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT OFF) + +define_channel_options(NAME "echo" TYPE "dynamic" + DESCRIPTION "Echo Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPEECO]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/echo/client/CMakeLists.txt b/channels/echo/client/CMakeLists.txt new file mode 100644 index 000000000..c9954d23e --- /dev/null +++ b/channels/echo/client/CMakeLists.txt @@ -0,0 +1,42 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 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. + +define_channel_client("echo") + +set(${MODULE_PREFIX}_SRCS + echo_main.c + echo_main.h) + +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-common freerdp-utils) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +if(NOT STATIC_CHANNELS) + install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_PLUGIN_PATH}) +endif() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") + diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c new file mode 100644 index 000000000..63b4fde68 --- /dev/null +++ b/channels/echo/client/echo_main.c @@ -0,0 +1,186 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2013 Christian Hofstaedtler + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include + +#include + +#include + +#include "echo_main.h" + +typedef struct _ECHO_LISTENER_CALLBACK ECHO_LISTENER_CALLBACK; +struct _ECHO_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; +}; + +typedef struct _ECHO_CHANNEL_CALLBACK ECHO_CHANNEL_CALLBACK; +struct _ECHO_CHANNEL_CALLBACK +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; + +typedef struct _ECHO_PLUGIN ECHO_PLUGIN; +struct _ECHO_PLUGIN +{ + IWTSPlugin iface; + + ECHO_LISTENER_CALLBACK* listener_callback; +}; + +static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer) +{ + int error; + ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback; + +#ifdef WITH_DEBUG_DVC + int i = 0; + char* debug_buffer; + char* p; + + if (cbSize > 0) + { + debug_buffer = (char*) malloc(3 * cbSize); + ZeroMemory(debug_buffer, 3 * cbSize); + + p = debug_buffer; + + for (i = 0; i < (int) (cbSize - 1); i++) + { + sprintf(p, "%02x ", pBuffer[i]); + p += 3; + } + sprintf(p, "%02x", pBuffer[i]); + + DEBUG_DVC("ECHO %d: %s", cbSize, debug_buffer); + free(debug_buffer); + } +#endif + + /* echo back what we have received. ECHO does not have any message IDs. */ + error = callback->channel->Write(callback->channel, cbSize, pBuffer, NULL); + + return error; +} + +static int echo_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback; + + DEBUG_DVC(""); + + free(callback); + + return 0; +} + +static int echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + ECHO_CHANNEL_CALLBACK* callback; + ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*) pListenerCallback; + + DEBUG_DVC(""); + + callback = (ECHO_CHANNEL_CALLBACK*) malloc(sizeof(ECHO_CHANNEL_CALLBACK)); + ZeroMemory(callback, sizeof(ECHO_CHANNEL_CALLBACK)); + + callback->iface.OnDataReceived = echo_on_data_received; + callback->iface.OnClose = echo_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + + *ppCallback = (IWTSVirtualChannelCallback*) callback; + + return 0; +} + +static int echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) +{ + ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin; + + DEBUG_DVC(""); + + echo->listener_callback = (ECHO_LISTENER_CALLBACK*) malloc(sizeof(ECHO_LISTENER_CALLBACK)); + ZeroMemory(echo->listener_callback, sizeof(ECHO_LISTENER_CALLBACK)); + + echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection; + echo->listener_callback->plugin = pPlugin; + echo->listener_callback->channel_mgr = pChannelMgr; + + return pChannelMgr->CreateListener(pChannelMgr, "ECHO", 0, + (IWTSListenerCallback*) echo->listener_callback, NULL); +} + +static int echo_plugin_terminated(IWTSPlugin* pPlugin) +{ + ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin; + + DEBUG_DVC(""); + + free(echo); + + return 0; +} + +#ifdef STATIC_CHANNELS +#define DVCPluginEntry echo_DVCPluginEntry +#endif + +int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + int error = 0; + ECHO_PLUGIN* echo; + + echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo"); + + if (echo == NULL) + { + echo = (ECHO_PLUGIN*) malloc(sizeof(ECHO_PLUGIN)); + ZeroMemory(echo, sizeof(ECHO_PLUGIN)); + + echo->iface.Initialize = echo_plugin_initialize; + echo->iface.Connected = NULL; + echo->iface.Disconnected = NULL; + echo->iface.Terminated = echo_plugin_terminated; + + error = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo); + } + + return error; +} diff --git a/channels/echo/client/echo_main.h b/channels/echo/client/echo_main.h new file mode 100644 index 000000000..e63eea768 --- /dev/null +++ b/channels/echo/client/echo_main.h @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Echo Virtual Channel Extension + * + * Copyright 2013 Christian Hofstaedtler + * + * 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 __ECHO_MAIN_H +#define __ECHO_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) +#else +#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#endif + +#endif /* __ECHO_MAIN_H */ + diff --git a/client/common/cmdline.c b/client/common/cmdline.c index dc3eefe0b..db2a25ae5 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -85,6 +85,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "smartcard", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect smartcard device" }, { "printer", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect printer device" }, { "usb", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect USB device" }, + { "echo", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "echo", "Echo channel" }, { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Smooth fonts (ClearType)" }, { "aero", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueFalse, -1, NULL, "Desktop composition" }, { "window-drag", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Full window drag" }, @@ -561,6 +562,16 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT free(p); } + CommandLineSwitchCase(arg, "echo") + { + char* p[1]; + int count; + + count = 1; + p[0] = "echo"; + + freerdp_client_add_dynamic_channel(settings, count, p); + } CommandLineSwitchCase(arg, "sound") { if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)