From 23eae318c5be414b74f285e9e7cfb6ae1e3ffad3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 14 Nov 2016 16:44:45 -0500 Subject: [PATCH] channels: start working on extended virtual channel API --- include/freerdp/svc.h | 22 +++- libfreerdp/core/client.c | 332 +++++++++++++++++++++++++++++++++++++++++++---- libfreerdp/core/client.h | 4 + 3 files changed, 333 insertions(+), 25 deletions(-) diff --git a/include/freerdp/svc.h b/include/freerdp/svc.h index c6843cc..d0532c8 100644 --- a/include/freerdp/svc.h +++ b/include/freerdp/svc.h @@ -30,7 +30,8 @@ #define CHANNEL_EVENT_USER 1000 -#define CHANNEL_EXPORT_FUNC_NAME "VirtualChannelEntry" +#define CHANNEL_EXPORT_FUNC_NAME "VirtualChannelEntry" +#define CHANNEL_EXPORT_FUNC_NAME_EX "VirtualChannelEntryEx" #define FREERDP_CHANNEL_MAGIC_NUMBER 0x46524450 @@ -53,4 +54,23 @@ struct _CHANNEL_ENTRY_POINTS_FREERDP typedef struct _CHANNEL_ENTRY_POINTS_FREERDP CHANNEL_ENTRY_POINTS_FREERDP; typedef CHANNEL_ENTRY_POINTS_FREERDP* PCHANNEL_ENTRY_POINTS_FREERDP; +struct _CHANNEL_ENTRY_POINTS_FREERDP_EX +{ + UINT32 cbSize; + UINT32 protocolVersion; + PVIRTUALCHANNELINITEX pVirtualChannelInitEx; + PVIRTUALCHANNELOPENEX pVirtualChannelOpenEx; + PVIRTUALCHANNELCLOSEEX pVirtualChannelCloseEx; + PVIRTUALCHANNELWRITEEX pVirtualChannelWriteEx; + + /* Extended Fields */ + UINT32 MagicNumber; /* identifies FreeRDP */ + void* pExtendedData; /* extended initial data */ + void* pInterface; /* channel callback interface, use after initialization */ + void** ppInterface; /* channel callback interface, use for initialization */ + rdpContext* context; +}; +typedef struct _CHANNEL_ENTRY_POINTS_FREERDP_EX CHANNEL_ENTRY_POINTS_FREERDP_EX; +typedef CHANNEL_ENTRY_POINTS_FREERDP_EX* PCHANNEL_ENTRY_POINTS_FREERDP_EX; + #endif /* FREERDP_SVC_H */ diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c index 951b296..e7d25a8 100644 --- a/libfreerdp/core/client.c +++ b/libfreerdp/core/client.c @@ -196,9 +196,9 @@ UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) pChannelClientData = &channels->clientDataList[index]; if (pChannelClientData->pChannelInitEventProc) - pChannelClientData->pChannelInitEventProc( - pChannelClientData->pInitHandle, - CHANNEL_EVENT_INITIALIZED, 0, 0); + { + pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle, CHANNEL_EVENT_INITIALIZED, 0, 0); + } if (CHANNEL_RC_OK != getChannelError(instance->context)) break; @@ -304,8 +304,7 @@ int freerdp_channels_data(freerdp* instance, UINT16 channelId, BYTE* data, return 1; } - pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, - channel->Name); + pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, channel->Name); if (!pChannelOpenData) { @@ -317,6 +316,11 @@ int freerdp_channels_data(freerdp* instance, UINT16 channelId, BYTE* data, pChannelOpenData->pChannelOpenEventProc(pChannelOpenData->OpenHandle, CHANNEL_EVENT_DATA_RECEIVED, data, dataSize, totalSize, flags); } + else if (pChannelOpenData->pChannelOpenEventProcEx) + { + pChannelOpenData->pChannelOpenEventProcEx(pChannelOpenData->lpUserParam, pChannelOpenData->OpenHandle, + CHANNEL_EVENT_DATA_RECEIVED, data, dataSize, totalSize, flags); + } return 0; } @@ -349,8 +353,7 @@ static int freerdp_channels_process_sync(rdpChannels* channels, break; pChannelOpenData = item->pChannelOpenData; - channel = freerdp_channels_find_channel_by_name(instance->context->rdp, - pChannelOpenData->name); + channel = freerdp_channels_find_channel_by_name(instance->context->rdp, pChannelOpenData->name); if (channel) instance->SendChannelData(instance, channel->ChannelId, item->Data, @@ -362,6 +365,12 @@ static int freerdp_channels_process_sync(rdpChannels* channels, CHANNEL_EVENT_WRITE_COMPLETE, item->UserData, item->DataLength, item->DataLength, 0); } + else if (pChannelOpenData->pChannelOpenEventProcEx) + { + pChannelOpenData->pChannelOpenEventProcEx(pChannelOpenData->lpUserParam, pChannelOpenData->OpenHandle, + CHANNEL_EVENT_WRITE_COMPLETE, item->UserData, item->DataLength, + item->DataLength, 0); + } free(item); } @@ -461,9 +470,10 @@ UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance) pChannelClientData = &channels->clientDataList[index]; if (pChannelClientData->pChannelInitEventProc) + { pChannelClientData->pChannelInitEventProc( - pChannelClientData->pInitHandle, - CHANNEL_EVENT_DISCONNECTED, 0, 0); + pChannelClientData->pInitHandle, CHANNEL_EVENT_DISCONNECTED, 0, 0); + } if (getChannelError(instance->context) != CHANNEL_RC_OK) goto fail; @@ -506,6 +516,92 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance) MessageQueue_PostQuit(channels->queue, 0); } +static UINT VCAPITYPE FreeRDP_VirtualChannelInitEx(LPVOID lpUserParam, LPVOID pInitHandle, + PCHANNEL_DEF pChannel, INT channelCount, ULONG versionRequested, PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx) +{ + INT index; + void* pInterface; + DWORD OpenHandle; + CHANNEL_DEF* channel; + rdpSettings* settings; + PCHANNEL_DEF pChannelDef; + CHANNEL_INIT_DATA* pChannelInitData; + CHANNEL_OPEN_DATA* pChannelOpenData; + CHANNEL_CLIENT_DATA* pChannelClientData; + rdpChannels* channels = (rdpChannels*) pInitHandle; + + if (!pInitHandle) + return CHANNEL_RC_BAD_INIT_HANDLE; + + if (!pChannel || (channelCount <= 0) || !pChannelInitEventProcEx) + return CHANNEL_RC_INITIALIZATION_ERROR; + + pInterface = g_pInterface; + + pChannelInitData = (CHANNEL_INIT_DATA*) pInitHandle; + channels = pChannelInitData->channels; + pChannelInitData->pInterface = pInterface; + + if (!channels->can_call_init) + return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY; + + if ((channels->openDataCount + channelCount) >= CHANNEL_MAX_COUNT) + return CHANNEL_RC_TOO_MANY_CHANNELS; + + if (!pChannel) + return CHANNEL_RC_BAD_CHANNEL; + + if (channels->connected) + return CHANNEL_RC_ALREADY_CONNECTED; + + if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000) + { + } + + for (index = 0; index < channelCount; index++) + { + pChannelDef = &pChannel[index]; + + if (freerdp_channels_find_channel_open_data_by_name(channels, pChannelDef->name) != 0) + { + return CHANNEL_RC_BAD_CHANNEL; + } + } + + pChannelClientData = &channels->clientDataList[channels->clientDataCount]; + pChannelClientData->pChannelInitEventProcEx = pChannelInitEventProcEx; + pChannelClientData->pInitHandle = pInitHandle; + channels->clientDataCount++; + settings = channels->instance->context->settings; + + for (index = 0; index < channelCount; index++) + { + pChannelDef = &pChannel[index]; + pChannelOpenData = &channels->openDataList[channels->openDataCount]; + OpenHandle = g_OpenHandleSeq++; + pChannelOpenData->OpenHandle = OpenHandle; + pChannelOpenData->channels = channels; + freerdp_channel_add_open_handle_data(&g_ChannelHandles, OpenHandle, (void*) channels); + HashTable_Add(channels->openHandles, (void*)(UINT_PTR) OpenHandle, + (void*) pChannelOpenData); + pChannelOpenData->flags = 1; /* init */ + strncpy(pChannelOpenData->name, pChannelDef->name, CHANNEL_NAME_LEN); + pChannelOpenData->options = pChannelDef->options; + + if (settings->ChannelCount < CHANNEL_MAX_COUNT) + { + channel = &settings->ChannelDefArray[settings->ChannelCount]; + strncpy(channel->name, pChannelDef->name, 7); + channel->options = pChannelDef->options; + settings->ChannelCount++; + } + + channels->openDataCount++; + } + + return CHANNEL_RC_OK; +} + static UINT VCAPITYPE FreeRDP_VirtualChannelInit(LPVOID* ppInitHandle, PCHANNEL_DEF pChannel, INT channelCount, ULONG versionRequested, @@ -596,14 +692,51 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelInit(LPVOID* ppInitHandle, return CHANNEL_RC_OK; } +static UINT VCAPITYPE FreeRDP_VirtualChannelOpenEx(LPVOID pInitHandle, + LPDWORD pOpenHandle, PCHAR pChannelName, PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx) +{ + void* pInterface; + rdpChannels* channels; + CHANNEL_INIT_DATA* pChannelInitData; + CHANNEL_OPEN_DATA* pChannelOpenData; + + pChannelInitData = (CHANNEL_INIT_DATA*) pInitHandle; + channels = pChannelInitData->channels; + pInterface = pChannelInitData->pInterface; + + if (!pOpenHandle) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + if (!pChannelOpenEventProcEx) + return CHANNEL_RC_BAD_PROC; + + if (!channels->connected) + return CHANNEL_RC_NOT_CONNECTED; + + pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, pChannelName); + + if (!pChannelOpenData) + return CHANNEL_RC_UNKNOWN_CHANNEL_NAME; + + if (pChannelOpenData->flags == 2) + return CHANNEL_RC_ALREADY_OPEN; + + pChannelOpenData->flags = 2; /* open */ + pChannelOpenData->pInterface = pInterface; + pChannelOpenData->pChannelOpenEventProcEx = pChannelOpenEventProcEx; + *pOpenHandle = pChannelOpenData->OpenHandle; + + return CHANNEL_RC_OK; +} + static UINT VCAPITYPE FreeRDP_VirtualChannelOpen(LPVOID pInitHandle, - LPDWORD pOpenHandle, - PCHAR pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc) + LPDWORD pOpenHandle, PCHAR pChannelName, PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc) { void* pInterface; rdpChannels* channels; CHANNEL_INIT_DATA* pChannelInitData; CHANNEL_OPEN_DATA* pChannelOpenData; + pChannelInitData = (CHANNEL_INIT_DATA*) pInitHandle; channels = pChannelInitData->channels; pInterface = pChannelInitData->pInterface; @@ -617,8 +750,7 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelOpen(LPVOID pInitHandle, if (!channels->connected) return CHANNEL_RC_NOT_CONNECTED; - pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, - pChannelName); + pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, pChannelName); if (!pChannelOpenData) return CHANNEL_RC_UNKNOWN_CHANNEL_NAME; @@ -630,19 +762,49 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelOpen(LPVOID pInitHandle, pChannelOpenData->pInterface = pInterface; pChannelOpenData->pChannelOpenEventProc = pChannelOpenEventProc; *pOpenHandle = pChannelOpenData->OpenHandle; + + return CHANNEL_RC_OK; +} + +static UINT VCAPITYPE FreeRDP_VirtualChannelCloseEx(LPVOID pInitHandle, DWORD openHandle) +{ + rdpChannels* channels = NULL; + CHANNEL_INIT_DATA* pChannelInitData = NULL; + CHANNEL_OPEN_DATA* pChannelOpenData = NULL; + + if (!pInitHandle) + return CHANNEL_RC_BAD_INIT_HANDLE; + + pChannelInitData = (CHANNEL_INIT_DATA*) pInitHandle; + channels = pChannelInitData->channels; + + if (!channels) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + pChannelOpenData = HashTable_GetItemValue(channels->openHandles, (void*)(UINT_PTR) openHandle); + + if (!pChannelOpenData) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + if (pChannelOpenData->flags != 2) + return CHANNEL_RC_NOT_OPEN; + + pChannelOpenData->flags = 0; + return CHANNEL_RC_OK; } static UINT VCAPITYPE FreeRDP_VirtualChannelClose(DWORD openHandle) { + rdpChannels* channels; CHANNEL_OPEN_DATA* pChannelOpenData; - rdpChannels* channels = (rdpChannels*) freerdp_channel_get_open_handle_data(&g_ChannelHandles, openHandle); + + channels = (rdpChannels*) freerdp_channel_get_open_handle_data(&g_ChannelHandles, openHandle); if (!channels) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - pChannelOpenData = HashTable_GetItemValue(channels->openHandles, - (void*)(UINT_PTR) openHandle); + pChannelOpenData = HashTable_GetItemValue(channels->openHandles, (void*)(UINT_PTR) openHandle); if (!pChannelOpenData) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -651,12 +813,65 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelClose(DWORD openHandle) return CHANNEL_RC_NOT_OPEN; pChannelOpenData->flags = 0; + + return CHANNEL_RC_OK; +} + +static UINT VCAPITYPE FreeRDP_VirtualChannelWriteEx(LPVOID pInitHandle, DWORD openHandle, + LPVOID pData, ULONG dataLength, LPVOID pUserData) +{ + rdpChannels* channels = NULL; + CHANNEL_INIT_DATA* pChannelInitData = NULL; + CHANNEL_OPEN_DATA* pChannelOpenData = NULL; + CHANNEL_OPEN_EVENT* pChannelOpenEvent = NULL; + + if (!pInitHandle) + return CHANNEL_RC_BAD_INIT_HANDLE; + + pChannelInitData = (CHANNEL_INIT_DATA*) pInitHandle; + channels = pChannelInitData->channels; + + if (!channels) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + pChannelOpenData = HashTable_GetItemValue(channels->openHandles, (void*)(UINT_PTR) openHandle); + + if (!pChannelOpenData) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + if (!channels->connected) + return CHANNEL_RC_NOT_CONNECTED; + + if (!pData) + return CHANNEL_RC_NULL_DATA; + + if (!dataLength) + return CHANNEL_RC_ZERO_LENGTH; + + if (pChannelOpenData->flags != 2) + return CHANNEL_RC_NOT_OPEN; + + pChannelOpenEvent = (CHANNEL_OPEN_EVENT*) malloc(sizeof(CHANNEL_OPEN_EVENT)); + + if (!pChannelOpenEvent) + return CHANNEL_RC_NO_MEMORY; + + pChannelOpenEvent->Data = pData; + pChannelOpenEvent->DataLength = dataLength; + pChannelOpenEvent->UserData = pUserData; + pChannelOpenEvent->pChannelOpenData = pChannelOpenData; + + if (!MessageQueue_Post(channels->queue, (void*) channels, 0, (void*) pChannelOpenEvent, NULL)) + { + free(pChannelOpenEvent); + return CHANNEL_RC_NO_MEMORY; + } + return CHANNEL_RC_OK; } static UINT VCAPITYPE FreeRDP_VirtualChannelWrite(DWORD openHandle, - LPVOID pData, - ULONG dataLength, LPVOID pUserData) + LPVOID pData, ULONG dataLength, LPVOID pUserData) { CHANNEL_OPEN_DATA* pChannelOpenData; CHANNEL_OPEN_EVENT* pChannelOpenEvent; @@ -665,8 +880,7 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelWrite(DWORD openHandle, if (!channels) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - pChannelOpenData = HashTable_GetItemValue(channels->openHandles, - (void*)(UINT_PTR) openHandle); + pChannelOpenData = HashTable_GetItemValue(channels->openHandles, (void*)(UINT_PTR) openHandle); if (!pChannelOpenData) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -693,8 +907,7 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelWrite(DWORD openHandle, pChannelOpenEvent->UserData = pUserData; pChannelOpenEvent->pChannelOpenData = pChannelOpenData; - if (!MessageQueue_Post(channels->queue, (void*) channels, 0, - (void*) pChannelOpenEvent, NULL)) + if (!MessageQueue_Post(channels->queue, (void*) channels, 0, (void*) pChannelOpenEvent, NULL)) { free(pChannelOpenEvent); return CHANNEL_RC_NO_MEMORY; @@ -703,8 +916,7 @@ static UINT VCAPITYPE FreeRDP_VirtualChannelWrite(DWORD openHandle, return CHANNEL_RC_OK; } -static BOOL freerdp_channels_is_loaded(rdpChannels* channels, - PVIRTUALCHANNELENTRY entry) +static BOOL freerdp_channels_is_loaded(rdpChannels* channels, PVIRTUALCHANNELENTRY entry) { int i; @@ -719,6 +931,21 @@ static BOOL freerdp_channels_is_loaded(rdpChannels* channels, return FALSE; } +static BOOL freerdp_channels_is_loaded_ex(rdpChannels* channels, PVIRTUALCHANNELENTRYEX entryEx) +{ + int i; + + for (i = 0; i < channels->clientDataCount; i++) + { + CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[i]; + + if (pChannelClientData->entryEx == entryEx) + return TRUE; + } + + return FALSE; +} + int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings, PVIRTUALCHANNELENTRY entry, void* data) { @@ -770,6 +997,63 @@ int freerdp_channels_client_load(rdpChannels* channels, rdpSettings* settings, return 0; } +int freerdp_channels_client_load_ex(rdpChannels* channels, rdpSettings* settings, + PVIRTUALCHANNELENTRYEX entryEx, void* data) +{ + int status; + void* pInitHandle = NULL; + CHANNEL_ENTRY_POINTS_FREERDP_EX EntryPointsEx; + CHANNEL_INIT_DATA* pChannelInitData = NULL; + CHANNEL_CLIENT_DATA* pChannelClientData = NULL; + + if (channels->clientDataCount + 1 >= CHANNEL_MAX_COUNT) + { + WLog_ERR(TAG, "error: too many channels"); + return 1; + } + + if (freerdp_channels_is_loaded_ex(channels, entryEx)) + { + WLog_WARN(TAG, "Skipping, channel already loaded"); + return 0; + } + + pChannelClientData = &channels->clientDataList[channels->clientDataCount]; + pChannelClientData->entryEx = entryEx; + + pChannelInitData = &(channels->initDataList[channels->initDataCount++]); + pInitHandle = pChannelInitData; + pChannelInitData->channels = channels; + + ZeroMemory(&EntryPointsEx, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); + EntryPointsEx.cbSize = sizeof(EntryPointsEx); + EntryPointsEx.protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000; + EntryPointsEx.pVirtualChannelInitEx = FreeRDP_VirtualChannelInitEx; + EntryPointsEx.pVirtualChannelOpenEx = FreeRDP_VirtualChannelOpenEx; + EntryPointsEx.pVirtualChannelCloseEx = FreeRDP_VirtualChannelCloseEx; + EntryPointsEx.pVirtualChannelWriteEx = FreeRDP_VirtualChannelWriteEx; + EntryPointsEx.MagicNumber = FREERDP_CHANNEL_MAGIC_NUMBER; + EntryPointsEx.ppInterface = &g_pInterface; + EntryPointsEx.pExtendedData = data; + EntryPointsEx.context = ((freerdp*) settings->instance)->context; + /* enable VirtualChannelInit */ + channels->can_call_init = TRUE; + EnterCriticalSection(&channels->channelsLock); + g_pInterface = NULL; + status = pChannelClientData->entryEx((PCHANNEL_ENTRY_POINTS_EX) &EntryPointsEx, pInitHandle); + LeaveCriticalSection(&channels->channelsLock); + /* disable MyVirtualChannelInit */ + channels->can_call_init = FALSE; + + if (!status) + { + WLog_ERR(TAG, "error: channel export function call failed"); + return 1; + } + + return 0; +} + /** * this is called when processing the command line parameters * called only from main thread diff --git a/libfreerdp/core/client.h b/libfreerdp/core/client.h index 5f6bbef..c4ff5b8 100644 --- a/libfreerdp/core/client.h +++ b/libfreerdp/core/client.h @@ -40,7 +40,9 @@ struct rdp_channel_client_data { PVIRTUALCHANNELENTRY entry; + PVIRTUALCHANNELENTRYEX entryEx; PCHANNEL_INIT_EVENT_FN pChannelInitEventProc; + PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx; void* pInitHandle; }; typedef struct rdp_channel_client_data CHANNEL_CLIENT_DATA; @@ -53,7 +55,9 @@ struct rdp_channel_open_data int flags; void* pInterface; rdpChannels* channels; + void* lpUserParam; PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc; + PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx; }; typedef struct rdp_channel_open_data CHANNEL_OPEN_DATA; -- 2.7.4