channels/cliprdr: start exchanging messages with server-side cliprdr

This commit is contained in:
Marc-André Moreau 2013-08-16 21:17:24 -04:00
parent 0fd705c6c7
commit bca442a477
10 changed files with 316 additions and 74 deletions

View File

@ -18,7 +18,6 @@
define_channel_client("cliprdr")
set(${MODULE_PREFIX}_SRCS
cliprdr_constants.h
cliprdr_format.c
cliprdr_format.h
cliprdr_main.c

View File

@ -1,58 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Clipboard Virtual Channel
*
* 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 __CLIPRDR_CONSTANTS
#define __CLIPRDR_CONSTANTS
/* CLIPRDR_HEADER.msgType */
#define CB_MONITOR_READY 0x0001
#define CB_FORMAT_LIST 0x0002
#define CB_FORMAT_LIST_RESPONSE 0x0003
#define CB_FORMAT_DATA_REQUEST 0x0004
#define CB_FORMAT_DATA_RESPONSE 0x0005
#define CB_TEMP_DIRECTORY 0x0006
#define CB_CLIP_CAPS 0x0007
#define CB_FILECONTENTS_REQUEST 0x0008
#define CB_FILECONTENTS_RESPONSE 0x0009
#define CB_LOCK_CLIPDATA 0x000A
#define CB_UNLOCK_CLIPDATA 0x000B
/* CLIPRDR_HEADER.msgFlags */
#define CB_RESPONSE_OK 0x0001
#define CB_RESPONSE_FAIL 0x0002
#define CB_ASCII_NAMES 0x0004
/* CLIPRDR_CAPS_SET.capabilitySetType */
#define CB_CAPSTYPE_GENERAL 0x0001
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
#define CB_CAPSTYPE_GENERAL_LEN 12
/* CLIPRDR_GENERAL_CAPABILITY.version */
#define CB_CAPS_VERSION_1 0x00000001
#define CB_CAPS_VERSION_2 0x00000002
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
#define CB_USE_LONG_FORMAT_NAMES 0x00000002
#define CB_STREAM_FILECLIP_ENABLED 0x00000004
#define CB_FILECLIP_NO_FILE_PATHS 0x00000008
#define CB_CAN_LOCK_CLIPDATA 0x00000010
#endif /* __CLIPRDR_CONSTANTS */

View File

@ -34,7 +34,6 @@
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/client/cliprdr.h>
#include "cliprdr_constants.h"
#include "cliprdr_main.h"
#include "cliprdr_format.h"

View File

@ -33,7 +33,6 @@
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/client/cliprdr.h>
#include "cliprdr_constants.h"
#include "cliprdr_main.h"
#include "cliprdr_format.h"

View File

@ -25,14 +25,6 @@
#include <freerdp/utils/debug.h>
struct _CLIPRDR_FORMAT_NAME
{
UINT32 id;
char* name;
int length;
};
typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
struct cliprdr_plugin
{
rdpSvcPlugin plugin;

View File

@ -22,6 +22,7 @@
#endif
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/stream.h>
#include "cliprdr_main.h"
@ -41,11 +42,69 @@
static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
{
wStream* s;
BOOL status;
UINT32 generalFlags;
CLIPRDR_HEADER header;
printf("CliprdrServerSendCapabilities\n");
header.msgType = CB_CLIP_CAPS;
header.msgFlags = 0;
header.dataLen = 24;
generalFlags = 0;
if (context->priv->UseLongFormatNames)
generalFlags |= CB_USE_LONG_FORMAT_NAMES;
s = Stream_New(NULL, header.dataLen);
Stream_Write_UINT16(s, header.msgType); /* msgType (2 bytes) */
Stream_Write_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
Stream_Write_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets (2 bytes) */
Stream_Write_UINT16(s, 0); /* pad1 (2 bytes) */
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL); /* capabilitySetType (2 bytes) */
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability (2 bytes) */
Stream_Write_UINT32(s, CB_CAPS_VERSION_2); /* version (4 bytes) */
Stream_Write_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
Stream_SealLength(s);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Buffer(s), Stream_Length(s), NULL);
Stream_Free(s, TRUE);
return 0;
}
static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
{
wStream* s;
BOOL status;
CLIPRDR_HEADER header;
printf("CliprdrServerSendMonitorReady\n");
header.msgType = CB_MONITOR_READY;
header.msgFlags = 0;
header.dataLen = 8;
s = Stream_New(NULL, header.dataLen);
Stream_Write_UINT16(s, header.msgType); /* msgType (2 bytes) */
Stream_Write_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
Stream_Write_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
Stream_SealLength(s);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Buffer(s), Stream_Length(s), NULL);
Stream_Free(s, TRUE);
return 0;
}
@ -54,6 +113,184 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
return 0;
}
static int cliprdr_server_receive_capabilities(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
{
UINT32 version;
UINT32 generalFlags;
UINT16 cCapabilitiesSets;
UINT16 capabilitySetType;
UINT16 lengthCapability;
Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */
Stream_Read_UINT32(s, version); /* version (4 bytes) */
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
if (generalFlags & CB_USE_LONG_FORMAT_NAMES)
context->priv->UseLongFormatNames = TRUE;
if (generalFlags & CB_STREAM_FILECLIP_ENABLED)
context->priv->StreamFileClipEnabled = TRUE;
if (generalFlags & CB_FILECLIP_NO_FILE_PATHS)
context->priv->FileClipNoFilePaths = TRUE;
if (generalFlags & CB_CAN_LOCK_CLIPDATA)
context->priv->CanLockClipData = TRUE;
return 0;
}
int cliprdr_wcslen(const WCHAR* str, const WCHAR* end)
{
WCHAR* p = (WCHAR*) str;
if (!p)
return -1;
while (*p)
{
if (p == end)
return -1;
p++;
}
return (p - str);
}
static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
{
int i;
WCHAR* end;
int length;
int position;
position = Stream_GetPosition(s);
end = (WCHAR*) &(Stream_Buffer(s)[Stream_Length(s)]);
winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
context->priv->ClientFormatNameCount = 0;
while (Stream_GetRemainingLength(s) >= 6)
{
Stream_Seek(s, 4); /* formatId (4 bytes) */
length = cliprdr_wcslen((WCHAR*) Stream_Pointer(s), end);
if (length < 0)
return -1;
Stream_Seek(s, (length + 1) * 2); /* wszFormatName */
context->priv->ClientFormatNameCount = 0;
}
context->priv->ClientFormatNames = (CLIPRDR_FORMAT_NAME*)
malloc(sizeof(CLIPRDR_FORMAT_NAME) * context->priv->ClientFormatNameCount);
Stream_SetPosition(s, position);
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
{
Stream_Read_UINT32(s, context->priv->ClientFormatNames[i].id); /* formatId (4 bytes) */
context->priv->ClientFormatNames[i].length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
-1, &context->priv->ClientFormatNames[i].name, 0, NULL, NULL);
Stream_Seek(s, (context->priv->ClientFormatNames[i].length + 1) * 2);
}
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
{
printf("Format %d: Id: 0x%04X Name: %s\n", i,
context->priv->ClientFormatNames[i].id,
context->priv->ClientFormatNames[i].name);
}
return 0;
}
static int cliprdr_server_receive_short_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
{
printf("%s: unimplemented\n", __FUNCTION__);
return 0;
}
static int cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
{
int status;
if (context->priv->UseLongFormatNames)
{
status = cliprdr_server_receive_long_format_list(context, s, header);
}
else
{
status = cliprdr_server_receive_short_format_list(context, s, header);
}
return status;
}
static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s)
{
CLIPRDR_HEADER header;
Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */
Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
Stream_Read_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
printf("CliprdrServerReceivePdu: msgType: %d msgFlags: 0x%08X dataLen: %d\n",
header.msgType, header.msgFlags, header.dataLen);
switch (header.msgType)
{
case CB_CLIP_CAPS:
cliprdr_server_receive_capabilities(context, s, &header);
break;
case CB_TEMP_DIRECTORY:
break;
case CB_FORMAT_LIST:
cliprdr_server_receive_format_list(context, s, &header);
break;
case CB_FORMAT_LIST_RESPONSE:
break;
case CB_LOCK_CLIPDATA:
break;
case CB_UNLOCK_CLIPDATA:
break;
case CB_FORMAT_DATA_REQUEST:
break;
case CB_FORMAT_DATA_RESPONSE:
break;
case CB_FILECONTENTS_REQUEST:
break;
case CB_FILECONTENTS_RESPONSE:
break;
default:
printf("Unexpected clipboard PDU type: %d\n", header.msgType);
break;
}
return 0;
}
static void* cliprdr_server_thread(void* arg)
{
wStream* s;
@ -85,6 +322,9 @@ static void* cliprdr_server_thread(void* arg)
events[nCount++] = ChannelEvent;
events[nCount++] = context->priv->StopEvent;
context->SendCapabilities(context);
context->SendMonitorReady(context);
while (1)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
@ -97,17 +337,24 @@ static void* cliprdr_server_thread(void* arg)
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
{
if (BytesReturned == 0)
if (!BytesReturned)
break;
Stream_EnsureRemainingCapacity(s, (int) BytesReturned);
Stream_EnsureRemainingCapacity(s, BytesReturned);
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
{
break;
}
Stream_Seek(s, BytesReturned);
}
Stream_SealLength(s);
Stream_SetPosition(s, 0);
cliprdr_server_receive_pdu(context, s);
}
Stream_Free(s, TRUE);
@ -164,6 +411,8 @@ CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm)
if (context->priv)
{
ZeroMemory(context->priv, sizeof(CliprdrServerPrivate));
context->priv->UseLongFormatNames = TRUE;
}
}

View File

@ -26,11 +26,25 @@
#include <freerdp/server/cliprdr.h>
struct _CLIPRDR_HEADER
{
UINT16 msgType;
UINT16 msgFlags;
UINT32 dataLen;
};
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
struct _cliprdr_server_private
{
HANDLE Thread;
HANDLE StopEvent;
void* ChannelHandle;
BOOL UseLongFormatNames;
BOOL StreamFileClipEnabled;
BOOL FileClipNoFilePaths;
BOOL CanLockClipData;
UINT32 ClientFormatNameCount;
CLIPRDR_FORMAT_NAME* ClientFormatNames;
};
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */

View File

@ -474,8 +474,7 @@ void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm)
}
}
void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
void** fds, int* fds_count)
void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, void** fds, int* fds_count)
{
void* fd;
@ -543,6 +542,11 @@ BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
return result;
}
HANDLE WTSVirtualChannelManagerGetEventHandle(WTSVirtualChannelManager* vcm)
{
return vcm->send_event;
}
void* WTSVirtualChannelOpenEx(
/* __in */ WTSVirtualChannelManager* vcm,
/* __in */ const char* pVirtualName,
@ -786,7 +790,7 @@ BOOL WTSVirtualChannelWrite(
int first;
UINT32 written;
if (channel == NULL)
if (!channel)
return FALSE;
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)

View File

@ -60,6 +60,8 @@ FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelMana
void** fds, int* fds_count);
FREERDP_API BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm);
FREERDP_API HANDLE WTSVirtualChannelManagerGetEventHandle(WTSVirtualChannelManager* vcm);
/**
* Opens a static or dynamic virtual channel and return the handle. If the
* operation fails, a NULL handle is returned.

View File

@ -54,6 +54,48 @@ struct _cliprdr_client_context
#define CB_FORMAT_JPEG 0xD012
#define CB_FORMAT_GIF 0xD013
/* CLIPRDR_HEADER.msgType */
#define CB_MONITOR_READY 0x0001
#define CB_FORMAT_LIST 0x0002
#define CB_FORMAT_LIST_RESPONSE 0x0003
#define CB_FORMAT_DATA_REQUEST 0x0004
#define CB_FORMAT_DATA_RESPONSE 0x0005
#define CB_TEMP_DIRECTORY 0x0006
#define CB_CLIP_CAPS 0x0007
#define CB_FILECONTENTS_REQUEST 0x0008
#define CB_FILECONTENTS_RESPONSE 0x0009
#define CB_LOCK_CLIPDATA 0x000A
#define CB_UNLOCK_CLIPDATA 0x000B
/* CLIPRDR_HEADER.msgFlags */
#define CB_RESPONSE_OK 0x0001
#define CB_RESPONSE_FAIL 0x0002
#define CB_ASCII_NAMES 0x0004
/* CLIPRDR_CAPS_SET.capabilitySetType */
#define CB_CAPSTYPE_GENERAL 0x0001
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
#define CB_CAPSTYPE_GENERAL_LEN 12
/* CLIPRDR_GENERAL_CAPABILITY.version */
#define CB_CAPS_VERSION_1 0x00000001
#define CB_CAPS_VERSION_2 0x00000002
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
#define CB_USE_LONG_FORMAT_NAMES 0x00000002
#define CB_STREAM_FILECLIP_ENABLED 0x00000004
#define CB_FILECLIP_NO_FILE_PATHS 0x00000008
#define CB_CAN_LOCK_CLIPDATA 0x00000010
struct _CLIPRDR_FORMAT_NAME
{
UINT32 id;
char* name;
int length;
};
typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
/**
* Clipboard Events
*/