From 2ee03f035a71af0f5ae9f85e6366c9c8e5920eb6 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sat, 10 Dec 2011 15:51:42 +0800 Subject: [PATCH 1/8] libfreerdp-core: change channel_send argument in order to be shared with server code. --- libfreerdp-core/channel.c | 16 ++++++++-------- libfreerdp-core/channel.h | 2 +- libfreerdp-core/rdp.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libfreerdp-core/channel.c b/libfreerdp-core/channel.c index 8f137910a..0da4537f6 100644 --- a/libfreerdp-core/channel.c +++ b/libfreerdp-core/channel.c @@ -28,7 +28,7 @@ #include "rdp.h" #include "channel.h" -boolean freerdp_channel_send(freerdp* instance, uint16 channel_id, uint8* data, int size) +boolean freerdp_channel_send(rdpRdp* rdp, uint16 channel_id, uint8* data, int size) { STREAM* s; uint32 flags; @@ -36,11 +36,11 @@ boolean freerdp_channel_send(freerdp* instance, uint16 channel_id, uint8* data, int chunk_size; rdpChannel* channel = NULL; - for (i = 0; i < instance->settings->num_channels; i++) + for (i = 0; i < rdp->settings->num_channels; i++) { - if (instance->settings->channels[i].channel_id == channel_id) + if (rdp->settings->channels[i].channel_id == channel_id) { - channel = &instance->settings->channels[i]; + channel = &rdp->settings->channels[i]; break; } } @@ -55,11 +55,11 @@ boolean freerdp_channel_send(freerdp* instance, uint16 channel_id, uint8* data, left = size; while (left > 0) { - s = rdp_send_stream_init(instance->context->rdp); + s = rdp_send_stream_init(rdp); - if (left > (int) instance->settings->vc_chunk_size) + if (left > (int) rdp->settings->vc_chunk_size) { - chunk_size = instance->settings->vc_chunk_size; + chunk_size = rdp->settings->vc_chunk_size; } else { @@ -76,7 +76,7 @@ boolean freerdp_channel_send(freerdp* instance, uint16 channel_id, uint8* data, stream_check_size(s, chunk_size); stream_write(s, data, chunk_size); - rdp_send(instance->context->rdp, s, channel_id); + rdp_send(rdp, s, channel_id); data += chunk_size; left -= chunk_size; diff --git a/libfreerdp-core/channel.h b/libfreerdp-core/channel.h index afb501dee..cfc2e70a0 100644 --- a/libfreerdp-core/channel.h +++ b/libfreerdp-core/channel.h @@ -20,7 +20,7 @@ #ifndef __CHANNEL_H #define __CHANNEL_H -boolean freerdp_channel_send(freerdp* instance, uint16 channel_id, uint8* data, int size); +boolean freerdp_channel_send(rdpRdp* rdp, uint16 channel_id, uint8* data, int size); void freerdp_channel_process(freerdp* instance, STREAM* s, uint16 channel_id); #endif /* __CHANNEL_H */ diff --git a/libfreerdp-core/rdp.c b/libfreerdp-core/rdp.c index 7ba54e3aa..3b1d7c859 100644 --- a/libfreerdp-core/rdp.c +++ b/libfreerdp-core/rdp.c @@ -775,7 +775,7 @@ static boolean rdp_recv_callback(rdpTransport* transport, STREAM* s, void* extra int rdp_send_channel_data(rdpRdp* rdp, int channel_id, uint8* data, int size) { - return freerdp_channel_send(rdp->instance, channel_id, data, size); + return freerdp_channel_send(rdp, channel_id, data, size); } /** From 703e253e9fb66006de7e12ea337992354d8d9899 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sat, 10 Dec 2011 16:41:29 +0800 Subject: [PATCH 2/8] libfreerdp-core: add channel data sending/receiving for server. --- include/freerdp/peer.h | 6 ++++++ libfreerdp-core/channel.c | 14 ++++++++++++++ libfreerdp-core/channel.h | 1 + libfreerdp-core/peer.c | 8 +++++++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 21d58bc45..bc8da5240 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -36,6 +36,9 @@ typedef void (*psPeerDisconnect)(freerdp_peer* client); typedef boolean (*psPeerPostConnect)(freerdp_peer* client); typedef boolean (*psPeerActivate)(freerdp_peer* client); +typedef int (*psPeerSendChannelData)(freerdp_peer* client, int channelId, uint8* data, int size); +typedef int (*psPeerReceiveChannelData)(freerdp_peer* client, int channelId, uint8* data, int size, int flags, int total_size); + struct rdp_freerdp_peer { rdpContext* context; @@ -57,6 +60,9 @@ struct rdp_freerdp_peer psPeerPostConnect PostConnect; psPeerActivate Activate; + + psPeerSendChannelData SendChannelData; + psPeerReceiveChannelData ReceiveChannelData; }; FREERDP_API void freerdp_peer_context_new(freerdp_peer* client); diff --git a/libfreerdp-core/channel.c b/libfreerdp-core/channel.c index 0da4537f6..e92a0a80c 100644 --- a/libfreerdp-core/channel.c +++ b/libfreerdp-core/channel.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -100,3 +101,16 @@ void freerdp_channel_process(freerdp* instance, STREAM* s, uint16 channel_id) channel_id, stream_get_tail(s), chunk_length, flags, length); } +void freerdp_channel_peer_process(freerdp_peer* client, STREAM* s, uint16 channel_id) +{ + uint32 length; + uint32 flags; + int chunk_length; + + stream_read_uint32(s, length); + stream_read_uint32(s, flags); + chunk_length = stream_get_left(s); + + IFCALL(client->ReceiveChannelData, client, + channel_id, stream_get_tail(s), chunk_length, flags, length); +} diff --git a/libfreerdp-core/channel.h b/libfreerdp-core/channel.h index cfc2e70a0..3632247c4 100644 --- a/libfreerdp-core/channel.h +++ b/libfreerdp-core/channel.h @@ -22,5 +22,6 @@ boolean freerdp_channel_send(rdpRdp* rdp, uint16 channel_id, uint8* data, int size); void freerdp_channel_process(freerdp* instance, STREAM* s, uint16 channel_id); +void freerdp_channel_peer_process(freerdp_peer* client, STREAM* s, uint16 channel_id); #endif /* __CHANNEL_H */ diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c index 3841f9da3..4d381dfbb 100644 --- a/libfreerdp-core/peer.c +++ b/libfreerdp-core/peer.c @@ -126,7 +126,7 @@ static boolean peer_recv_tpkt_pdu(freerdp_peer* client, STREAM* s) if (channelId != MCS_GLOBAL_CHANNEL_ID) { - /* TODO: process channel data from client */ + freerdp_channel_peer_process(client, s, channelId); } else { @@ -242,6 +242,11 @@ static void freerdp_peer_disconnect(freerdp_peer* client) transport_disconnect(client->context->rdp->transport); } +static int freerdp_peer_send_channel_data(freerdp_peer* client, int channelId, uint8* data, int size) +{ + return rdp_send_channel_data(client->context->rdp, channelId, data, size); +} + void freerdp_peer_context_new(freerdp_peer* client) { rdpRdp* rdp; @@ -288,6 +293,7 @@ freerdp_peer* freerdp_peer_new(int sockfd) client->GetFileDescriptor = freerdp_peer_get_fds; client->CheckFileDescriptor = freerdp_peer_check_fds; client->Disconnect = freerdp_peer_disconnect; + client->SendChannelData = freerdp_peer_send_channel_data; } return client; From 3b3c27648d0a2ea00c494ba1685b7f2f860b86a0 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Sun, 11 Dec 2011 19:49:08 +0800 Subject: [PATCH 3/8] wtsvc: add public API. --- include/freerdp/channels/wtsvc.h | 102 +++++++++++++++++++++++++++++ libfreerdp-channels/CMakeLists.txt | 3 +- libfreerdp-channels/wtsvc.c | 73 +++++++++++++++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 include/freerdp/channels/wtsvc.h create mode 100644 libfreerdp-channels/wtsvc.c diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h new file mode 100644 index 000000000..2f439e7fe --- /dev/null +++ b/include/freerdp/channels/wtsvc.h @@ -0,0 +1,102 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Server Virtual Channel Interface + * + * Copyright 2011-2012 Vic Lee + * + * 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. + */ + +/** + * The server-side virtual channel API follows the Microsoft Remote Desktop + * Services API functions WTSVirtualChannel* defined in: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464.aspx + * + * Difference between the MS API are documented in this header. All functions + * are implemented in and integrated with libfreerdp-channels. + * + * Thread-safety: the API is designed to be safe to use one thread per channel. + * To access a virtual channel from multiple threads, one must provide his own + * machanism to protect the virtual channel handle. + */ + +#ifndef __FREERDP_WTSVC_H +#define __FREERDP_WTSVC_H + +#include +#include + +#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001 + +typedef enum _WTS_VIRTUAL_CLASS +{ + WTSVirtualClientData, + WTSVirtualFileHandle +} WTS_VIRTUAL_CLASS; + +/** + * Opens a static or dynamic virtual channel and return the handle. If the + * operation fails, a NULL handle is returned. + * + * The original MS API has 'DWORD SessionId' as the first argument, while we + * just use the server peer instance (representing the session) instead. + */ +FREERDP_API void* WTSVirtualChannelOpenEx( + /* __in */ freerdp_peer* client, + /* __in */ const char* pVirtualName, + /* __in */ uint32 flags); + +/** + * Returns information about a specified virtual channel. + * + * Servers use this function to gain access to a virtual channel file handle + * that can be used for asynchronous I/O. + */ +FREERDP_API boolean WTSVirtualChannelQuery( + /* __in */ void* hChannelHandle, + /* __in */ WTS_VIRTUAL_CLASS WtsVirtualClass, + /* __out */ void** ppBuffer, + /* __out */ uint32* pBytesReturned); + +/** + * Frees memory allocated by WTSVirtualChannelQuery + */ +FREERDP_API void WTSFreeMemory( + /* __in */ void* pMemory); + +/** + * Reads data from the server end of a virtual channel. + */ +FREERDP_API boolean WTSVirtualChannelRead( + /* __in */ void* hChannelHandle, + /* __in */ uint32 TimeOut, + /* __out */ uint8* Buffer, + /* __in */ uint32 BufferSize, + /* __out */ uint32* pBytesRead); + +/** + * Writes data to the server end of a virtual channel. + */ +FREERDP_API boolean WTSVirtualChannelWrite( + /* __in */ void* hChannelHandle, + /* __in */ uint8* Buffer, + /* __in */ uint32 Length, + /* __out */ uint32* pBytesWritten); + +/** + * Closes an open virtual channel handle. + */ +FREERDP_API boolean WTSVirtualChannelClose( + /* __in */ void* hChannelHandle); + +#endif /* __FREERDP_WTSVC_H */ diff --git a/libfreerdp-channels/CMakeLists.txt b/libfreerdp-channels/CMakeLists.txt index ba0108717..da2283d09 100644 --- a/libfreerdp-channels/CMakeLists.txt +++ b/libfreerdp-channels/CMakeLists.txt @@ -19,7 +19,8 @@ set(FREERDP_CHANNELS_SRCS libchannels.c - libchannels.h) + libchannels.h + wtsvc.c) add_library(freerdp-channels ${FREERDP_CHANNELS_SRCS}) diff --git a/libfreerdp-channels/wtsvc.c b/libfreerdp-channels/wtsvc.c new file mode 100644 index 000000000..786933865 --- /dev/null +++ b/libfreerdp-channels/wtsvc.c @@ -0,0 +1,73 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Server Virtual Channel Interface + * + * Copyright 2011-2012 Vic Lee + * + * 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 "config.h" +#include +#include +#include +#include +#include +#include + +void* WTSVirtualChannelOpenEx( + /* __in */ freerdp_peer* client, + /* __in */ const char* pVirtualName, + /* __in */ uint32 flags) +{ + return NULL; +} + +boolean WTSVirtualChannelQuery( + /* __in */ void* hChannelHandle, + /* __in */ WTS_VIRTUAL_CLASS WtsVirtualClass, + /* __out */ void** ppBuffer, + /* __out */ uint32* pBytesReturned) +{ + return false; +} + +void WTSFreeMemory( + /* __in */ void* pMemory) +{ +} + +boolean WTSVirtualChannelRead( + /* __in */ void* hChannelHandle, + /* __in */ uint32 TimeOut, + /* __out */ uint8* Buffer, + /* __in */ uint32 BufferSize, + /* __out */ uint32* pBytesRead) +{ + return false; +} + +boolean WTSVirtualChannelWrite( + /* __in */ void* hChannelHandle, + /* __in */ uint8* Buffer, + /* __in */ uint32 Length, + /* __out */ uint32* pBytesWritten) +{ + return false; +} + +boolean WTSVirtualChannelClose( + /* __in */ void* hChannelHandle) +{ + return false; +} From b1ee431a3eaba4c1af27050e28f1a92a41b01c10 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Mon, 12 Dec 2011 14:12:16 +0800 Subject: [PATCH 4/8] wtsvc: implement channel open/close. --- libfreerdp-channels/CMakeLists.txt | 3 +- libfreerdp-channels/wtsvc.c | 49 +++++++++++++++++++++++++++--- libfreerdp-channels/wtsvc.h | 41 +++++++++++++++++++++++++ server/test/CMakeLists.txt | 1 + server/test/tfreerdp.c | 21 +++++++++++++ 5 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 libfreerdp-channels/wtsvc.h diff --git a/libfreerdp-channels/CMakeLists.txt b/libfreerdp-channels/CMakeLists.txt index da2283d09..55a139a94 100644 --- a/libfreerdp-channels/CMakeLists.txt +++ b/libfreerdp-channels/CMakeLists.txt @@ -20,7 +20,8 @@ set(FREERDP_CHANNELS_SRCS libchannels.c libchannels.h - wtsvc.c) + wtsvc.c + wtsvc.h) add_library(freerdp-channels ${FREERDP_CHANNELS_SRCS}) diff --git a/libfreerdp-channels/wtsvc.c b/libfreerdp-channels/wtsvc.c index 786933865..24d68ea4e 100644 --- a/libfreerdp-channels/wtsvc.c +++ b/libfreerdp-channels/wtsvc.c @@ -21,16 +21,52 @@ #include #include #include -#include #include -#include + +#include "wtsvc.h" void* WTSVirtualChannelOpenEx( /* __in */ freerdp_peer* client, /* __in */ const char* pVirtualName, /* __in */ uint32 flags) { - return NULL; + int i; + int len; + rdpPeerChannel* channel; + const char* channel_name; + + channel_name = ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0 ? "drdynvc" : pVirtualName); + + len = strlen(channel_name); + if (len > 8) + return NULL; + + for (i = 0; i < client->settings->num_channels; i++) + { + if (client->settings->channels[i].joined && + strncmp(client->settings->channels[i].name, channel_name, len) == 0) + { + break; + } + } + if (i >= client->settings->num_channels) + return NULL; + + channel = xnew(rdpPeerChannel); + channel->client = client; + channel->channel_id = client->settings->channels[i].channel_id; + if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) + { + channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; + + /* TODO: do DVC channel initialization here using pVirtualName */ + } + else + { + channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; + } + + return channel; } boolean WTSVirtualChannelQuery( @@ -69,5 +105,10 @@ boolean WTSVirtualChannelWrite( boolean WTSVirtualChannelClose( /* __in */ void* hChannelHandle) { - return false; + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + + if (channel != NULL) + xfree(channel); + + return true; } diff --git a/libfreerdp-channels/wtsvc.h b/libfreerdp-channels/wtsvc.h new file mode 100644 index 000000000..795e4090b --- /dev/null +++ b/libfreerdp-channels/wtsvc.h @@ -0,0 +1,41 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Server Virtual Channel Interface + * + * Copyright 2011-2012 Vic Lee + * + * 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 __WTSVC_H +#define __WTSVC_H + +#include +#include +#include +#include + +enum +{ + RDP_PEER_CHANNEL_TYPE_SVC = 0, + RDP_PEER_CHANNEL_TYPE_DVC = 1 +}; + +typedef struct rdp_peer_channel +{ + freerdp_peer* client; + uint16 channel_id; + uint16 channel_type; +} rdpPeerChannel; + +#endif /* __WTSVC_H */ diff --git a/server/test/CMakeLists.txt b/server/test/CMakeLists.txt index 842b8617c..eb930231e 100644 --- a/server/test/CMakeLists.txt +++ b/server/test/CMakeLists.txt @@ -23,3 +23,4 @@ add_executable(tfreerdp-server target_link_libraries(tfreerdp-server freerdp-core) target_link_libraries(tfreerdp-server freerdp-utils) target_link_libraries(tfreerdp-server freerdp-codec) +target_link_libraries(tfreerdp-server freerdp-channels) diff --git a/server/test/tfreerdp.c b/server/test/tfreerdp.c index ebde3fe8b..78a1a146e 100644 --- a/server/test/tfreerdp.c +++ b/server/test/tfreerdp.c @@ -31,6 +31,7 @@ #include #include #include +#include static char* test_pcap_file = NULL; static boolean test_dump_rfx_realtime = true; @@ -54,6 +55,7 @@ struct test_peer_context int icon_x; int icon_y; boolean activated; + void* debug_channel; }; typedef struct test_peer_context testPeerContext; @@ -319,6 +321,9 @@ void tf_peer_dump_rfx(freerdp_peer* client) boolean tf_peer_post_connect(freerdp_peer* client) { + int i; + testPeerContext* context = (testPeerContext*) client->context; + /** * This callback is called when the entire connection sequence is done, i.e. we've received the * Font List PDU from the client and sent out the Font Map PDU. @@ -342,6 +347,22 @@ boolean tf_peer_post_connect(freerdp_peer* client) /* A real server should tag the peer as activated here and start sending updates in mainloop. */ test_peer_load_icon(client); + /* Iterate all channel names requested by the client and activate those supported by the server */ + for (i = 0; i < client->settings->num_channels; i++) + { + if (client->settings->channels[i].joined) + { + if (strncmp(client->settings->channels[i].name, "rdpdbg", 6) == 0) + { + context->debug_channel = WTSVirtualChannelOpenEx(client, "rdpdbg", 0); + if (context->debug_channel != NULL) + { + printf("Open channel rdpdbg.\n"); + } + } + } + } + /* Return false here would stop the execution of the peer mainloop. */ return true; } From 228ebb83cd5085f1204314cf15317f39aae8e705 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Mon, 12 Dec 2011 16:42:42 +0800 Subject: [PATCH 5/8] wtsvc: implement channel writing. --- include/freerdp/channels/wtsvc.h | 22 ++++-- libfreerdp-channels/wtsvc.c | 114 ++++++++++++++++++++++++++++++- libfreerdp-channels/wtsvc.h | 10 +++ server/test/tfreerdp.c | 16 ++++- 4 files changed, 154 insertions(+), 8 deletions(-) diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index 2f439e7fe..652f501a1 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -25,9 +25,8 @@ * Difference between the MS API are documented in this header. All functions * are implemented in and integrated with libfreerdp-channels. * - * Thread-safety: the API is designed to be safe to use one thread per channel. - * To access a virtual channel from multiple threads, one must provide his own - * machanism to protect the virtual channel handle. + * Unlike MS API, all functions except WTSVirtualChannelOpenEx in this + * implementation are thread-safe. */ #ifndef __FREERDP_WTSVC_H @@ -36,6 +35,8 @@ #include #include +typedef struct WTSVirtualChannelManager WTSVirtualChannelManager; + #define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001 typedef enum _WTS_VIRTUAL_CLASS @@ -44,15 +45,26 @@ typedef enum _WTS_VIRTUAL_CLASS WTSVirtualFileHandle } WTS_VIRTUAL_CLASS; +/** + * WTSVirtualChannelManager functions are FreeRDP extensions to the API. + */ +FREERDP_API WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client); +FREERDP_API void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm); +FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, + void** fds, int* fds_count); +FREERDP_API boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm); + /** * Opens a static or dynamic virtual channel and return the handle. If the * operation fails, a NULL handle is returned. * * The original MS API has 'DWORD SessionId' as the first argument, while we - * just use the server peer instance (representing the session) instead. + * use our WTSVirtualChannelManager object instead. + * + * This functions should be called only from the main thread. */ FREERDP_API void* WTSVirtualChannelOpenEx( - /* __in */ freerdp_peer* client, + /* __in */ WTSVirtualChannelManager* vcm, /* __in */ const char* pVirtualName, /* __in */ uint32 flags); diff --git a/libfreerdp-channels/wtsvc.c b/libfreerdp-channels/wtsvc.c index 24d68ea4e..88f3d0c26 100644 --- a/libfreerdp-channels/wtsvc.c +++ b/libfreerdp-channels/wtsvc.c @@ -25,8 +25,83 @@ #include "wtsvc.h" +struct send_item +{ + uint16 channel_id; + uint8* buffer; + uint32 length; +}; + +static void send_item_free(struct send_item* item) +{ + xfree(item->buffer); + xfree(item); +} + +WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client) +{ + WTSVirtualChannelManager* vcm; + + vcm = xnew(WTSVirtualChannelManager); + if (vcm != NULL) + { + vcm->client = client; + vcm->send_event = wait_obj_new(); + vcm->send_queue = list_new(); + vcm->mutex = freerdp_mutex_new(); + } + + return vcm; +} + +void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm) +{ + struct send_item* item; + + if (vcm != NULL) + { + wait_obj_free(vcm->send_event); + while ((item = (struct send_item*) list_dequeue(vcm->send_queue)) != NULL) + { + send_item_free(item); + } + list_free(vcm->send_queue); + freerdp_mutex_free(vcm->mutex); + xfree(vcm); + } +} + +void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, + void** fds, int* fds_count) +{ + wait_obj_get_fds(vcm->send_event, fds, fds_count); +} + +boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm) +{ + boolean result = true; + struct send_item* item; + + wait_obj_clear(vcm->send_event); + + freerdp_mutex_lock(vcm->mutex); + while ((item = (struct send_item*) list_dequeue(vcm->send_queue)) != NULL) + { + if (vcm->client->SendChannelData(vcm->client, item->channel_id, item->buffer, item->length) == false) + { + result = false; + } + send_item_free(item); + if (result == false) + break; + } + freerdp_mutex_unlock(vcm->mutex); + + return result; +} + void* WTSVirtualChannelOpenEx( - /* __in */ freerdp_peer* client, + /* __in */ WTSVirtualChannelManager* vcm, /* __in */ const char* pVirtualName, /* __in */ uint32 flags) { @@ -34,6 +109,7 @@ void* WTSVirtualChannelOpenEx( int len; rdpPeerChannel* channel; const char* channel_name; + freerdp_peer* client = vcm->client; channel_name = ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0 ? "drdynvc" : pVirtualName); @@ -53,6 +129,7 @@ void* WTSVirtualChannelOpenEx( return NULL; channel = xnew(rdpPeerChannel); + channel->vcm = vcm; channel->client = client; channel->channel_id = client->settings->channels[i].channel_id; if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) @@ -99,7 +176,40 @@ boolean WTSVirtualChannelWrite( /* __in */ uint32 Length, /* __out */ uint32* pBytesWritten) { - return false; + uint32 written = 0; + boolean result = false; + struct send_item* item; + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + WTSVirtualChannelManager* vcm = channel->vcm; + + if (channel == NULL) + return false; + + if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) + { + item = xnew(struct send_item); + item->channel_id = channel->channel_id; + item->buffer = xmalloc(Length); + item->length = Length; + memcpy(item->buffer, Buffer, Length); + + freerdp_mutex_lock(vcm->mutex); + list_enqueue(vcm->send_queue, item); + freerdp_mutex_unlock(vcm->mutex); + + wait_obj_set(vcm->send_event); + + written = Length; + result = true; + } + else + { + /* TODO: Send to DVC channel */ + } + + if (pBytesWritten != NULL) + *pBytesWritten = written; + return result; } boolean WTSVirtualChannelClose( diff --git a/libfreerdp-channels/wtsvc.h b/libfreerdp-channels/wtsvc.h index 795e4090b..ce71958cc 100644 --- a/libfreerdp-channels/wtsvc.h +++ b/libfreerdp-channels/wtsvc.h @@ -23,6 +23,7 @@ #include #include #include +#include #include enum @@ -33,9 +34,18 @@ enum typedef struct rdp_peer_channel { + WTSVirtualChannelManager* vcm; freerdp_peer* client; uint16 channel_id; uint16 channel_type; } rdpPeerChannel; +struct WTSVirtualChannelManager +{ + freerdp_peer* client; + struct wait_obj* send_event; + LIST* send_queue; + freerdp_mutex mutex; +}; + #endif /* __WTSVC_H */ diff --git a/server/test/tfreerdp.c b/server/test/tfreerdp.c index 78a1a146e..90743c6a1 100644 --- a/server/test/tfreerdp.c +++ b/server/test/tfreerdp.c @@ -55,6 +55,7 @@ struct test_peer_context int icon_x; int icon_y; boolean activated; + WTSVirtualChannelManager* vcm; void* debug_channel; }; typedef struct test_peer_context testPeerContext; @@ -71,6 +72,8 @@ void test_peer_context_new(freerdp_peer* client, testPeerContext* context) context->icon_x = -1; context->icon_y = -1; + + context->vcm = WTSCreateVirtualChannelManager(client); } void test_peer_context_free(freerdp_peer* client, testPeerContext* context) @@ -81,6 +84,11 @@ void test_peer_context_free(freerdp_peer* client, testPeerContext* context) xfree(context->icon_data); xfree(context->bg_data); rfx_context_free(context->rfx_context); + if (context->debug_channel) + { + WTSVirtualChannelClose(context->debug_channel); + } + WTSDestroyVirtualChannelManager(context->vcm); xfree(context); } } @@ -354,10 +362,11 @@ boolean tf_peer_post_connect(freerdp_peer* client) { if (strncmp(client->settings->channels[i].name, "rdpdbg", 6) == 0) { - context->debug_channel = WTSVirtualChannelOpenEx(client, "rdpdbg", 0); + context->debug_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpdbg", 0); if (context->debug_channel != NULL) { printf("Open channel rdpdbg.\n"); + WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test1", 5, NULL); } } } @@ -442,6 +451,7 @@ static void* test_peer_mainloop(void* arg) int rcount; void* rfds[32]; fd_set rfds_set; + testPeerContext* context; freerdp_peer* client = (freerdp_peer*) arg; memset(rfds, 0, sizeof(rfds)); @@ -464,6 +474,7 @@ static void* test_peer_mainloop(void* arg) client->input->ExtendedMouseEvent = tf_peer_extended_mouse_event; client->Initialize(client); + context = (testPeerContext*) client->context; printf("We've got a client %s\n", client->hostname); @@ -476,6 +487,7 @@ static void* test_peer_mainloop(void* arg) printf("Failed to get FreeRDP file descriptor\n"); break; } + WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount); max_fds = 0; FD_ZERO(&rfds_set); @@ -508,6 +520,8 @@ static void* test_peer_mainloop(void* arg) if (client->CheckFileDescriptor(client) != true) break; + if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != true) + break; } printf("Client %s disconnected.\n", client->hostname); From d3fc3ff2e6b93797d05cfff241b578984919f888 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Mon, 12 Dec 2011 21:07:23 +0800 Subject: [PATCH 6/8] wtsvc: implement channel reading. --- include/freerdp/channels/wtsvc.h | 14 +++ libfreerdp-channels/wtsvc.c | 194 +++++++++++++++++++++++++++---- libfreerdp-channels/wtsvc.h | 12 +- 3 files changed, 196 insertions(+), 24 deletions(-) diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index 652f501a1..37565076b 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -88,6 +88,20 @@ FREERDP_API void WTSFreeMemory( /** * Reads data from the server end of a virtual channel. + * + * FreeRDP behavior: + * + * This function will always return a complete channel data packet, i.e. chunks + * are already assembled. If BufferSize argument is smaller than the packet + * size, it will set the desired size in pBytesRead and return false. The + * caller should allocate a large enough buffer and call this function again. + * Returning false with pBytesRead set to zero indicates an error has occurred. + * If no pending packet to be read, it will set pBytesRead to zero and return + * true. + * + * TimeOut is not supported, and this function will always return immediately. + * The caller should use the file handle returned by WTSVirtualChannelQuery to + * determine whether a packet has arrived. */ FREERDP_API boolean WTSVirtualChannelRead( /* __in */ void* hChannelHandle, diff --git a/libfreerdp-channels/wtsvc.c b/libfreerdp-channels/wtsvc.c index 88f3d0c26..03a91b4b7 100644 --- a/libfreerdp-channels/wtsvc.c +++ b/libfreerdp-channels/wtsvc.c @@ -21,23 +21,87 @@ #include #include #include +#include #include #include "wtsvc.h" -struct send_item +typedef struct wts_data_item { uint16 channel_id; uint8* buffer; uint32 length; -}; +} wts_data_item; -static void send_item_free(struct send_item* item) +static void wts_data_item_free(wts_data_item* item) { xfree(item->buffer); xfree(item); } +static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size) +{ + wts_data_item* item; + + if (flags & CHANNEL_FLAG_FIRST) + { + stream_set_pos(channel->receive_data, 0); + } + + stream_check_size(channel->receive_data, size); + stream_write(channel->receive_data, data, size); + + if (flags & CHANNEL_FLAG_LAST) + { + if (stream_get_length(channel->receive_data) != total_size) + { + printf("WTSProcessChannelData: read error\n"); + } + if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC) + { + /* TODO: Receive DVC channel data */ + } + else + { + item = xnew(wts_data_item); + item->length = stream_get_length(channel->receive_data); + item->buffer = xmalloc(item->length); + memcpy(item->buffer, stream_get_head(channel->receive_data), item->length); + + freerdp_mutex_lock(channel->mutex); + list_enqueue(channel->receive_queue, item); + freerdp_mutex_unlock(channel->mutex); + + wait_obj_set(channel->receive_event); + } + stream_set_pos(channel->receive_data, 0); + } +} + +static int WTSReceiveChannelData(freerdp_peer* client, int channelId, uint8* data, int size, int flags, int total_size) +{ + int i; + boolean result = false; + rdpPeerChannel* channel; + + for (i = 0; i < client->settings->num_channels; i++) + { + if (client->settings->channels[i].channel_id == channelId) + break; + } + if (i < client->settings->num_channels) + { + channel = (rdpPeerChannel*) client->settings->channels[i].handle; + if (channel != NULL) + { + WTSProcessChannelData(channel, channelId, data, size, flags, total_size); + result = true; + } + } + + return result; +} + WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client) { WTSVirtualChannelManager* vcm; @@ -49,6 +113,8 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client) vcm->send_event = wait_obj_new(); vcm->send_queue = list_new(); vcm->mutex = freerdp_mutex_new(); + + client->ReceiveChannelData = WTSReceiveChannelData; } return vcm; @@ -56,14 +122,20 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client) void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm) { - struct send_item* item; + wts_data_item* item; if (vcm != NULL) { - wait_obj_free(vcm->send_event); - while ((item = (struct send_item*) list_dequeue(vcm->send_queue)) != NULL) + if (vcm->drdynvc_channel != NULL) { - send_item_free(item); + WTSVirtualChannelClose(vcm->drdynvc_channel); + vcm->drdynvc_channel = NULL; + } + + wait_obj_free(vcm->send_event); + while ((item = (wts_data_item*) list_dequeue(vcm->send_queue)) != NULL) + { + wts_data_item_free(item); } list_free(vcm->send_queue); freerdp_mutex_free(vcm->mutex); @@ -80,18 +152,18 @@ void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm) { boolean result = true; - struct send_item* item; + wts_data_item* item; wait_obj_clear(vcm->send_event); freerdp_mutex_lock(vcm->mutex); - while ((item = (struct send_item*) list_dequeue(vcm->send_queue)) != NULL) + while ((item = (wts_data_item*) list_dequeue(vcm->send_queue)) != NULL) { if (vcm->client->SendChannelData(vcm->client, item->channel_id, item->buffer, item->length) == false) { result = false; } - send_item_free(item); + wts_data_item_free(item); if (result == false) break; } @@ -128,19 +200,35 @@ void* WTSVirtualChannelOpenEx( if (i >= client->settings->num_channels) return NULL; - channel = xnew(rdpPeerChannel); - channel->vcm = vcm; - channel->client = client; - channel->channel_id = client->settings->channels[i].channel_id; - if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) + channel = (rdpPeerChannel*) client->settings->channels[i].handle; + if (channel == NULL) { - channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; + channel = xnew(rdpPeerChannel); + channel->vcm = vcm; + channel->client = client; + channel->channel_id = client->settings->channels[i].channel_id; + channel->index = i; + channel->receive_data = stream_new(client->settings->vc_chunk_size); + if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) + { + channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; + vcm->drdynvc_channel = channel; + } + else + { + channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; + channel->receive_event = wait_obj_new(); + channel->receive_queue = list_new(); + channel->mutex = freerdp_mutex_new(); + } - /* TODO: do DVC channel initialization here using pVirtualName */ + client->settings->channels[i].handle = channel; } - else + if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC) { - channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; + /* TODO: do DVC channel initialization here using pVirtualName */ + /* A sub-channel should be created and returned, instead of using the main drdynvc channel */ + /* Set channel->index to num_channels */ } return channel; @@ -152,12 +240,31 @@ boolean WTSVirtualChannelQuery( /* __out */ void** ppBuffer, /* __out */ uint32* pBytesReturned) { - return false; + void* fds[10]; + int fds_count = 0; + boolean result = false; + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + + switch (WtsVirtualClass) + { + case WTSVirtualFileHandle: + wait_obj_get_fds(channel->receive_event, fds, &fds_count); + *ppBuffer = xmalloc(sizeof(void*)); + memcpy(*ppBuffer, &fds[0], sizeof(void*)); + *pBytesReturned = sizeof(void*); + result = true; + break; + + default: + break; + } + return result; } void WTSFreeMemory( /* __in */ void* pMemory) { + xfree(pMemory); } boolean WTSVirtualChannelRead( @@ -167,7 +274,30 @@ boolean WTSVirtualChannelRead( /* __in */ uint32 BufferSize, /* __out */ uint32* pBytesRead) { - return false; + wts_data_item* item; + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + + item = (wts_data_item*) list_peek(channel->receive_queue); + if (item == NULL) + { + wait_obj_clear(channel->receive_event); + *pBytesRead = 0; + return true; + } + *pBytesRead = item->length; + if (item->length > BufferSize) + return false; + + /* remove the first element (same as what we just peek) */ + freerdp_mutex_lock(channel->mutex); + list_dequeue(channel->receive_queue); + if (channel->receive_queue->head == NULL) + wait_obj_clear(channel->receive_event); + freerdp_mutex_unlock(channel->mutex); + + memcpy(Buffer, item->buffer, item->length); + + return true; } boolean WTSVirtualChannelWrite( @@ -177,8 +307,8 @@ boolean WTSVirtualChannelWrite( /* __out */ uint32* pBytesWritten) { uint32 written = 0; + wts_data_item* item; boolean result = false; - struct send_item* item; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; WTSVirtualChannelManager* vcm = channel->vcm; @@ -187,7 +317,7 @@ boolean WTSVirtualChannelWrite( if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) { - item = xnew(struct send_item); + item = xnew(wts_data_item); item->channel_id = channel->channel_id; item->buffer = xmalloc(Length); item->length = Length; @@ -215,10 +345,28 @@ boolean WTSVirtualChannelWrite( boolean WTSVirtualChannelClose( /* __in */ void* hChannelHandle) { + wts_data_item* item; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; if (channel != NULL) + { + if (channel->index < channel->client->settings->num_channels) + channel->client->settings->channels[channel->index].handle = NULL; + stream_free(channel->receive_data); + if (channel->receive_event) + wait_obj_free(channel->receive_event); + if (channel->receive_queue) + { + while ((item = (wts_data_item*) list_dequeue(channel->receive_queue)) != NULL) + { + wts_data_item_free(item); + } + list_free(channel->receive_queue); + } + if (channel->mutex) + freerdp_mutex_free(channel->mutex); xfree(channel); + } return true; } diff --git a/libfreerdp-channels/wtsvc.h b/libfreerdp-channels/wtsvc.h index ce71958cc..11110d490 100644 --- a/libfreerdp-channels/wtsvc.h +++ b/libfreerdp-channels/wtsvc.h @@ -21,6 +21,7 @@ #define __WTSVC_H #include +#include #include #include #include @@ -29,7 +30,8 @@ enum { RDP_PEER_CHANNEL_TYPE_SVC = 0, - RDP_PEER_CHANNEL_TYPE_DVC = 1 + RDP_PEER_CHANNEL_TYPE_DVC = 1, + RDP_PEER_CHANNEL_TYPE_DVC_SUB = 2 }; typedef struct rdp_peer_channel @@ -38,6 +40,12 @@ typedef struct rdp_peer_channel freerdp_peer* client; uint16 channel_id; uint16 channel_type; + uint16 index; + + STREAM* receive_data; + struct wait_obj* receive_event; + LIST* receive_queue; + freerdp_mutex mutex; } rdpPeerChannel; struct WTSVirtualChannelManager @@ -46,6 +54,8 @@ struct WTSVirtualChannelManager struct wait_obj* send_event; LIST* send_queue; freerdp_mutex mutex; + + rdpPeerChannel* drdynvc_channel; }; #endif /* __WTSVC_H */ From f3c06defb19c8d20000c7f0377e837d478258881 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Mon, 12 Dec 2011 22:36:11 +0800 Subject: [PATCH 7/8] libfreerdp-utils/wait_obj: add attached wait_obj type. --- include/freerdp/utils/wait_obj.h | 1 + libfreerdp-utils/wait_obj.c | 52 +++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/freerdp/utils/wait_obj.h b/include/freerdp/utils/wait_obj.h index cb75edb2c..a202a25df 100644 --- a/include/freerdp/utils/wait_obj.h +++ b/include/freerdp/utils/wait_obj.h @@ -23,6 +23,7 @@ #include FREERDP_API struct wait_obj* wait_obj_new(void); +FREERDP_API struct wait_obj* wait_obj_new_with_fd(void* fd); FREERDP_API void wait_obj_free(struct wait_obj* obj); FREERDP_API int wait_obj_is_set(struct wait_obj* obj); FREERDP_API void wait_obj_set(struct wait_obj* obj); diff --git a/libfreerdp-utils/wait_obj.c b/libfreerdp-utils/wait_obj.c index 34273380b..a2ba5b921 100644 --- a/libfreerdp-utils/wait_obj.c +++ b/libfreerdp-utils/wait_obj.c @@ -41,6 +41,7 @@ struct wait_obj #else int pipe_fd[2]; #endif + int attached; }; struct wait_obj* @@ -50,6 +51,7 @@ wait_obj_new(void) obj = xnew(struct wait_obj); + obj->attached = 0; #ifdef _WIN32 obj->event = CreateEvent(NULL, TRUE, FALSE, NULL); #else @@ -66,30 +68,50 @@ wait_obj_new(void) return obj; } +struct wait_obj* wait_obj_new_with_fd(void* fd) +{ + struct wait_obj* obj; + + obj = xnew(struct wait_obj); + + obj->attached = 1; +#ifdef _WIN32 + obj->event = fd; +#else + obj->pipe_fd[0] = (int)(long)fd; + obj->pipe_fd[1] = -1; +#endif + + return obj; +} + void wait_obj_free(struct wait_obj* obj) { if (obj) { + if (obj->attached == 0) + { #ifdef _WIN32 - if (obj->event) - { - CloseHandle(obj->event); - obj->event = NULL; - } + if (obj->event) + { + CloseHandle(obj->event); + obj->event = NULL; + } #else - if (obj->pipe_fd[0] != -1) - { - close(obj->pipe_fd[0]); - obj->pipe_fd[0] = -1; - } - if (obj->pipe_fd[1] != -1) - { - close(obj->pipe_fd[1]); - obj->pipe_fd[1] = -1; - } + if (obj->pipe_fd[0] != -1) + { + close(obj->pipe_fd[0]); + obj->pipe_fd[0] = -1; + } + if (obj->pipe_fd[1] != -1) + { + close(obj->pipe_fd[1]); + obj->pipe_fd[1] = -1; + } #endif + } xfree(obj); } From fd806cfdd24a134fea02972bdecefe98a27bf89c Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Mon, 12 Dec 2011 22:37:48 +0800 Subject: [PATCH 8/8] server/test: add debug channel thread for channel testing. --- server/test/tfreerdp.c | 68 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/server/test/tfreerdp.c b/server/test/tfreerdp.c index 90743c6a1..74761cf53 100644 --- a/server/test/tfreerdp.c +++ b/server/test/tfreerdp.c @@ -57,6 +57,7 @@ struct test_peer_context boolean activated; WTSVirtualChannelManager* vcm; void* debug_channel; + freerdp_thread* debug_channel_thread; }; typedef struct test_peer_context testPeerContext; @@ -80,6 +81,11 @@ void test_peer_context_free(freerdp_peer* client, testPeerContext* context) { if (context) { + if (context->debug_channel_thread) + { + freerdp_thread_stop(context->debug_channel_thread); + freerdp_thread_free(context->debug_channel_thread); + } stream_free(context->s); xfree(context->icon_data); xfree(context->bg_data); @@ -327,6 +333,57 @@ void tf_peer_dump_rfx(freerdp_peer* client) } } +static void* tf_debug_channel_thread_func(void* arg) +{ + void* fd; + STREAM* s; + void* buffer; + uint32 bytes_returned = 0; + testPeerContext* context = (testPeerContext*) arg; + freerdp_thread* thread = context->debug_channel_thread; + + if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == true) + { + fd = *((void**)buffer); + WTSFreeMemory(buffer); + thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd); + } + + s = stream_new(4096); + + WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test1", 5, NULL); + + while (1) + { + freerdp_thread_wait(thread); + if (freerdp_thread_is_stopped(thread)) + break; + + stream_set_pos(s, 0); + if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s), + stream_get_size(s), &bytes_returned) == false) + { + if (bytes_returned == 0) + break; + stream_check_size(s, bytes_returned); + if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s), + stream_get_size(s), &bytes_returned) == false) + { + /* should not happen */ + break; + } + } + stream_set_pos(s, bytes_returned); + + printf("got %d bytes\n", bytes_returned); + } + + stream_free(s); + freerdp_thread_quit(thread); + + return 0; +} + boolean tf_peer_post_connect(freerdp_peer* client) { int i; @@ -366,7 +423,9 @@ boolean tf_peer_post_connect(freerdp_peer* client) if (context->debug_channel != NULL) { printf("Open channel rdpdbg.\n"); - WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test1", 5, NULL); + context->debug_channel_thread = freerdp_thread_new(); + freerdp_thread_start(context->debug_channel_thread, + tf_debug_channel_thread_func, context); } } } @@ -424,6 +483,13 @@ void tf_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code) update->DesktopResize(update->context); context->activated = false; } + else if ((flags & 0x4000) && code == 0x2E) /* 'c' key */ + { + if (context->debug_channel) + { + WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test2", 5, NULL); + } + } } void tf_peer_unicode_keyboard_event(rdpInput* input, uint16 code)