From aaef9694abed02fb42ec9a249f3144a4dc0b18d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 15 Oct 2012 17:03:34 -0400 Subject: [PATCH] libfreerdp-channels: split in client/server functionality, move to libfreerdp-channels-client and libfreerdp-channels-server --- CMakeLists.txt | 8 +- channels/audin/server/CMakeLists.txt | 2 +- channels/client/CMakeLists.txt | 10 + channels/client/channels.c | 986 ++++++++++++++++ channels/server/CMakeLists.txt | 13 +- channels/server/channels.c | 781 +++++++++++++ .../wtsvc.h => channels/server/channels.h | 3 +- client/DirectFB/CMakeLists.txt | 2 +- client/Mac/CMakeLists.txt | 4 +- client/Sample/CMakeLists.txt | 2 +- client/Windows/CMakeLists.txt | 2 +- client/X11/CMakeLists.txt | 2 +- cunit/CMakeLists.txt | 1 - libfreerdp/CMakeLists.txt | 1 - libfreerdp/channels/CMakeLists.txt | 50 - libfreerdp/channels/libchannels.c | 1006 ----------------- libfreerdp/channels/libchannels.h | 36 - libfreerdp/channels/wtsvc.c | 807 ------------- server/Sample/CMakeLists.txt | 2 +- server/Windows/CMakeLists.txt | 2 +- 20 files changed, 1803 insertions(+), 1917 deletions(-) rename libfreerdp/channels/wtsvc.h => channels/server/channels.h (95%) delete mode 100644 libfreerdp/channels/CMakeLists.txt delete mode 100644 libfreerdp/channels/libchannels.c delete mode 100644 libfreerdp/channels/libchannels.h delete mode 100644 libfreerdp/channels/wtsvc.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 66fc38421..6f7e1a810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,10 +215,10 @@ add_definitions("-DHAVE_CONFIG_H") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h) # RPATH configuration -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") +#set(CMAKE_SKIP_BUILD_RPATH FALSE) +#set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +#set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") # Unit Tests diff --git a/channels/audin/server/CMakeLists.txt b/channels/audin/server/CMakeLists.txt index a067d4d0e..5035c6728 100644 --- a/channels/audin/server/CMakeLists.txt +++ b/channels/audin/server/CMakeLists.txt @@ -29,6 +29,6 @@ set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-utils freerdp-channels) + MODULES freerdp-utils) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL}/Server") diff --git a/channels/client/CMakeLists.txt b/channels/client/CMakeLists.txt index 3a196aec5..b77da9d54 100644 --- a/channels/client/CMakeLists.txt +++ b/channels/client/CMakeLists.txt @@ -64,6 +64,16 @@ add_library(${MODULE_NAME} STATIC ${${MODULE_PREFIX}_SRCS}) set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL + MODULE freerdp + MODULES freerdp-utils) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-crt winpr-synch winpr-interlocked) + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/channels/client/channels.c b/channels/client/channels.c index ab7def82f..fec5e3b66 100644 --- a/channels/client/channels.c +++ b/channels/client/channels.c @@ -2,6 +2,8 @@ * FreeRDP: A Remote Desktop Protocol Implementation * Client Channels * + * Copyright 2009-2011 Jay Sorg + * Copyright 2010-2011 Vic Lee * Copyright 2012 Marc-Andre Moreau * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +25,42 @@ #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef WITH_DEBUG_CHANNELS +#define DEBUG_CHANNELS(fmt, ...) DEBUG_CLASS(CHANNELS, fmt, ## __VA_ARGS__) +#else +#define DEBUG_CHANNELS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#endif + +#define CHANNEL_MAX_COUNT 30 + +/** + * MS compatible plugin interface + * reference: + * http://msdn.microsoft.com/en-us/library/aa383580.aspx + * + * Notes on threads: + * Many virtual channel plugins are built using threads. + * Non main threads may call MyVirtualChannelOpen, + * MyVirtualChannelClose, or MyVirtualChannelWrite. + * Since the plugin's VirtualChannelEntry function is called + * from the main thread, MyVirtualChannelInit has to be called + * from the main thread. + */ extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[]; @@ -76,3 +113,952 @@ void* freerdp_channels_find_static_device_service_entry(const char* name) { return freerdp_channels_find_static_entry("DeviceServiceEntry", name); } + +struct lib_data +{ + PVIRTUALCHANNELENTRY entry; /* the one and only exported function */ + PCHANNEL_INIT_EVENT_FN init_event_proc; + void* init_handle; +}; + +struct channel_data +{ + char name[CHANNEL_NAME_LEN + 1]; + int open_handle; + int options; + int flags; /* 0 nothing 1 init 2 open */ + PCHANNEL_OPEN_EVENT_FN open_event_proc; +}; + +struct _SYNC_DATA +{ + SLIST_ENTRY ItemEntry; + void* Data; + UINT32 DataLength; + void* UserData; + int Index; +}; +typedef struct _SYNC_DATA SYNC_DATA; + +typedef struct rdp_init_handle rdpInitHandle; + +struct rdp_init_handle +{ + rdpChannels* channels; +}; + +struct rdp_channels +{ + /** + * Only the main thread alters these arrays, before any + * library thread is allowed in(post_connect is called) + * so no need to use mutex locking + * After post_connect, each library thread can only access it's + * own array items + * ie, no two threads can access index 0, ... + */ + + struct lib_data libs_data[CHANNEL_MAX_COUNT]; + int num_libs_data; + + struct channel_data channels_data[CHANNEL_MAX_COUNT]; + int num_channels_data; + + rdpInitHandle init_handles[CHANNEL_MAX_COUNT]; + int num_init_handles; + + /* control for entry into MyVirtualChannelInit */ + int can_call_init; + rdpSettings* settings; + + /* true once freerdp_chanman_post_connect is called */ + int is_connected; + + /* used for locating the channels for a given instance */ + freerdp* instance; + + /* signal for incoming data or event */ + struct wait_obj* signal; + + /* used for sync write */ + PSLIST_HEADER pSyncDataList; + + /* used for sync event */ + HANDLE event_sem; + RDP_EVENT* event; +}; + +/** + * The current channel manager reference passes from VirtualChannelEntry to + * VirtualChannelInit for the pInitHandle. + */ +static rdpChannels* g_init_channels; + +/* The list of all channel managers. */ +typedef struct rdp_channels_list rdpChannelsList; + +struct rdp_channels_list +{ + rdpChannels* channels; + rdpChannelsList* next; +}; + +static rdpChannelsList* g_channels_list; + +/* To generate unique sequence for all open handles */ +static int g_open_handle_sequence; + +/* For locking the global resources */ +static HANDLE g_mutex_init; +static HANDLE g_mutex_list; + +/* returns the channels for the open handle passed in */ +static rdpChannels* freerdp_channels_find_by_open_handle(int open_handle, int* pindex) +{ + int lindex; + rdpChannels* channels; + rdpChannelsList* channels_list; + + WaitForSingleObject(g_mutex_list, INFINITE); + + for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next) + { + channels = channels_list->channels; + + for (lindex = 0; lindex < channels->num_channels_data; lindex++) + { + if (channels->channels_data[lindex].open_handle == open_handle) + { + ReleaseMutex(g_mutex_list); + *pindex = lindex; + return channels; + } + } + } + + ReleaseMutex(g_mutex_list); + + return NULL; +} + +/* returns the channels for the rdp instance passed in */ +static rdpChannels* freerdp_channels_find_by_instance(freerdp* instance) +{ + rdpChannels* channels; + rdpChannelsList* channels_list; + + WaitForSingleObject(g_mutex_list, INFINITE); + + for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next) + { + channels = channels_list->channels; + if (channels->instance == instance) + { + ReleaseMutex(g_mutex_list); + return channels; + } + } + + ReleaseMutex(g_mutex_list); + + return NULL; +} + +/* returns struct channel_data for the channel name passed in */ +static struct channel_data* freerdp_channels_find_channel_data_by_name(rdpChannels* channels, const char* channel_name, int* pindex) +{ + int lindex; + struct channel_data* lchannel_data; + + for (lindex = 0; lindex < channels->num_channels_data; lindex++) + { + lchannel_data = channels->channels_data + lindex; + + if (strcmp(channel_name, lchannel_data->name) == 0) + { + if (pindex != 0) + *pindex = lindex; + + return lchannel_data; + } + } + + return NULL; +} + +/* returns rdpChannel for the channel id passed in */ +static rdpChannel* freerdp_channels_find_channel_by_id(rdpChannels* channels, rdpSettings* settings, int channel_id, int* pindex) +{ + int lindex; + int lcount; + rdpChannel* lrdp_channel; + + lcount = settings->num_channels; + + for (lindex = 0; lindex < lcount; lindex++) + { + lrdp_channel = settings->channels + lindex; + + if (lrdp_channel->channel_id == channel_id) + { + if (pindex != 0) + *pindex = lindex; + + return lrdp_channel; + } + } + + return NULL; +} + +/* returns rdpChannel for the channel name passed in */ +static rdpChannel* freerdp_channels_find_channel_by_name(rdpChannels* channels, + rdpSettings* settings, const char* channel_name, int* pindex) +{ + int lindex; + int lcount; + rdpChannel* lrdp_channel; + + lcount = settings->num_channels; + + for (lindex = 0; lindex < lcount; lindex++) + { + lrdp_channel = settings->channels + lindex; + + if (strcmp(channel_name, lrdp_channel->name) == 0) + { + if (pindex != 0) + *pindex = lindex; + + return lrdp_channel; + } + } + + return NULL; +} + +/** + * must be called by same thread that calls freerdp_chanman_load_plugin + * according to MS docs + * only called from main thread + */ +static UINT32 FREERDP_CC MyVirtualChannelInit(void** ppInitHandle, PCHANNEL_DEF pChannel, + int channelCount, UINT32 versionRequested, PCHANNEL_INIT_EVENT_FN pChannelInitEventProc) +{ + int index; + rdpChannels* channels; + struct lib_data* llib; + rdpChannel* lrdp_channel; + PCHANNEL_DEF lchannel_def; + struct channel_data* lchannel_data; + + if (ppInitHandle == NULL) + { + DEBUG_CHANNELS("error bad init handle"); + return CHANNEL_RC_BAD_INIT_HANDLE; + } + + channels = g_init_channels; + channels->init_handles[channels->num_init_handles].channels = channels; + *ppInitHandle = &channels->init_handles[channels->num_init_handles]; + channels->num_init_handles++; + + DEBUG_CHANNELS("enter"); + + if (!channels->can_call_init) + { + DEBUG_CHANNELS("error not in entry"); + return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY; + } + + if (channels->num_channels_data + channelCount >= CHANNEL_MAX_COUNT) + { + DEBUG_CHANNELS("error too many channels"); + return CHANNEL_RC_TOO_MANY_CHANNELS; + } + + if (pChannel == 0) + { + DEBUG_CHANNELS("error bad channel"); + return CHANNEL_RC_BAD_CHANNEL; + } + + if (channels->is_connected) + { + DEBUG_CHANNELS("error already connected"); + return CHANNEL_RC_ALREADY_CONNECTED; + } + + if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000) + { + DEBUG_CHANNELS("warning version"); + } + + for (index = 0; index < channelCount; index++) + { + lchannel_def = pChannel + index; + + if (freerdp_channels_find_channel_data_by_name(channels, lchannel_def->name, 0) != 0) + { + DEBUG_CHANNELS("error channel already used"); + return CHANNEL_RC_BAD_CHANNEL; + } + } + + llib = channels->libs_data + channels->num_libs_data; + llib->init_event_proc = pChannelInitEventProc; + llib->init_handle = *ppInitHandle; + channels->num_libs_data++; + + for (index = 0; index < channelCount; index++) + { + lchannel_def = pChannel + index; + lchannel_data = channels->channels_data + channels->num_channels_data; + + WaitForSingleObject(g_mutex_list, INFINITE); + lchannel_data->open_handle = g_open_handle_sequence++; + ReleaseMutex(g_mutex_list); + + lchannel_data->flags = 1; /* init */ + strncpy(lchannel_data->name, lchannel_def->name, CHANNEL_NAME_LEN); + lchannel_data->options = lchannel_def->options; + + if (channels->settings->num_channels < 16) + { + lrdp_channel = channels->settings->channels + channels->settings->num_channels; + strncpy(lrdp_channel->name, lchannel_def->name, 7); + lrdp_channel->options = lchannel_def->options; + channels->settings->num_channels++; + } + else + { + DEBUG_CHANNELS("warning more than 16 channels"); + } + + channels->num_channels_data++; + } + + return CHANNEL_RC_OK; +} + +/** + * can be called from any thread + * thread safe because no 2 threads can have the same channel name registered + */ +static UINT32 FREERDP_CC MyVirtualChannelOpen(void* pInitHandle, UINT32* pOpenHandle, + char* pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc) +{ + int index; + rdpChannels* channels; + struct channel_data* lchannel_data; + + DEBUG_CHANNELS("enter"); + + channels = ((rdpInitHandle*) pInitHandle)->channels; + + if (pOpenHandle == 0) + { + DEBUG_CHANNELS("error bad channel handle"); + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + } + + if (pChannelOpenEventProc == 0) + { + DEBUG_CHANNELS("error bad proc"); + return CHANNEL_RC_BAD_PROC; + } + + if (!channels->is_connected) + { + DEBUG_CHANNELS("error not connected"); + return CHANNEL_RC_NOT_CONNECTED; + } + + lchannel_data = freerdp_channels_find_channel_data_by_name(channels, pChannelName, &index); + + if (lchannel_data == 0) + { + DEBUG_CHANNELS("error channel name"); + return CHANNEL_RC_UNKNOWN_CHANNEL_NAME; + } + + if (lchannel_data->flags == 2) + { + DEBUG_CHANNELS("error channel already open"); + return CHANNEL_RC_ALREADY_OPEN; + } + + lchannel_data->flags = 2; /* open */ + lchannel_data->open_event_proc = pChannelOpenEventProc; + *pOpenHandle = lchannel_data->open_handle; + + return CHANNEL_RC_OK; +} + +/** + * can be called from any thread + * thread safe because no 2 threads can have the same openHandle + */ +static UINT32 FREERDP_CC MyVirtualChannelClose(UINT32 openHandle) +{ + int index; + rdpChannels* channels; + struct channel_data* lchannel_data; + + DEBUG_CHANNELS("enter"); + + channels = freerdp_channels_find_by_open_handle(openHandle, &index); + + if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) + { + DEBUG_CHANNELS("error bad channels"); + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + } + + lchannel_data = channels->channels_data + index; + + if (lchannel_data->flags != 2) + { + DEBUG_CHANNELS("error not open"); + return CHANNEL_RC_NOT_OPEN; + } + + lchannel_data->flags = 0; + + return CHANNEL_RC_OK; +} + +/* can be called from any thread */ +static UINT32 FREERDP_CC MyVirtualChannelWrite(UINT32 openHandle, void* pData, UINT32 dataLength, void* pUserData) +{ + int index; + SYNC_DATA* item; + rdpChannels* channels; + struct channel_data* lchannel_data; + + channels = freerdp_channels_find_by_open_handle(openHandle, &index); + + if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) + { + DEBUG_CHANNELS("error bad channel handle"); + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + } + + if (!channels->is_connected) + { + DEBUG_CHANNELS("error not connected"); + return CHANNEL_RC_NOT_CONNECTED; + } + + if (pData == 0) + { + DEBUG_CHANNELS("error bad pData"); + return CHANNEL_RC_NULL_DATA; + } + + if (dataLength == 0) + { + DEBUG_CHANNELS("error bad dataLength"); + return CHANNEL_RC_ZERO_LENGTH; + } + + lchannel_data = channels->channels_data + index; + + if (lchannel_data->flags != 2) + { + DEBUG_CHANNELS("error not open"); + return CHANNEL_RC_NOT_OPEN; + } + + if (!channels->is_connected) + { + DEBUG_CHANNELS("error not connected"); + return CHANNEL_RC_NOT_CONNECTED; + } + + item = (SYNC_DATA*) _aligned_malloc(sizeof(SYNC_DATA), MEMORY_ALLOCATION_ALIGNMENT); + item->Data = pData; + item->DataLength = dataLength; + item->UserData = pUserData; + item->Index = index; + + InterlockedPushEntrySList(channels->pSyncDataList, &(item->ItemEntry)); + + /* set the event */ + wait_obj_set(channels->signal); + + return CHANNEL_RC_OK; +} + +static UINT32 FREERDP_CC MyVirtualChannelEventPush(UINT32 openHandle, RDP_EVENT* event) +{ + int index; + rdpChannels* channels; + struct channel_data* lchannel_data; + + channels = freerdp_channels_find_by_open_handle(openHandle, &index); + + if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) + { + DEBUG_CHANNELS("error bad channels handle"); + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + } + + if (!channels->is_connected) + { + DEBUG_CHANNELS("error not connected"); + return CHANNEL_RC_NOT_CONNECTED; + } + + if (event == NULL) + { + DEBUG_CHANNELS("error bad event"); + return CHANNEL_RC_NULL_DATA; + } + + lchannel_data = channels->channels_data + index; + + if (lchannel_data->flags != 2) + { + DEBUG_CHANNELS("error not open"); + return CHANNEL_RC_NOT_OPEN; + } + + /* lock channels->event */ + WaitForSingleObject(channels->event_sem, INFINITE); + + if (!channels->is_connected) + { + ReleaseSemaphore(channels->event_sem, 1, NULL); + DEBUG_CHANNELS("error not connected"); + return CHANNEL_RC_NOT_CONNECTED; + } + + channels->event = event; + /* set the event */ + wait_obj_set(channels->signal); + + return CHANNEL_RC_OK; +} + +/** + * this is called shortly after the application starts and + * before any other function in the file + * called only from main thread + */ +int freerdp_channels_global_init(void) +{ + g_init_channels = NULL; + g_channels_list = NULL; + g_open_handle_sequence = 1; + g_mutex_init = CreateMutex(NULL, FALSE, NULL); + g_mutex_list = CreateMutex(NULL, FALSE, NULL); + + return 0; +} + +int freerdp_channels_global_uninit(void) +{ + while (g_channels_list) + freerdp_channels_free(g_channels_list->channels); + + CloseHandle(g_mutex_init); + CloseHandle(g_mutex_list); + + return 0; +} + +rdpChannels* freerdp_channels_new(void) +{ + rdpChannels* channels; + rdpChannelsList* channels_list; + + channels = xnew(rdpChannels); + + channels->pSyncDataList = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT); + InitializeSListHead(channels->pSyncDataList); + + channels->event_sem = CreateSemaphore(NULL, 1, 16, NULL); + channels->signal = wait_obj_new(); + + /* Add it to the global list */ + channels_list = xnew(rdpChannelsList); + channels_list->channels = channels; + + WaitForSingleObject(g_mutex_list, INFINITE); + channels_list->next = g_channels_list; + g_channels_list = channels_list; + ReleaseMutex(g_mutex_list); + + return channels; +} + +void freerdp_channels_free(rdpChannels* channels) +{ + rdpChannelsList* list; + rdpChannelsList* prev; + + InterlockedFlushSList(channels->pSyncDataList); + _aligned_free(channels->pSyncDataList); + + CloseHandle(channels->event_sem); + wait_obj_free(channels->signal); + + /* Remove from global list */ + + WaitForSingleObject(g_mutex_list, INFINITE); + + for (prev = NULL, list = g_channels_list; list; prev = list, list = list->next) + { + if (list->channels == channels) + break; + } + + if (list) + { + if (prev) + prev->next = list->next; + else + g_channels_list = list->next; + free(list); + } + + ReleaseMutex(g_mutex_list); + + free(channels); +} + +int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings, void* entry, void* data) +{ + int status; + struct lib_data* lib; + CHANNEL_ENTRY_POINTS_EX ep; + + if (channels->num_libs_data + 1 >= CHANNEL_MAX_COUNT) + { + DEBUG_CHANNELS("too many channels"); + return 1; + } + + lib = channels->libs_data + channels->num_libs_data; + lib->entry = (PVIRTUALCHANNELENTRY) entry; + + ep.cbSize = sizeof(ep); + ep.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000; + ep.pVirtualChannelInit = MyVirtualChannelInit; + ep.pVirtualChannelOpen = MyVirtualChannelOpen; + ep.pVirtualChannelClose = MyVirtualChannelClose; + ep.pVirtualChannelWrite = MyVirtualChannelWrite; + ep.pExtendedData = data; + ep.pVirtualChannelEventPush = MyVirtualChannelEventPush; + + /* enable MyVirtualChannelInit */ + channels->can_call_init = 1; + channels->settings = settings; + + WaitForSingleObject(g_mutex_init, INFINITE); + + g_init_channels = channels; + status = lib->entry((PCHANNEL_ENTRY_POINTS) &ep); + g_init_channels = NULL; + + ReleaseMutex(g_mutex_init); + + /* disable MyVirtualChannelInit */ + channels->settings = 0; + channels->can_call_init = 0; + + if (!status) + { + DEBUG_CHANNELS("export function call failed"); + return 1; + } + + return 0; +} + +/** + * this is called when processing the command line parameters + * called only from main thread + */ +int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, const char* name, void* data) +{ + void* entry; + + DEBUG_CHANNELS("%s", name); + + entry = (PVIRTUALCHANNELENTRY) freerdp_load_plugin(name, CHANNEL_EXPORT_FUNC_NAME); + + if (entry == NULL) + { + DEBUG_CHANNELS("failed to find export function"); + return 1; + } + + return freerdp_channels_client_load(channels, settings, entry, data); +} + +/** + * go through and inform all the libraries that we are initialized + * called only from main thread + */ +int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) +{ + int index; + void* dummy; + struct lib_data* llib; + CHANNEL_DEF lchannel_def; + + DEBUG_CHANNELS("enter"); + channels->instance = instance; + + /** + * If rdpsnd is registered but not rdpdr, it's necessary to register a fake + * rdpdr channel to make sound work. This is a workaround for Window 7 and + * Windows 2008 + */ + if (freerdp_channels_find_channel_data_by_name(channels, "rdpsnd", 0) != 0 && + freerdp_channels_find_channel_data_by_name(channels, "rdpdr", 0) == 0) + { + lchannel_def.options = CHANNEL_OPTION_INITIALIZED | + CHANNEL_OPTION_ENCRYPT_RDP; + strcpy(lchannel_def.name, "rdpdr"); + channels->can_call_init = 1; + channels->settings = instance->settings; + WaitForSingleObject(g_mutex_init, INFINITE); + g_init_channels = channels; + MyVirtualChannelInit(&dummy, &lchannel_def, 1, + VIRTUAL_CHANNEL_VERSION_WIN2000, 0); + g_init_channels = NULL; + ReleaseMutex(g_mutex_init); + channels->can_call_init = 0; + channels->settings = 0; + DEBUG_CHANNELS("registered fake rdpdr for rdpsnd."); + } + + for (index = 0; index < channels->num_libs_data; index++) + { + llib = channels->libs_data + index; + + if (llib->init_event_proc != 0) + llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_INITIALIZED, 0, 0); + } + + return 0; +} + +/** + * go through and inform all the libraries that we are connected + * this will tell the libraries that its ok to call MyVirtualChannelOpen + * called only from main thread + */ +int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) +{ + int index; + char* hostname; + int hostname_len; + struct lib_data* llib; + + channels->is_connected = 1; + hostname = instance->settings->hostname; + hostname_len = strlen(hostname); + + DEBUG_CHANNELS("hostname [%s] channels->num_libs [%d]", hostname, channels->num_libs_data); + + for (index = 0; index < channels->num_libs_data; index++) + { + llib = channels->libs_data + index; + + if (llib->init_event_proc != 0) + llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_CONNECTED, hostname, hostname_len); + } + + return 0; +} + +/** + * data comming from the server to the client + * called only from main thread + */ +int freerdp_channels_data(freerdp* instance, int channel_id, void* data, int data_size, int flags, int total_size) +{ + int index; + rdpChannels* channels; + rdpChannel* lrdp_channel; + struct channel_data* lchannel_data; + + channels = freerdp_channels_find_by_instance(instance); + + if (channels == 0) + { + DEBUG_CHANNELS("could not find channel manager"); + return 1; + } + + lrdp_channel = freerdp_channels_find_channel_by_id(channels, instance->settings, + channel_id, &index); + if (lrdp_channel == 0) + { + DEBUG_CHANNELS("could not find channel id"); + return 1; + } + + lchannel_data = freerdp_channels_find_channel_data_by_name(channels, lrdp_channel->name, &index); + + if (lchannel_data == 0) + { + DEBUG_CHANNELS("could not find channel name"); + return 1; + } + + if (lchannel_data->open_event_proc != 0) + { + lchannel_data->open_event_proc(lchannel_data->open_handle, + CHANNEL_EVENT_DATA_RECEIVED, data, data_size, total_size, flags); + } + + return 0; +} + +static const char* event_class_to_name_table[] = +{ + "rdpdbg", /* RDP_EVENT_CLASS_DEBUG */ + "cliprdr", /* RDP_EVENT_CLASS_CLIPRDR */ + "tsmf", /* RDP_EVENT_CLASS_TSMF */ + "rail", /* RDP_EVENT_CLASS_RAIL */ + NULL +}; + +/** + * Send a plugin-defined event to the plugin. + * called only from main thread + * @param channels the channel manager instance + * @param event an event object created by freerdp_event_new() + */ +FREERDP_API int freerdp_channels_send_event(rdpChannels* channels, RDP_EVENT* event) +{ + int index; + const char* name; + struct channel_data* lchannel_data; + + name = event_class_to_name_table[event->event_class]; + + if (name == NULL) + { + DEBUG_CHANNELS("unknown event_class %d", event->event_class); + freerdp_event_free(event); + return 1; + } + + lchannel_data = freerdp_channels_find_channel_data_by_name(channels, name, &index); + + if (lchannel_data == NULL) + { + DEBUG_CHANNELS("could not find channel name %s", name); + freerdp_event_free(event); + return 1; + } + + if (lchannel_data->open_event_proc != NULL) + { + lchannel_data->open_event_proc(lchannel_data->open_handle, + CHANNEL_EVENT_USER, + event, sizeof(RDP_EVENT), sizeof(RDP_EVENT), 0); + } + + return 0; +} + +/** + * called only from main thread + */ +static void freerdp_channels_process_sync(rdpChannels* channels, freerdp* instance) +{ + SYNC_DATA* item; + rdpChannel* lrdp_channel; + struct channel_data* lchannel_data; + + while (QueryDepthSList(channels->pSyncDataList) > 0) + { + item = (SYNC_DATA*) InterlockedPopEntrySList(channels->pSyncDataList); + + if (!item) + break; + + lchannel_data = channels->channels_data + item->Index; + + lrdp_channel = freerdp_channels_find_channel_by_name(channels, instance->settings, + lchannel_data->name, &item->Index); + + if (lrdp_channel != NULL) + instance->SendChannelData(instance, lrdp_channel->channel_id, item->Data, item->DataLength); + + if (lchannel_data->open_event_proc != 0) + { + lchannel_data->open_event_proc(lchannel_data->open_handle, + CHANNEL_EVENT_WRITE_COMPLETE, item->UserData, sizeof(void*), sizeof(void*), 0); + } + + _aligned_free(item); + } +} + +/** + * called only from main thread + */ +BOOL freerdp_channels_get_fds(rdpChannels* channels, freerdp* instance, void** read_fds, + int* read_count, void** write_fds, int* write_count) +{ + wait_obj_get_fds(channels->signal, read_fds, read_count); + return TRUE; +} + +/** + * called only from main thread + */ +BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance) +{ + if (wait_obj_is_set(channels->signal)) + { + wait_obj_clear(channels->signal); + freerdp_channels_process_sync(channels, instance); + } + + return TRUE; +} + +RDP_EVENT* freerdp_channels_pop_event(rdpChannels* channels) +{ + RDP_EVENT* event; + + if (channels->event == NULL) + return NULL; + + event = channels->event; + channels->event = NULL; + + /* release channels->event */ + ReleaseSemaphore(channels->event_sem, 1, NULL); + + return event; +} + +void freerdp_channels_close(rdpChannels* channels, freerdp* instance) +{ + int index; + struct lib_data* llib; + + DEBUG_CHANNELS("closing"); + channels->is_connected = 0; + freerdp_channels_check_fds(channels, instance); + + /* tell all libraries we are shutting down */ + for (index = 0; index < channels->num_libs_data; index++) + { + llib = channels->libs_data + index; + + if (llib->init_event_proc != 0) + llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_TERMINATED, 0, 0); + } +} + diff --git a/channels/server/CMakeLists.txt b/channels/server/CMakeLists.txt index 3c3ddb372..8e6e468ba 100644 --- a/channels/server/CMakeLists.txt +++ b/channels/server/CMakeLists.txt @@ -19,7 +19,8 @@ set(MODULE_NAME "freerdp-channels-server") set(MODULE_PREFIX "FREERDP_CHANNELS_SERVER") set(${MODULE_PREFIX}_SRCS - channels.c) + channels.c + channels.h) foreach(STATIC_MODULE ${CHANNEL_STATIC_SERVER_MODULES}) set(STATIC_MODULE_NAME ${${STATIC_MODULE}_SERVER_NAME}) @@ -32,6 +33,16 @@ add_library(${MODULE_NAME} STATIC ${${MODULE_PREFIX}_SRCS}) set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL + MODULE freerdp + MODULES freerdp-utils) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-crt winpr-synch winpr-interlocked) + target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/channels/server/channels.c b/channels/server/channels.c index af1914c8c..f9c5c4abf 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -2,6 +2,7 @@ * FreeRDP: A Remote Desktop Protocol Implementation * Server Channels * + * Copyright 2011-2012 Vic Lee * Copyright 2012 Marc-Andre Moreau * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,10 +22,790 @@ #include #include +#include +#include #include +#include + +#include "channels.h" + +#define CREATE_REQUEST_PDU 0x01 +#define DATA_FIRST_PDU 0x02 +#define DATA_PDU 0x03 +#define CLOSE_REQUEST_PDU 0x04 +#define CAPABILITY_REQUEST_PDU 0x05 + +typedef struct wts_data_item +{ + UINT16 channel_id; + BYTE* buffer; + UINT32 length; +} wts_data_item; + +static void wts_data_item_free(wts_data_item* item) +{ + free(item->buffer); + free(item); +} + void* freerdp_channels_server_find_static_entry(const char* name, const char* entry) { return NULL; } +static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, UINT32 ChannelId) +{ + LIST_ITEM* item; + rdpPeerChannel* channel = NULL; + + for (item = vcm->dvc_channel_list->head; item; item = item->next) + { + channel = (rdpPeerChannel*) item->data; + + if (channel->channel_id == ChannelId) + break; + } + + return channel; +} + +static void wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* buffer, UINT32 length) +{ + wts_data_item* item; + + item = xnew(wts_data_item); + item->length = length; + item->buffer = malloc(length); + memcpy(item->buffer, buffer, length); + + WaitForSingleObject(channel->mutex, INFINITE); + list_enqueue(channel->receive_queue, item); + ReleaseMutex(channel->mutex); + + wait_obj_set(channel->receive_event); +} + +static void wts_queue_send_item(rdpPeerChannel* channel, wts_data_item* item) +{ + WTSVirtualChannelManager* vcm; + + vcm = channel->vcm; + + item->channel_id = channel->channel_id; + + WaitForSingleObject(vcm->mutex, INFINITE); + list_enqueue(vcm->send_queue, item); + ReleaseMutex(vcm->mutex); + + wait_obj_set(vcm->send_event); +} + +static int wts_read_variable_uint(STREAM* s, int cbLen, UINT32 *val) +{ + switch (cbLen) + { + case 0: + if (stream_get_left(s) < 1) + return 0; + stream_read_BYTE(s, *val); + return 1; + case 1: + if (stream_get_left(s) < 2) + return 0; + stream_read_UINT16(s, *val); + return 2; + default: + if (stream_get_left(s) < 4) + return 0; + stream_read_UINT32(s, *val); + return 4; + } +} + +static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT32 length) +{ + UINT16 Version; + + if (length < 3) + return; + + stream_seek_BYTE(channel->receive_data); /* Pad (1 byte) */ + stream_read_UINT16(channel->receive_data, Version); + + DEBUG_DVC("Version: %d", Version); + + channel->vcm->drdynvc_state = DRDYNVC_STATE_READY; +} + +static void wts_read_drdynvc_create_response(rdpPeerChannel* channel, STREAM* s, UINT32 length) +{ + UINT32 CreationStatus; + + if (length < 4) + return; + + stream_read_UINT32(s, CreationStatus); + + if ((INT32) CreationStatus < 0) + { + DEBUG_DVC("ChannelId %d creation failed (%d)", channel->channel_id, (INT32)CreationStatus); + channel->dvc_open_state = DVC_OPEN_STATE_FAILED; + } + else + { + DEBUG_DVC("ChannelId %d creation succeeded", channel->channel_id); + channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED; + } + wait_obj_set(channel->receive_event); +} + +static void wts_read_drdynvc_data_first(rdpPeerChannel* channel, STREAM* s, int cbLen, UINT32 length) +{ + int value; + + value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length); + + if (value == 0) + return; + + length -= value; + + if (length > channel->dvc_total_length) + return; + + stream_set_pos(channel->receive_data, 0); + stream_check_size(channel->receive_data, (int) channel->dvc_total_length); + stream_write(channel->receive_data, stream_get_tail(s), length); +} + +static void wts_read_drdynvc_data(rdpPeerChannel* channel, STREAM* s, UINT32 length) +{ + if (channel->dvc_total_length > 0) + { + if (stream_get_length(channel->receive_data) + length > channel->dvc_total_length) + { + channel->dvc_total_length = 0; + printf("wts_read_drdynvc_data: incorrect fragment data, discarded.\n"); + return; + } + + stream_write(channel->receive_data, stream_get_tail(s), length); + + if (stream_get_length(channel->receive_data) >= (int) channel->dvc_total_length) + { + wts_queue_receive_data(channel, stream_get_head(channel->receive_data), channel->dvc_total_length); + channel->dvc_total_length = 0; + } + } + else + { + wts_queue_receive_data(channel, stream_get_tail(s), length); + } +} + +static void wts_read_drdynvc_close_response(rdpPeerChannel* channel) +{ + DEBUG_DVC("ChannelId %d close response", channel->channel_id); + channel->dvc_open_state = DVC_OPEN_STATE_CLOSED; +} + +static void wts_read_drdynvc_pdu(rdpPeerChannel* channel) +{ + UINT32 length; + int value; + int Cmd; + int Sp; + int cbChId; + UINT32 ChannelId; + rdpPeerChannel* dvc; + + length = stream_get_pos(channel->receive_data); + + if (length < 1) + return; + + stream_set_pos(channel->receive_data, 0); + stream_read_BYTE(channel->receive_data, value); + + length--; + Cmd = (value & 0xf0) >> 4; + Sp = (value & 0x0c) >> 2; + cbChId = (value & 0x03) >> 0; + + if (Cmd == CAPABILITY_REQUEST_PDU) + { + wts_read_drdynvc_capabilities_response(channel, length); + } + else if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY) + { + value = wts_read_variable_uint(channel->receive_data, cbChId, &ChannelId); + + if (value == 0) + return; + + length -= value; + + DEBUG_DVC("Cmd %d ChannelId %d length %d", Cmd, ChannelId, length); + dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId); + + if (dvc) + { + switch (Cmd) + { + case CREATE_REQUEST_PDU: + wts_read_drdynvc_create_response(dvc, channel->receive_data, length); + break; + + case DATA_FIRST_PDU: + wts_read_drdynvc_data_first(dvc, channel->receive_data, Sp, length); + break; + + case DATA_PDU: + wts_read_drdynvc_data(dvc, channel->receive_data, length); + break; + + case CLOSE_REQUEST_PDU: + wts_read_drdynvc_close_response(dvc); + break; + + default: + printf("wts_read_drdynvc_pdu: Cmd %d not recognized.\n", Cmd); + break; + } + } + else + { + DEBUG_DVC("ChannelId %d not exists.", ChannelId); + } + } + else + { + printf("wts_read_drdynvc_pdu: received Cmd %d but channel is not ready.\n", Cmd); + } +} + +static int wts_write_variable_uint(STREAM* stream, UINT32 val) +{ + int cb; + + if (val <= 0xFF) + { + cb = 0; + stream_write_BYTE(stream, val); + } + else if (val <= 0xFFFF) + { + cb = 1; + stream_write_UINT16(stream, val); + } + else + { + cb = 3; + stream_write_UINT32(stream, val); + } + + return cb; +} + +static void wts_write_drdynvc_header(STREAM *s, BYTE Cmd, UINT32 ChannelId) +{ + BYTE* bm; + int cbChId; + + stream_get_mark(s, bm); + stream_seek_BYTE(s); + cbChId = wts_write_variable_uint(s, ChannelId); + *bm = ((Cmd & 0x0F) << 4) | cbChId; +} + +static void wts_write_drdynvc_create_request(STREAM *s, UINT32 ChannelId, const char *ChannelName) +{ + UINT32 len; + + wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId); + len = strlen(ChannelName) + 1; + stream_check_size(s, (int) len); + stream_write(s, ChannelName, len); +} + +static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, BYTE* data, int size, int flags, int total_size) +{ + 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->vcm->drdynvc_channel) + { + wts_read_drdynvc_pdu(channel); + } + else + { + wts_queue_receive_data(channel, stream_get_head(channel->receive_data), stream_get_length(channel->receive_data)); + } + stream_set_pos(channel->receive_data, 0); + } +} + +static int WTSReceiveChannelData(freerdp_peer* client, int channelId, BYTE* data, int size, int flags, int total_size) +{ + int i; + BOOL 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; + + vcm = xnew(WTSVirtualChannelManager); + + if (vcm != NULL) + { + vcm->client = client; + vcm->send_event = wait_obj_new(); + vcm->send_queue = list_new(); + vcm->mutex = CreateMutex(NULL, FALSE, NULL); + vcm->dvc_channel_id_seq = 1; + vcm->dvc_channel_list = list_new(); + + client->ReceiveChannelData = WTSReceiveChannelData; + } + + return vcm; +} + +void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm) +{ + wts_data_item* item; + rdpPeerChannel* channel; + + if (vcm != NULL) + { + while ((channel = (rdpPeerChannel*) list_dequeue(vcm->dvc_channel_list)) != NULL) + { + WTSVirtualChannelClose(channel); + } + + list_free(vcm->dvc_channel_list); + + if (vcm->drdynvc_channel != NULL) + { + 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); + CloseHandle(vcm->mutex); + free(vcm); + } +} + +void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, + void** fds, int* fds_count) +{ + wait_obj_get_fds(vcm->send_event, fds, fds_count); + + if (vcm->drdynvc_channel) + { + wait_obj_get_fds(vcm->drdynvc_channel->receive_event, fds, fds_count); + } +} + +BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm) +{ + BOOL result = TRUE; + wts_data_item* item; + rdpPeerChannel* channel; + UINT32 dynvc_caps; + + if (vcm->drdynvc_state == DRDYNVC_STATE_NONE && vcm->client->activated) + { + /* Initialize drdynvc channel once and only once. */ + vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED; + + channel = WTSVirtualChannelOpenEx(vcm, "drdynvc", 0); + + if (channel) + { + vcm->drdynvc_channel = channel; + dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */ + WTSVirtualChannelWrite(channel, (BYTE*) &dynvc_caps, sizeof(dynvc_caps), NULL); + } + } + + wait_obj_clear(vcm->send_event); + + WaitForSingleObject(vcm->mutex, INFINITE); + + 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; + } + + wts_data_item_free(item); + + if (result == FALSE) + break; + } + + ReleaseMutex(vcm->mutex); + + return result; +} + +void* WTSVirtualChannelOpenEx( + /* __in */ WTSVirtualChannelManager* vcm, + /* __in */ const char* pVirtualName, + /* __in */ UINT32 flags) +{ + int i; + int len; + STREAM* s; + rdpPeerChannel* channel; + freerdp_peer* client = vcm->client; + + if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) + { + if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY) + { + DEBUG_DVC("Dynamic virtual channel not ready."); + return NULL; + } + + channel = xnew(rdpPeerChannel); + channel->vcm = vcm; + channel->client = client; + channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; + channel->receive_data = stream_new(client->settings->vc_chunk_size); + channel->receive_event = wait_obj_new(); + channel->receive_queue = list_new(); + channel->mutex = CreateMutex(NULL, FALSE, NULL); + + WaitForSingleObject(vcm->mutex, INFINITE); + channel->channel_id = vcm->dvc_channel_id_seq++; + list_enqueue(vcm->dvc_channel_list, channel); + ReleaseMutex(vcm->mutex); + + s = stream_new(64); + wts_write_drdynvc_create_request(s, channel->channel_id, pVirtualName); + WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL); + stream_free(s); + + DEBUG_DVC("ChannelId %d.%s (total %d)", channel->channel_id, pVirtualName, list_size(vcm->dvc_channel_list)); + } + else + { + len = strlen(pVirtualName); + + 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, pVirtualName, len) == 0) + { + break; + } + } + + if (i >= client->settings->num_channels) + return NULL; + + channel = (rdpPeerChannel*) client->settings->channels[i].handle; + + if (channel == NULL) + { + channel = xnew(rdpPeerChannel); + channel->vcm = vcm; + channel->client = client; + channel->channel_id = client->settings->channels[i].channel_id; + channel->index = i; + channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; + channel->receive_data = stream_new(client->settings->vc_chunk_size); + channel->receive_event = wait_obj_new(); + channel->receive_queue = list_new(); + channel->mutex = CreateMutex(NULL, FALSE, NULL); + + client->settings->channels[i].handle = channel; + } + } + + return channel; +} + +BOOL WTSVirtualChannelQuery( + /* __in */ void* hChannelHandle, + /* __in */ WTS_VIRTUAL_CLASS WtsVirtualClass, + /* __out */ void** ppBuffer, + /* __out */ UINT32* pBytesReturned) +{ + BOOL bval; + void* fds[10]; + int fds_count = 0; + BOOL result = FALSE; + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + + switch (WtsVirtualClass) + { + case WTSVirtualFileHandle: + wait_obj_get_fds(channel->receive_event, fds, &fds_count); + *ppBuffer = malloc(sizeof(void*)); + memcpy(*ppBuffer, &fds[0], sizeof(void*)); + *pBytesReturned = sizeof(void*); + result = TRUE; + break; + + case WTSVirtualChannelReady: + if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) + { + bval = TRUE; + result = TRUE; + } + else + { + switch (channel->dvc_open_state) + { + case DVC_OPEN_STATE_NONE: + bval = FALSE; + result = TRUE; + break; + case DVC_OPEN_STATE_SUCCEEDED: + bval = TRUE; + result = TRUE; + break; + default: + bval = FALSE; + result = FALSE; + break; + } + } + *ppBuffer = malloc(sizeof(BOOL)); + memcpy(*ppBuffer, &bval, sizeof(BOOL)); + *pBytesReturned = sizeof(BOOL); + break; + + default: + break; + } + return result; +} + +void WTSFreeMemory( + /* __in */ void* pMemory) +{ + free(pMemory); +} + +BOOL WTSVirtualChannelRead( + /* __in */ void* hChannelHandle, + /* __in */ UINT32 TimeOut, + /* __out */ BYTE* Buffer, + /* __in */ UINT32 BufferSize, + /* __out */ UINT32* pBytesRead) +{ + 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) */ + WaitForSingleObject(channel->mutex, INFINITE); + list_dequeue(channel->receive_queue); + + if (list_size(channel->receive_queue) == 0) + wait_obj_clear(channel->receive_event); + + ReleaseMutex(channel->mutex); + + memcpy(Buffer, item->buffer, item->length); + wts_data_item_free(item) ; + + return TRUE; +} + +BOOL WTSVirtualChannelWrite( + /* __in */ void* hChannelHandle, + /* __in */ BYTE* Buffer, + /* __in */ UINT32 Length, + /* __out */ UINT32* pBytesWritten) +{ + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + wts_data_item* item; + STREAM* s; + int cbLen; + int cbChId; + int first; + UINT32 written; + + if (channel == NULL) + return FALSE; + + if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) + { + item = xnew(wts_data_item); + item->buffer = malloc(Length); + item->length = Length; + memcpy(item->buffer, Buffer, Length); + + wts_queue_send_item(channel, item); + } + else if (channel->vcm->drdynvc_channel == NULL || channel->vcm->drdynvc_state != DRDYNVC_STATE_READY) + { + DEBUG_DVC("drdynvc not ready"); + return FALSE; + } + else + { + s = stream_new(0); + first = TRUE; + + while (Length > 0) + { + item = xnew(wts_data_item); + item->buffer = malloc(channel->client->settings->vc_chunk_size); + stream_attach(s, item->buffer, channel->client->settings->vc_chunk_size); + + stream_seek_BYTE(s); + cbChId = wts_write_variable_uint(s, channel->channel_id); + + if (first && (Length > (UINT32) stream_get_left(s))) + { + cbLen = wts_write_variable_uint(s, Length); + item->buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId; + } + else + { + item->buffer[0] = (DATA_PDU << 4) | cbChId; + } + + first = FALSE; + written = stream_get_left(s); + + if (written > Length) + written = Length; + + stream_write(s, Buffer, written); + item->length = stream_get_length(s); + stream_detach(s); + Length -= written; + Buffer += written; + + wts_queue_send_item(channel->vcm->drdynvc_channel, item); + } + + stream_free(s); + } + + if (pBytesWritten != NULL) + *pBytesWritten = Length; + return TRUE; +} + +BOOL WTSVirtualChannelClose( + /* __in */ void* hChannelHandle) +{ + STREAM* s; + wts_data_item* item; + WTSVirtualChannelManager* vcm; + rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; + + if (channel) + { + vcm = channel->vcm; + + if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) + { + if (channel->index < channel->client->settings->num_channels) + channel->client->settings->channels[channel->index].handle = NULL; + } + else + { + WaitForSingleObject(vcm->mutex, INFINITE); + list_remove(vcm->dvc_channel_list, channel); + ReleaseMutex(vcm->mutex); + + if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED) + { + s = stream_new(8); + wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channel_id); + WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL); + stream_free(s); + } + } + + if (channel->receive_data) + 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) + CloseHandle(channel->mutex); + + free(channel); + } + + return TRUE; +} + diff --git a/libfreerdp/channels/wtsvc.h b/channels/server/channels.h similarity index 95% rename from libfreerdp/channels/wtsvc.h rename to channels/server/channels.h index b452a6ee8..213ddc101 100644 --- a/libfreerdp/channels/wtsvc.h +++ b/channels/server/channels.h @@ -1,8 +1,9 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Server Virtual Channel Interface + * Server Channels * * Copyright 2011-2012 Vic Lee + * 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. diff --git a/client/DirectFB/CMakeLists.txt b/client/DirectFB/CMakeLists.txt index ab3c15513..bd3637de4 100644 --- a/client/DirectFB/CMakeLists.txt +++ b/client/DirectFB/CMakeLists.txt @@ -36,7 +36,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-codec freerdp-channels freerdp-utils) + MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-codec freerdp-utils) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index c14c063d4..b14daef48 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -136,12 +136,10 @@ endif() target_link_libraries(MacFreeRDP ${EXTRA_LIBS} freerdp-core - freerdp-channels freerdp-cache freerdp-gdi freerdp-utils freerdp-codec - freerdp-rail -) + freerdp-rail) set_property(TARGET MacFreeRDP PROPERTY FOLDER "Client/Mac") diff --git a/client/Sample/CMakeLists.txt b/client/Sample/CMakeLists.txt index cc97423a4..903a77688 100644 --- a/client/Sample/CMakeLists.txt +++ b/client/Sample/CMakeLists.txt @@ -28,7 +28,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMAKE_DL_LIBS}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-channels freerdp-utils) + MODULES freerdp-core freerdp-gdi freerdp-utils) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 3b9f315ae..33fa5da37 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -41,7 +41,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-codec freerdp-channels freerdp-utils) + MODULES freerdp-core freerdp-gdi freerdp-codec freerdp-utils) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index c7fced8da..0ef0b6a50 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -98,7 +98,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-rail freerdp-channels freerdp-utils) + MODULES freerdp-core freerdp-gdi freerdp-locale freerdp-rail freerdp-utils) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index 8e2fc144e..ca351c5fc 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -68,7 +68,6 @@ target_link_libraries(test_freerdp ${CUNIT_LIBRARIES}) target_link_libraries(test_freerdp freerdp-core) target_link_libraries(test_freerdp freerdp-gdi) target_link_libraries(test_freerdp freerdp-utils) -target_link_libraries(test_freerdp freerdp-channels) target_link_libraries(test_freerdp freerdp-codec) target_link_libraries(test_freerdp freerdp-crypto) diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index c6ddfc2e6..f73d66307 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -29,7 +29,6 @@ set(${MODULE_PREFIX}_SUBMODULES cache codec crypto - channels locale core) diff --git a/libfreerdp/channels/CMakeLists.txt b/libfreerdp/channels/CMakeLists.txt deleted file mode 100644 index 6c8b18348..000000000 --- a/libfreerdp/channels/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# libfreerdp-channels 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. - -set(MODULE_NAME "freerdp-channels") -set(MODULE_PREFIX "FREERDP_CHANNELS") - -set(${MODULE_PREFIX}_SRCS - libchannels.c - libchannels.h - wtsvc.c - wtsvc.h) - -add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" - MONOLITHIC ${MONOLITHIC_BUILD} - SOURCES ${${MODULE_PREFIX}_SRCS}) - -set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL - MODULE freerdp - MODULES freerdp-utils) - -set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS - MONOLITHIC ${MONOLITHIC_BUILD} - MODULE winpr - MODULES winpr-crt winpr-synch winpr-interlocked) - -if(MONOLITHIC_BUILD) - set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) -else() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) -endif() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") diff --git a/libfreerdp/channels/libchannels.c b/libfreerdp/channels/libchannels.c deleted file mode 100644 index a0bf51ccc..000000000 --- a/libfreerdp/channels/libchannels.c +++ /dev/null @@ -1,1006 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Virtual Channel Manager - * - * Copyright 2009-2011 Jay Sorg - * Copyright 2010-2011 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. - */ - -/** - * MS compatible plugin interface - * reference: - * http://msdn.microsoft.com/en-us/library/aa383580.aspx - * - * Notes on threads: - * Many virtual channel plugins are built using threads. - * Non main threads may call MyVirtualChannelOpen, - * MyVirtualChannelClose, or MyVirtualChannelWrite. - * Since the plugin's VirtualChannelEntry function is called - * from the main thread, MyVirtualChannelInit has to be called - * from the main thread. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "libchannels.h" - -#define CHANNEL_MAX_COUNT 30 - -struct lib_data -{ - PVIRTUALCHANNELENTRY entry; /* the one and only exported function */ - PCHANNEL_INIT_EVENT_FN init_event_proc; - void* init_handle; -}; - -struct channel_data -{ - char name[CHANNEL_NAME_LEN + 1]; - int open_handle; - int options; - int flags; /* 0 nothing 1 init 2 open */ - PCHANNEL_OPEN_EVENT_FN open_event_proc; -}; - -struct _SYNC_DATA -{ - SLIST_ENTRY ItemEntry; - void* Data; - UINT32 DataLength; - void* UserData; - int Index; -}; -typedef struct _SYNC_DATA SYNC_DATA; - -typedef struct rdp_init_handle rdpInitHandle; - -struct rdp_init_handle -{ - rdpChannels* channels; -}; - -struct rdp_channels -{ - /** - * Only the main thread alters these arrays, before any - * library thread is allowed in(post_connect is called) - * so no need to use mutex locking - * After post_connect, each library thread can only access it's - * own array items - * ie, no two threads can access index 0, ... - */ - - struct lib_data libs_data[CHANNEL_MAX_COUNT]; - int num_libs_data; - - struct channel_data channels_data[CHANNEL_MAX_COUNT]; - int num_channels_data; - - rdpInitHandle init_handles[CHANNEL_MAX_COUNT]; - int num_init_handles; - - /* control for entry into MyVirtualChannelInit */ - int can_call_init; - rdpSettings* settings; - - /* true once freerdp_chanman_post_connect is called */ - int is_connected; - - /* used for locating the channels for a given instance */ - freerdp* instance; - - /* signal for incoming data or event */ - struct wait_obj* signal; - - /* used for sync write */ - PSLIST_HEADER pSyncDataList; - - /* used for sync event */ - HANDLE event_sem; - RDP_EVENT* event; -}; - -/** - * The current channel manager reference passes from VirtualChannelEntry to - * VirtualChannelInit for the pInitHandle. - */ -static rdpChannels* g_init_channels; - -/* The list of all channel managers. */ -typedef struct rdp_channels_list rdpChannelsList; - -struct rdp_channels_list -{ - rdpChannels* channels; - rdpChannelsList* next; -}; - -static rdpChannelsList* g_channels_list; - -/* To generate unique sequence for all open handles */ -static int g_open_handle_sequence; - -/* For locking the global resources */ -static HANDLE g_mutex_init; -static HANDLE g_mutex_list; - -/* returns the channels for the open handle passed in */ -static rdpChannels* freerdp_channels_find_by_open_handle(int open_handle, int* pindex) -{ - int lindex; - rdpChannels* channels; - rdpChannelsList* channels_list; - - WaitForSingleObject(g_mutex_list, INFINITE); - - for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next) - { - channels = channels_list->channels; - - for (lindex = 0; lindex < channels->num_channels_data; lindex++) - { - if (channels->channels_data[lindex].open_handle == open_handle) - { - ReleaseMutex(g_mutex_list); - *pindex = lindex; - return channels; - } - } - } - - ReleaseMutex(g_mutex_list); - - return NULL; -} - -/* returns the channels for the rdp instance passed in */ -static rdpChannels* freerdp_channels_find_by_instance(freerdp* instance) -{ - rdpChannels* channels; - rdpChannelsList* channels_list; - - WaitForSingleObject(g_mutex_list, INFINITE); - - for (channels_list = g_channels_list; channels_list; channels_list = channels_list->next) - { - channels = channels_list->channels; - if (channels->instance == instance) - { - ReleaseMutex(g_mutex_list); - return channels; - } - } - - ReleaseMutex(g_mutex_list); - - return NULL; -} - -/* returns struct channel_data for the channel name passed in */ -static struct channel_data* freerdp_channels_find_channel_data_by_name(rdpChannels* channels, const char* channel_name, int* pindex) -{ - int lindex; - struct channel_data* lchannel_data; - - for (lindex = 0; lindex < channels->num_channels_data; lindex++) - { - lchannel_data = channels->channels_data + lindex; - - if (strcmp(channel_name, lchannel_data->name) == 0) - { - if (pindex != 0) - *pindex = lindex; - - return lchannel_data; - } - } - - return NULL; -} - -/* returns rdpChannel for the channel id passed in */ -static rdpChannel* freerdp_channels_find_channel_by_id(rdpChannels* channels, rdpSettings* settings, int channel_id, int* pindex) -{ - int lindex; - int lcount; - rdpChannel* lrdp_channel; - - lcount = settings->num_channels; - - for (lindex = 0; lindex < lcount; lindex++) - { - lrdp_channel = settings->channels + lindex; - - if (lrdp_channel->channel_id == channel_id) - { - if (pindex != 0) - *pindex = lindex; - - return lrdp_channel; - } - } - - return NULL; -} - -/* returns rdpChannel for the channel name passed in */ -static rdpChannel* freerdp_channels_find_channel_by_name(rdpChannels* channels, - rdpSettings* settings, const char* channel_name, int* pindex) -{ - int lindex; - int lcount; - rdpChannel* lrdp_channel; - - lcount = settings->num_channels; - - for (lindex = 0; lindex < lcount; lindex++) - { - lrdp_channel = settings->channels + lindex; - - if (strcmp(channel_name, lrdp_channel->name) == 0) - { - if (pindex != 0) - *pindex = lindex; - - return lrdp_channel; - } - } - - return NULL; -} - -/** - * must be called by same thread that calls freerdp_chanman_load_plugin - * according to MS docs - * only called from main thread - */ -static UINT32 FREERDP_CC MyVirtualChannelInit(void** ppInitHandle, PCHANNEL_DEF pChannel, - int channelCount, UINT32 versionRequested, PCHANNEL_INIT_EVENT_FN pChannelInitEventProc) -{ - int index; - rdpChannels* channels; - struct lib_data* llib; - rdpChannel* lrdp_channel; - PCHANNEL_DEF lchannel_def; - struct channel_data* lchannel_data; - - if (ppInitHandle == NULL) - { - DEBUG_CHANNELS("error bad init handle"); - return CHANNEL_RC_BAD_INIT_HANDLE; - } - - channels = g_init_channels; - channels->init_handles[channels->num_init_handles].channels = channels; - *ppInitHandle = &channels->init_handles[channels->num_init_handles]; - channels->num_init_handles++; - - DEBUG_CHANNELS("enter"); - - if (!channels->can_call_init) - { - DEBUG_CHANNELS("error not in entry"); - return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY; - } - - if (channels->num_channels_data + channelCount >= CHANNEL_MAX_COUNT) - { - DEBUG_CHANNELS("error too many channels"); - return CHANNEL_RC_TOO_MANY_CHANNELS; - } - - if (pChannel == 0) - { - DEBUG_CHANNELS("error bad channel"); - return CHANNEL_RC_BAD_CHANNEL; - } - - if (channels->is_connected) - { - DEBUG_CHANNELS("error already connected"); - return CHANNEL_RC_ALREADY_CONNECTED; - } - - if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000) - { - DEBUG_CHANNELS("warning version"); - } - - for (index = 0; index < channelCount; index++) - { - lchannel_def = pChannel + index; - - if (freerdp_channels_find_channel_data_by_name(channels, lchannel_def->name, 0) != 0) - { - DEBUG_CHANNELS("error channel already used"); - return CHANNEL_RC_BAD_CHANNEL; - } - } - - llib = channels->libs_data + channels->num_libs_data; - llib->init_event_proc = pChannelInitEventProc; - llib->init_handle = *ppInitHandle; - channels->num_libs_data++; - - for (index = 0; index < channelCount; index++) - { - lchannel_def = pChannel + index; - lchannel_data = channels->channels_data + channels->num_channels_data; - - WaitForSingleObject(g_mutex_list, INFINITE); - lchannel_data->open_handle = g_open_handle_sequence++; - ReleaseMutex(g_mutex_list); - - lchannel_data->flags = 1; /* init */ - strncpy(lchannel_data->name, lchannel_def->name, CHANNEL_NAME_LEN); - lchannel_data->options = lchannel_def->options; - - if (channels->settings->num_channels < 16) - { - lrdp_channel = channels->settings->channels + channels->settings->num_channels; - strncpy(lrdp_channel->name, lchannel_def->name, 7); - lrdp_channel->options = lchannel_def->options; - channels->settings->num_channels++; - } - else - { - DEBUG_CHANNELS("warning more than 16 channels"); - } - - channels->num_channels_data++; - } - - return CHANNEL_RC_OK; -} - -/** - * can be called from any thread - * thread safe because no 2 threads can have the same channel name registered - */ -static UINT32 FREERDP_CC MyVirtualChannelOpen(void* pInitHandle, UINT32* pOpenHandle, - char* pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc) -{ - int index; - rdpChannels* channels; - struct channel_data* lchannel_data; - - DEBUG_CHANNELS("enter"); - - channels = ((rdpInitHandle*) pInitHandle)->channels; - - if (pOpenHandle == 0) - { - DEBUG_CHANNELS("error bad channel handle"); - return CHANNEL_RC_BAD_CHANNEL_HANDLE; - } - - if (pChannelOpenEventProc == 0) - { - DEBUG_CHANNELS("error bad proc"); - return CHANNEL_RC_BAD_PROC; - } - - if (!channels->is_connected) - { - DEBUG_CHANNELS("error not connected"); - return CHANNEL_RC_NOT_CONNECTED; - } - - lchannel_data = freerdp_channels_find_channel_data_by_name(channels, pChannelName, &index); - - if (lchannel_data == 0) - { - DEBUG_CHANNELS("error channel name"); - return CHANNEL_RC_UNKNOWN_CHANNEL_NAME; - } - - if (lchannel_data->flags == 2) - { - DEBUG_CHANNELS("error channel already open"); - return CHANNEL_RC_ALREADY_OPEN; - } - - lchannel_data->flags = 2; /* open */ - lchannel_data->open_event_proc = pChannelOpenEventProc; - *pOpenHandle = lchannel_data->open_handle; - - return CHANNEL_RC_OK; -} - -/** - * can be called from any thread - * thread safe because no 2 threads can have the same openHandle - */ -static UINT32 FREERDP_CC MyVirtualChannelClose(UINT32 openHandle) -{ - int index; - rdpChannels* channels; - struct channel_data* lchannel_data; - - DEBUG_CHANNELS("enter"); - - channels = freerdp_channels_find_by_open_handle(openHandle, &index); - - if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) - { - DEBUG_CHANNELS("error bad channels"); - return CHANNEL_RC_BAD_CHANNEL_HANDLE; - } - - lchannel_data = channels->channels_data + index; - - if (lchannel_data->flags != 2) - { - DEBUG_CHANNELS("error not open"); - return CHANNEL_RC_NOT_OPEN; - } - - lchannel_data->flags = 0; - - return CHANNEL_RC_OK; -} - -/* can be called from any thread */ -static UINT32 FREERDP_CC MyVirtualChannelWrite(UINT32 openHandle, void* pData, UINT32 dataLength, void* pUserData) -{ - int index; - SYNC_DATA* item; - rdpChannels* channels; - struct channel_data* lchannel_data; - - channels = freerdp_channels_find_by_open_handle(openHandle, &index); - - if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) - { - DEBUG_CHANNELS("error bad channel handle"); - return CHANNEL_RC_BAD_CHANNEL_HANDLE; - } - - if (!channels->is_connected) - { - DEBUG_CHANNELS("error not connected"); - return CHANNEL_RC_NOT_CONNECTED; - } - - if (pData == 0) - { - DEBUG_CHANNELS("error bad pData"); - return CHANNEL_RC_NULL_DATA; - } - - if (dataLength == 0) - { - DEBUG_CHANNELS("error bad dataLength"); - return CHANNEL_RC_ZERO_LENGTH; - } - - lchannel_data = channels->channels_data + index; - - if (lchannel_data->flags != 2) - { - DEBUG_CHANNELS("error not open"); - return CHANNEL_RC_NOT_OPEN; - } - - if (!channels->is_connected) - { - DEBUG_CHANNELS("error not connected"); - return CHANNEL_RC_NOT_CONNECTED; - } - - item = (SYNC_DATA*) _aligned_malloc(sizeof(SYNC_DATA), MEMORY_ALLOCATION_ALIGNMENT); - item->Data = pData; - item->DataLength = dataLength; - item->UserData = pUserData; - item->Index = index; - - InterlockedPushEntrySList(channels->pSyncDataList, &(item->ItemEntry)); - - /* set the event */ - wait_obj_set(channels->signal); - - return CHANNEL_RC_OK; -} - -static UINT32 FREERDP_CC MyVirtualChannelEventPush(UINT32 openHandle, RDP_EVENT* event) -{ - int index; - rdpChannels* channels; - struct channel_data* lchannel_data; - - channels = freerdp_channels_find_by_open_handle(openHandle, &index); - - if ((channels == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) - { - DEBUG_CHANNELS("error bad channels handle"); - return CHANNEL_RC_BAD_CHANNEL_HANDLE; - } - - if (!channels->is_connected) - { - DEBUG_CHANNELS("error not connected"); - return CHANNEL_RC_NOT_CONNECTED; - } - - if (event == NULL) - { - DEBUG_CHANNELS("error bad event"); - return CHANNEL_RC_NULL_DATA; - } - - lchannel_data = channels->channels_data + index; - - if (lchannel_data->flags != 2) - { - DEBUG_CHANNELS("error not open"); - return CHANNEL_RC_NOT_OPEN; - } - - /* lock channels->event */ - WaitForSingleObject(channels->event_sem, INFINITE); - - if (!channels->is_connected) - { - ReleaseSemaphore(channels->event_sem, 1, NULL); - DEBUG_CHANNELS("error not connected"); - return CHANNEL_RC_NOT_CONNECTED; - } - - channels->event = event; - /* set the event */ - wait_obj_set(channels->signal); - - return CHANNEL_RC_OK; -} - -/** - * this is called shortly after the application starts and - * before any other function in the file - * called only from main thread - */ -int freerdp_channels_global_init(void) -{ - g_init_channels = NULL; - g_channels_list = NULL; - g_open_handle_sequence = 1; - g_mutex_init = CreateMutex(NULL, FALSE, NULL); - g_mutex_list = CreateMutex(NULL, FALSE, NULL); - - return 0; -} - -int freerdp_channels_global_uninit(void) -{ - while (g_channels_list) - freerdp_channels_free(g_channels_list->channels); - - CloseHandle(g_mutex_init); - CloseHandle(g_mutex_list); - - return 0; -} - -rdpChannels* freerdp_channels_new(void) -{ - rdpChannels* channels; - rdpChannelsList* channels_list; - - channels = xnew(rdpChannels); - - channels->pSyncDataList = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT); - InitializeSListHead(channels->pSyncDataList); - - channels->event_sem = CreateSemaphore(NULL, 1, 16, NULL); - channels->signal = wait_obj_new(); - - /* Add it to the global list */ - channels_list = xnew(rdpChannelsList); - channels_list->channels = channels; - - WaitForSingleObject(g_mutex_list, INFINITE); - channels_list->next = g_channels_list; - g_channels_list = channels_list; - ReleaseMutex(g_mutex_list); - - return channels; -} - -void freerdp_channels_free(rdpChannels* channels) -{ - rdpChannelsList* list; - rdpChannelsList* prev; - - InterlockedFlushSList(channels->pSyncDataList); - _aligned_free(channels->pSyncDataList); - - CloseHandle(channels->event_sem); - wait_obj_free(channels->signal); - - /* Remove from global list */ - - WaitForSingleObject(g_mutex_list, INFINITE); - - for (prev = NULL, list = g_channels_list; list; prev = list, list = list->next) - { - if (list->channels == channels) - break; - } - - if (list) - { - if (prev) - prev->next = list->next; - else - g_channels_list = list->next; - free(list); - } - - ReleaseMutex(g_mutex_list); - - free(channels); -} - -int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings, void* entry, void* data) -{ - int status; - struct lib_data* lib; - CHANNEL_ENTRY_POINTS_EX ep; - - if (channels->num_libs_data + 1 >= CHANNEL_MAX_COUNT) - { - DEBUG_CHANNELS("too many channels"); - return 1; - } - - lib = channels->libs_data + channels->num_libs_data; - lib->entry = (PVIRTUALCHANNELENTRY) entry; - - ep.cbSize = sizeof(ep); - ep.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000; - ep.pVirtualChannelInit = MyVirtualChannelInit; - ep.pVirtualChannelOpen = MyVirtualChannelOpen; - ep.pVirtualChannelClose = MyVirtualChannelClose; - ep.pVirtualChannelWrite = MyVirtualChannelWrite; - ep.pExtendedData = data; - ep.pVirtualChannelEventPush = MyVirtualChannelEventPush; - - /* enable MyVirtualChannelInit */ - channels->can_call_init = 1; - channels->settings = settings; - - WaitForSingleObject(g_mutex_init, INFINITE); - - g_init_channels = channels; - status = lib->entry((PCHANNEL_ENTRY_POINTS) &ep); - g_init_channels = NULL; - - ReleaseMutex(g_mutex_init); - - /* disable MyVirtualChannelInit */ - channels->settings = 0; - channels->can_call_init = 0; - - if (!status) - { - DEBUG_CHANNELS("export function call failed"); - return 1; - } - - return 0; -} - -/** - * this is called when processing the command line parameters - * called only from main thread - */ -int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, const char* name, void* data) -{ - void* entry; - - DEBUG_CHANNELS("%s", name); - - entry = (PVIRTUALCHANNELENTRY) freerdp_load_plugin(name, CHANNEL_EXPORT_FUNC_NAME); - - if (entry == NULL) - { - DEBUG_CHANNELS("failed to find export function"); - return 1; - } - - return freerdp_channels_client_load(channels, settings, entry, data); -} - -/** - * go through and inform all the libraries that we are initialized - * called only from main thread - */ -int freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) -{ - int index; - void* dummy; - struct lib_data* llib; - CHANNEL_DEF lchannel_def; - - DEBUG_CHANNELS("enter"); - channels->instance = instance; - - /** - * If rdpsnd is registered but not rdpdr, it's necessary to register a fake - * rdpdr channel to make sound work. This is a workaround for Window 7 and - * Windows 2008 - */ - if (freerdp_channels_find_channel_data_by_name(channels, "rdpsnd", 0) != 0 && - freerdp_channels_find_channel_data_by_name(channels, "rdpdr", 0) == 0) - { - lchannel_def.options = CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP; - strcpy(lchannel_def.name, "rdpdr"); - channels->can_call_init = 1; - channels->settings = instance->settings; - WaitForSingleObject(g_mutex_init, INFINITE); - g_init_channels = channels; - MyVirtualChannelInit(&dummy, &lchannel_def, 1, - VIRTUAL_CHANNEL_VERSION_WIN2000, 0); - g_init_channels = NULL; - ReleaseMutex(g_mutex_init); - channels->can_call_init = 0; - channels->settings = 0; - DEBUG_CHANNELS("registered fake rdpdr for rdpsnd."); - } - - for (index = 0; index < channels->num_libs_data; index++) - { - llib = channels->libs_data + index; - - if (llib->init_event_proc != 0) - llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_INITIALIZED, 0, 0); - } - - return 0; -} - -/** - * go through and inform all the libraries that we are connected - * this will tell the libraries that its ok to call MyVirtualChannelOpen - * called only from main thread - */ -int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) -{ - int index; - char* hostname; - int hostname_len; - struct lib_data* llib; - - channels->is_connected = 1; - hostname = instance->settings->hostname; - hostname_len = strlen(hostname); - - DEBUG_CHANNELS("hostname [%s] channels->num_libs [%d]", hostname, channels->num_libs_data); - - for (index = 0; index < channels->num_libs_data; index++) - { - llib = channels->libs_data + index; - - if (llib->init_event_proc != 0) - llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_CONNECTED, hostname, hostname_len); - } - - return 0; -} - -/** - * data comming from the server to the client - * called only from main thread - */ -int freerdp_channels_data(freerdp* instance, int channel_id, void* data, int data_size, int flags, int total_size) -{ - int index; - rdpChannels* channels; - rdpChannel* lrdp_channel; - struct channel_data* lchannel_data; - - channels = freerdp_channels_find_by_instance(instance); - - if (channels == 0) - { - DEBUG_CHANNELS("could not find channel manager"); - return 1; - } - - lrdp_channel = freerdp_channels_find_channel_by_id(channels, instance->settings, - channel_id, &index); - if (lrdp_channel == 0) - { - DEBUG_CHANNELS("could not find channel id"); - return 1; - } - - lchannel_data = freerdp_channels_find_channel_data_by_name(channels, lrdp_channel->name, &index); - - if (lchannel_data == 0) - { - DEBUG_CHANNELS("could not find channel name"); - return 1; - } - - if (lchannel_data->open_event_proc != 0) - { - lchannel_data->open_event_proc(lchannel_data->open_handle, - CHANNEL_EVENT_DATA_RECEIVED, data, data_size, total_size, flags); - } - - return 0; -} - -static const char* event_class_to_name_table[] = -{ - "rdpdbg", /* RDP_EVENT_CLASS_DEBUG */ - "cliprdr", /* RDP_EVENT_CLASS_CLIPRDR */ - "tsmf", /* RDP_EVENT_CLASS_TSMF */ - "rail", /* RDP_EVENT_CLASS_RAIL */ - NULL -}; - -/** - * Send a plugin-defined event to the plugin. - * called only from main thread - * @param channels the channel manager instance - * @param event an event object created by freerdp_event_new() - */ -FREERDP_API int freerdp_channels_send_event(rdpChannels* channels, RDP_EVENT* event) -{ - int index; - const char* name; - struct channel_data* lchannel_data; - - name = event_class_to_name_table[event->event_class]; - - if (name == NULL) - { - DEBUG_CHANNELS("unknown event_class %d", event->event_class); - freerdp_event_free(event); - return 1; - } - - lchannel_data = freerdp_channels_find_channel_data_by_name(channels, name, &index); - - if (lchannel_data == NULL) - { - DEBUG_CHANNELS("could not find channel name %s", name); - freerdp_event_free(event); - return 1; - } - - if (lchannel_data->open_event_proc != NULL) - { - lchannel_data->open_event_proc(lchannel_data->open_handle, - CHANNEL_EVENT_USER, - event, sizeof(RDP_EVENT), sizeof(RDP_EVENT), 0); - } - - return 0; -} - -/** - * called only from main thread - */ -static void freerdp_channels_process_sync(rdpChannels* channels, freerdp* instance) -{ - SYNC_DATA* item; - rdpChannel* lrdp_channel; - struct channel_data* lchannel_data; - - while (QueryDepthSList(channels->pSyncDataList) > 0) - { - item = (SYNC_DATA*) InterlockedPopEntrySList(channels->pSyncDataList); - - if (!item) - break; - - lchannel_data = channels->channels_data + item->Index; - - lrdp_channel = freerdp_channels_find_channel_by_name(channels, instance->settings, - lchannel_data->name, &item->Index); - - if (lrdp_channel != NULL) - instance->SendChannelData(instance, lrdp_channel->channel_id, item->Data, item->DataLength); - - if (lchannel_data->open_event_proc != 0) - { - lchannel_data->open_event_proc(lchannel_data->open_handle, - CHANNEL_EVENT_WRITE_COMPLETE, item->UserData, sizeof(void*), sizeof(void*), 0); - } - - _aligned_free(item); - } -} - -/** - * called only from main thread - */ -BOOL freerdp_channels_get_fds(rdpChannels* channels, freerdp* instance, void** read_fds, - int* read_count, void** write_fds, int* write_count) -{ - wait_obj_get_fds(channels->signal, read_fds, read_count); - return TRUE; -} - -/** - * called only from main thread - */ -BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance) -{ - if (wait_obj_is_set(channels->signal)) - { - wait_obj_clear(channels->signal); - freerdp_channels_process_sync(channels, instance); - } - - return TRUE; -} - -RDP_EVENT* freerdp_channels_pop_event(rdpChannels* channels) -{ - RDP_EVENT* event; - - if (channels->event == NULL) - return NULL; - - event = channels->event; - channels->event = NULL; - - /* release channels->event */ - ReleaseSemaphore(channels->event_sem, 1, NULL); - - return event; -} - -void freerdp_channels_close(rdpChannels* channels, freerdp* instance) -{ - int index; - struct lib_data* llib; - - DEBUG_CHANNELS("closing"); - channels->is_connected = 0; - freerdp_channels_check_fds(channels, instance); - - /* tell all libraries we are shutting down */ - for (index = 0; index < channels->num_libs_data; index++) - { - llib = channels->libs_data + index; - - if (llib->init_event_proc != 0) - llib->init_event_proc(llib->init_handle, CHANNEL_EVENT_TERMINATED, 0, 0); - } -} diff --git a/libfreerdp/channels/libchannels.h b/libfreerdp/channels/libchannels.h deleted file mode 100644 index bc0b51804..000000000 --- a/libfreerdp/channels/libchannels.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Virtual Channel Manager - * - * Copyright 2009-2011 Jay Sorg - * Copyright 2010-2011 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 __LIBCHANNELS_H -#define __LIBCHANNELS_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#ifdef WITH_DEBUG_CHANNELS -#define DEBUG_CHANNELS(fmt, ...) DEBUG_CLASS(CHANNELS, fmt, ## __VA_ARGS__) -#else -#define DEBUG_CHANNELS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) -#endif - -#endif /* __LIBCHANNELS_H */ diff --git a/libfreerdp/channels/wtsvc.c b/libfreerdp/channels/wtsvc.c deleted file mode 100644 index 877a7d3fb..000000000 --- a/libfreerdp/channels/wtsvc.c +++ /dev/null @@ -1,807 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include - -#include - -#include "wtsvc.h" - -#define CREATE_REQUEST_PDU 0x01 -#define DATA_FIRST_PDU 0x02 -#define DATA_PDU 0x03 -#define CLOSE_REQUEST_PDU 0x04 -#define CAPABILITY_REQUEST_PDU 0x05 - -typedef struct wts_data_item -{ - UINT16 channel_id; - BYTE* buffer; - UINT32 length; -} wts_data_item; - -static void wts_data_item_free(wts_data_item* item) -{ - free(item->buffer); - free(item); -} - -static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, UINT32 ChannelId) -{ - LIST_ITEM* item; - rdpPeerChannel* channel = NULL; - - for (item = vcm->dvc_channel_list->head; item; item = item->next) - { - channel = (rdpPeerChannel*) item->data; - - if (channel->channel_id == ChannelId) - break; - } - - return channel; -} - -static void wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* buffer, UINT32 length) -{ - wts_data_item* item; - - item = xnew(wts_data_item); - item->length = length; - item->buffer = malloc(length); - memcpy(item->buffer, buffer, length); - - WaitForSingleObject(channel->mutex, INFINITE); - list_enqueue(channel->receive_queue, item); - ReleaseMutex(channel->mutex); - - wait_obj_set(channel->receive_event); -} - -static void wts_queue_send_item(rdpPeerChannel* channel, wts_data_item* item) -{ - WTSVirtualChannelManager* vcm; - - vcm = channel->vcm; - - item->channel_id = channel->channel_id; - - WaitForSingleObject(vcm->mutex, INFINITE); - list_enqueue(vcm->send_queue, item); - ReleaseMutex(vcm->mutex); - - wait_obj_set(vcm->send_event); -} - -static int wts_read_variable_uint(STREAM* s, int cbLen, UINT32 *val) -{ - switch (cbLen) - { - case 0: - if (stream_get_left(s) < 1) - return 0; - stream_read_BYTE(s, *val); - return 1; - case 1: - if (stream_get_left(s) < 2) - return 0; - stream_read_UINT16(s, *val); - return 2; - default: - if (stream_get_left(s) < 4) - return 0; - stream_read_UINT32(s, *val); - return 4; - } -} - -static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT32 length) -{ - UINT16 Version; - - if (length < 3) - return; - - stream_seek_BYTE(channel->receive_data); /* Pad (1 byte) */ - stream_read_UINT16(channel->receive_data, Version); - - DEBUG_DVC("Version: %d", Version); - - channel->vcm->drdynvc_state = DRDYNVC_STATE_READY; -} - -static void wts_read_drdynvc_create_response(rdpPeerChannel* channel, STREAM* s, UINT32 length) -{ - UINT32 CreationStatus; - - if (length < 4) - return; - - stream_read_UINT32(s, CreationStatus); - - if ((INT32) CreationStatus < 0) - { - DEBUG_DVC("ChannelId %d creation failed (%d)", channel->channel_id, (INT32)CreationStatus); - channel->dvc_open_state = DVC_OPEN_STATE_FAILED; - } - else - { - DEBUG_DVC("ChannelId %d creation succeeded", channel->channel_id); - channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED; - } - wait_obj_set(channel->receive_event); -} - -static void wts_read_drdynvc_data_first(rdpPeerChannel* channel, STREAM* s, int cbLen, UINT32 length) -{ - int value; - - value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length); - - if (value == 0) - return; - - length -= value; - - if (length > channel->dvc_total_length) - return; - - stream_set_pos(channel->receive_data, 0); - stream_check_size(channel->receive_data, (int) channel->dvc_total_length); - stream_write(channel->receive_data, stream_get_tail(s), length); -} - -static void wts_read_drdynvc_data(rdpPeerChannel* channel, STREAM* s, UINT32 length) -{ - if (channel->dvc_total_length > 0) - { - if (stream_get_length(channel->receive_data) + length > channel->dvc_total_length) - { - channel->dvc_total_length = 0; - printf("wts_read_drdynvc_data: incorrect fragment data, discarded.\n"); - return; - } - - stream_write(channel->receive_data, stream_get_tail(s), length); - - if (stream_get_length(channel->receive_data) >= (int) channel->dvc_total_length) - { - wts_queue_receive_data(channel, stream_get_head(channel->receive_data), channel->dvc_total_length); - channel->dvc_total_length = 0; - } - } - else - { - wts_queue_receive_data(channel, stream_get_tail(s), length); - } -} - -static void wts_read_drdynvc_close_response(rdpPeerChannel* channel) -{ - DEBUG_DVC("ChannelId %d close response", channel->channel_id); - channel->dvc_open_state = DVC_OPEN_STATE_CLOSED; -} - -static void wts_read_drdynvc_pdu(rdpPeerChannel* channel) -{ - UINT32 length; - int value; - int Cmd; - int Sp; - int cbChId; - UINT32 ChannelId; - rdpPeerChannel* dvc; - - length = stream_get_pos(channel->receive_data); - - if (length < 1) - return; - - stream_set_pos(channel->receive_data, 0); - stream_read_BYTE(channel->receive_data, value); - - length--; - Cmd = (value & 0xf0) >> 4; - Sp = (value & 0x0c) >> 2; - cbChId = (value & 0x03) >> 0; - - if (Cmd == CAPABILITY_REQUEST_PDU) - { - wts_read_drdynvc_capabilities_response(channel, length); - } - else if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY) - { - value = wts_read_variable_uint(channel->receive_data, cbChId, &ChannelId); - - if (value == 0) - return; - - length -= value; - - DEBUG_DVC("Cmd %d ChannelId %d length %d", Cmd, ChannelId, length); - dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId); - - if (dvc) - { - switch (Cmd) - { - case CREATE_REQUEST_PDU: - wts_read_drdynvc_create_response(dvc, channel->receive_data, length); - break; - - case DATA_FIRST_PDU: - wts_read_drdynvc_data_first(dvc, channel->receive_data, Sp, length); - break; - - case DATA_PDU: - wts_read_drdynvc_data(dvc, channel->receive_data, length); - break; - - case CLOSE_REQUEST_PDU: - wts_read_drdynvc_close_response(dvc); - break; - - default: - printf("wts_read_drdynvc_pdu: Cmd %d not recognized.\n", Cmd); - break; - } - } - else - { - DEBUG_DVC("ChannelId %d not exists.", ChannelId); - } - } - else - { - printf("wts_read_drdynvc_pdu: received Cmd %d but channel is not ready.\n", Cmd); - } -} - -static int wts_write_variable_uint(STREAM* stream, UINT32 val) -{ - int cb; - - if (val <= 0xFF) - { - cb = 0; - stream_write_BYTE(stream, val); - } - else if (val <= 0xFFFF) - { - cb = 1; - stream_write_UINT16(stream, val); - } - else - { - cb = 3; - stream_write_UINT32(stream, val); - } - - return cb; -} - -static void wts_write_drdynvc_header(STREAM *s, BYTE Cmd, UINT32 ChannelId) -{ - BYTE* bm; - int cbChId; - - stream_get_mark(s, bm); - stream_seek_BYTE(s); - cbChId = wts_write_variable_uint(s, ChannelId); - *bm = ((Cmd & 0x0F) << 4) | cbChId; -} - -static void wts_write_drdynvc_create_request(STREAM *s, UINT32 ChannelId, const char *ChannelName) -{ - UINT32 len; - - wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId); - len = strlen(ChannelName) + 1; - stream_check_size(s, (int) len); - stream_write(s, ChannelName, len); -} - -static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, BYTE* data, int size, int flags, int total_size) -{ - 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->vcm->drdynvc_channel) - { - wts_read_drdynvc_pdu(channel); - } - else - { - wts_queue_receive_data(channel, stream_get_head(channel->receive_data), stream_get_length(channel->receive_data)); - } - stream_set_pos(channel->receive_data, 0); - } -} - -static int WTSReceiveChannelData(freerdp_peer* client, int channelId, BYTE* data, int size, int flags, int total_size) -{ - int i; - BOOL 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; - - vcm = xnew(WTSVirtualChannelManager); - - if (vcm != NULL) - { - vcm->client = client; - vcm->send_event = wait_obj_new(); - vcm->send_queue = list_new(); - vcm->mutex = CreateMutex(NULL, FALSE, NULL); - vcm->dvc_channel_id_seq = 1; - vcm->dvc_channel_list = list_new(); - - client->ReceiveChannelData = WTSReceiveChannelData; - } - - return vcm; -} - -void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm) -{ - wts_data_item* item; - rdpPeerChannel* channel; - - if (vcm != NULL) - { - while ((channel = (rdpPeerChannel*) list_dequeue(vcm->dvc_channel_list)) != NULL) - { - WTSVirtualChannelClose(channel); - } - - list_free(vcm->dvc_channel_list); - - if (vcm->drdynvc_channel != NULL) - { - 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); - CloseHandle(vcm->mutex); - free(vcm); - } -} - -void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, - void** fds, int* fds_count) -{ - wait_obj_get_fds(vcm->send_event, fds, fds_count); - - if (vcm->drdynvc_channel) - { - wait_obj_get_fds(vcm->drdynvc_channel->receive_event, fds, fds_count); - } -} - -BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm) -{ - BOOL result = TRUE; - wts_data_item* item; - rdpPeerChannel* channel; - UINT32 dynvc_caps; - - if (vcm->drdynvc_state == DRDYNVC_STATE_NONE && vcm->client->activated) - { - /* Initialize drdynvc channel once and only once. */ - vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED; - - channel = WTSVirtualChannelOpenEx(vcm, "drdynvc", 0); - - if (channel) - { - vcm->drdynvc_channel = channel; - dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */ - WTSVirtualChannelWrite(channel, (BYTE*) &dynvc_caps, sizeof(dynvc_caps), NULL); - } - } - - wait_obj_clear(vcm->send_event); - - WaitForSingleObject(vcm->mutex, INFINITE); - - 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; - } - - wts_data_item_free(item); - - if (result == FALSE) - break; - } - - ReleaseMutex(vcm->mutex); - - return result; -} - -void* WTSVirtualChannelOpenEx( - /* __in */ WTSVirtualChannelManager* vcm, - /* __in */ const char* pVirtualName, - /* __in */ UINT32 flags) -{ - int i; - int len; - STREAM* s; - rdpPeerChannel* channel; - freerdp_peer* client = vcm->client; - - if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0) - { - if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY) - { - DEBUG_DVC("Dynamic virtual channel not ready."); - return NULL; - } - - channel = xnew(rdpPeerChannel); - channel->vcm = vcm; - channel->client = client; - channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC; - channel->receive_data = stream_new(client->settings->vc_chunk_size); - channel->receive_event = wait_obj_new(); - channel->receive_queue = list_new(); - channel->mutex = CreateMutex(NULL, FALSE, NULL); - - WaitForSingleObject(vcm->mutex, INFINITE); - channel->channel_id = vcm->dvc_channel_id_seq++; - list_enqueue(vcm->dvc_channel_list, channel); - ReleaseMutex(vcm->mutex); - - s = stream_new(64); - wts_write_drdynvc_create_request(s, channel->channel_id, pVirtualName); - WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL); - stream_free(s); - - DEBUG_DVC("ChannelId %d.%s (total %d)", channel->channel_id, pVirtualName, list_size(vcm->dvc_channel_list)); - } - else - { - len = strlen(pVirtualName); - - 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, pVirtualName, len) == 0) - { - break; - } - } - - if (i >= client->settings->num_channels) - return NULL; - - channel = (rdpPeerChannel*) client->settings->channels[i].handle; - - if (channel == NULL) - { - channel = xnew(rdpPeerChannel); - channel->vcm = vcm; - channel->client = client; - channel->channel_id = client->settings->channels[i].channel_id; - channel->index = i; - channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC; - channel->receive_data = stream_new(client->settings->vc_chunk_size); - channel->receive_event = wait_obj_new(); - channel->receive_queue = list_new(); - channel->mutex = CreateMutex(NULL, FALSE, NULL); - - client->settings->channels[i].handle = channel; - } - } - - return channel; -} - -BOOL WTSVirtualChannelQuery( - /* __in */ void* hChannelHandle, - /* __in */ WTS_VIRTUAL_CLASS WtsVirtualClass, - /* __out */ void** ppBuffer, - /* __out */ UINT32* pBytesReturned) -{ - BOOL bval; - void* fds[10]; - int fds_count = 0; - BOOL result = FALSE; - rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; - - switch (WtsVirtualClass) - { - case WTSVirtualFileHandle: - wait_obj_get_fds(channel->receive_event, fds, &fds_count); - *ppBuffer = malloc(sizeof(void*)); - memcpy(*ppBuffer, &fds[0], sizeof(void*)); - *pBytesReturned = sizeof(void*); - result = TRUE; - break; - - case WTSVirtualChannelReady: - if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) - { - bval = TRUE; - result = TRUE; - } - else - { - switch (channel->dvc_open_state) - { - case DVC_OPEN_STATE_NONE: - bval = FALSE; - result = TRUE; - break; - case DVC_OPEN_STATE_SUCCEEDED: - bval = TRUE; - result = TRUE; - break; - default: - bval = FALSE; - result = FALSE; - break; - } - } - *ppBuffer = malloc(sizeof(BOOL)); - memcpy(*ppBuffer, &bval, sizeof(BOOL)); - *pBytesReturned = sizeof(BOOL); - break; - - default: - break; - } - return result; -} - -void WTSFreeMemory( - /* __in */ void* pMemory) -{ - free(pMemory); -} - -BOOL WTSVirtualChannelRead( - /* __in */ void* hChannelHandle, - /* __in */ UINT32 TimeOut, - /* __out */ BYTE* Buffer, - /* __in */ UINT32 BufferSize, - /* __out */ UINT32* pBytesRead) -{ - 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) */ - WaitForSingleObject(channel->mutex, INFINITE); - list_dequeue(channel->receive_queue); - - if (list_size(channel->receive_queue) == 0) - wait_obj_clear(channel->receive_event); - - ReleaseMutex(channel->mutex); - - memcpy(Buffer, item->buffer, item->length); - wts_data_item_free(item) ; - - return TRUE; -} - -BOOL WTSVirtualChannelWrite( - /* __in */ void* hChannelHandle, - /* __in */ BYTE* Buffer, - /* __in */ UINT32 Length, - /* __out */ UINT32* pBytesWritten) -{ - rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; - wts_data_item* item; - STREAM* s; - int cbLen; - int cbChId; - int first; - UINT32 written; - - if (channel == NULL) - return FALSE; - - if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) - { - item = xnew(wts_data_item); - item->buffer = malloc(Length); - item->length = Length; - memcpy(item->buffer, Buffer, Length); - - wts_queue_send_item(channel, item); - } - else if (channel->vcm->drdynvc_channel == NULL || channel->vcm->drdynvc_state != DRDYNVC_STATE_READY) - { - DEBUG_DVC("drdynvc not ready"); - return FALSE; - } - else - { - s = stream_new(0); - first = TRUE; - - while (Length > 0) - { - item = xnew(wts_data_item); - item->buffer = malloc(channel->client->settings->vc_chunk_size); - stream_attach(s, item->buffer, channel->client->settings->vc_chunk_size); - - stream_seek_BYTE(s); - cbChId = wts_write_variable_uint(s, channel->channel_id); - - if (first && (Length > (UINT32) stream_get_left(s))) - { - cbLen = wts_write_variable_uint(s, Length); - item->buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId; - } - else - { - item->buffer[0] = (DATA_PDU << 4) | cbChId; - } - - first = FALSE; - written = stream_get_left(s); - - if (written > Length) - written = Length; - - stream_write(s, Buffer, written); - item->length = stream_get_length(s); - stream_detach(s); - Length -= written; - Buffer += written; - - wts_queue_send_item(channel->vcm->drdynvc_channel, item); - } - - stream_free(s); - } - - if (pBytesWritten != NULL) - *pBytesWritten = Length; - return TRUE; -} - -BOOL WTSVirtualChannelClose( - /* __in */ void* hChannelHandle) -{ - STREAM* s; - wts_data_item* item; - WTSVirtualChannelManager* vcm; - rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; - - if (channel) - { - vcm = channel->vcm; - - if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC) - { - if (channel->index < channel->client->settings->num_channels) - channel->client->settings->channels[channel->index].handle = NULL; - } - else - { - WaitForSingleObject(vcm->mutex, INFINITE); - list_remove(vcm->dvc_channel_list, channel); - ReleaseMutex(vcm->mutex); - - if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED) - { - s = stream_new(8); - wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channel_id); - WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL); - stream_free(s); - } - } - - if (channel->receive_data) - 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) - CloseHandle(channel->mutex); - - free(channel); - } - - return TRUE; -} diff --git a/server/Sample/CMakeLists.txt b/server/Sample/CMakeLists.txt index 459de5150..e92305876 100644 --- a/server/Sample/CMakeLists.txt +++ b/server/Sample/CMakeLists.txt @@ -33,7 +33,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-core freerdp-utils freerdp-codec freerdp-channels) + MODULES freerdp-core freerdp-utils freerdp-codec) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/server/Windows/CMakeLists.txt b/server/Windows/CMakeLists.txt index a4cb023f6..cda340ce0 100644 --- a/server/Windows/CMakeLists.txt +++ b/server/Windows/CMakeLists.txt @@ -58,7 +58,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE freerdp - MODULES freerdp-core freerdp-utils freerdp-codec freerdp-channels) + MODULES freerdp-core freerdp-utils freerdp-codec) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})