Merge branch 'xrdp-ng' of github.com:awakecoding/FreeRDP
This commit is contained in:
commit
a26db7a980
@ -284,6 +284,7 @@ if(NOT IOS AND NOT ANDROID)
|
||||
endif()
|
||||
|
||||
if(UNIX OR CYGWIN)
|
||||
check_include_files(sys/eventfd.h HAVE_AIO_H)
|
||||
check_include_files(sys/eventfd.h HAVE_EVENTFD_H)
|
||||
check_include_files(sys/timerfd.h HAVE_TIMERFD_H)
|
||||
set(X11_FEATURE_TYPE "RECOMMENDED")
|
||||
|
@ -78,7 +78,7 @@ static void audin_server_send_version(audin_server* audin, wStream* s)
|
||||
{
|
||||
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
|
||||
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
|
||||
WTSVirtualChannelWrite(audin->audin_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
||||
@ -130,7 +130,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
||||
@ -166,6 +166,7 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
|
||||
Stream_Read_UINT16(s, audin->context.client_formats[i].nBlockAlign);
|
||||
Stream_Read_UINT16(s, audin->context.client_formats[i].wBitsPerSample);
|
||||
Stream_Read_UINT16(s, audin->context.client_formats[i].cbSize);
|
||||
|
||||
if (audin->context.client_formats[i].cbSize > 0)
|
||||
{
|
||||
Stream_Seek(s, audin->context.client_formats[i].cbSize);
|
||||
@ -201,7 +202,7 @@ static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
|
||||
Stream_Write_UINT16(s, 0); /* cbSize */
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
||||
@ -283,10 +284,10 @@ static void* audin_server_thread_func(void* arg)
|
||||
void* buffer;
|
||||
BYTE MessageId;
|
||||
BOOL ready = FALSE;
|
||||
UINT32 bytes_returned = 0;
|
||||
DWORD BytesReturned = 0;
|
||||
audin_server* audin = (audin_server*) arg;
|
||||
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE)
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &BytesReturned) == TRUE)
|
||||
{
|
||||
fd = *((void**) buffer);
|
||||
WTSFreeMemory(buffer);
|
||||
@ -303,7 +304,7 @@ static void* audin_server_thread_func(void* arg)
|
||||
if (WaitForSingleObject(audin->stopEvent, 0) == WAIT_OBJECT_0)
|
||||
break;
|
||||
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &bytes_returned) == FALSE)
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE)
|
||||
break;
|
||||
|
||||
ready = *((BOOL*) buffer);
|
||||
@ -330,46 +331,48 @@ static void* audin_server_thread_func(void* arg)
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, Stream_Buffer(s),
|
||||
Stream_Capacity(s), &bytes_returned) == FALSE)
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
if (bytes_returned == 0)
|
||||
if (BytesReturned == 0)
|
||||
break;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, (int) bytes_returned);
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, Stream_Buffer(s),
|
||||
Stream_Capacity(s), &bytes_returned) == FALSE)
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_returned < 1)
|
||||
if (BytesReturned < 1)
|
||||
continue;
|
||||
|
||||
Stream_Read_UINT8(s, MessageId);
|
||||
bytes_returned--;
|
||||
BytesReturned--;
|
||||
|
||||
switch (MessageId)
|
||||
{
|
||||
case MSG_SNDIN_VERSION:
|
||||
if (audin_server_recv_version(audin, s, bytes_returned))
|
||||
if (audin_server_recv_version(audin, s, BytesReturned))
|
||||
audin_server_send_formats(audin, s);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATS:
|
||||
if (audin_server_recv_formats(audin, s, bytes_returned))
|
||||
if (audin_server_recv_formats(audin, s, BytesReturned))
|
||||
audin_server_send_open(audin, s);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_OPEN_REPLY:
|
||||
audin_server_recv_open_reply(audin, s, bytes_returned);
|
||||
audin_server_recv_open_reply(audin, s, BytesReturned);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_DATA_INCOMING:
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_DATA:
|
||||
audin_server_recv_data(audin, s, bytes_returned);
|
||||
audin_server_recv_data(audin, s, BytesReturned);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATCHANGE:
|
||||
@ -394,7 +397,7 @@ static BOOL audin_server_open(audin_server_context* context)
|
||||
|
||||
if (!audin->thread)
|
||||
{
|
||||
audin->audin_channel = WTSVirtualChannelOpenEx(context->vcm, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
|
||||
audin->audin_channel = WTSVirtualChannelManagerOpenEx(context->vcm, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
|
||||
|
||||
if (!audin->audin_channel)
|
||||
return FALSE;
|
||||
|
@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_CHANNELS)
|
||||
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT ON)
|
||||
|
||||
define_channel_options(NAME "cliprdr" TYPE "static"
|
||||
DESCRIPTION "Clipboard Virtual Channel Extension"
|
||||
|
@ -18,7 +18,6 @@
|
||||
define_channel_client("cliprdr")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
cliprdr_constants.h
|
||||
cliprdr_format.c
|
||||
cliprdr_format.h
|
||||
cliprdr_main.c
|
||||
|
@ -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 */
|
@ -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"
|
||||
|
||||
|
@ -27,13 +27,13 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include "cliprdr_constants.h"
|
||||
#include "cliprdr_main.h"
|
||||
#include "cliprdr_format.h"
|
||||
|
||||
@ -77,6 +77,11 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s)
|
||||
Stream_Write_UINT32(s, dataLen);
|
||||
Stream_SetPosition(s, pos);
|
||||
|
||||
#ifdef WITH_DEBUG_CLIPRDR
|
||||
printf("Cliprdr Sending (%d bytes)\n", dataLen + 8);
|
||||
winpr_HexDump(Stream_Buffer(s), dataLen + 8);
|
||||
#endif
|
||||
|
||||
svc_plugin_send((rdpSvcPlugin*) cliprdr, s);
|
||||
}
|
||||
|
||||
@ -207,6 +212,10 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
||||
DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d",
|
||||
CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen);
|
||||
|
||||
#ifdef WITH_DEBUG_CLIPRDR
|
||||
winpr_HexDump(Stream_Buffer(s), dataLen + 8);
|
||||
#endif
|
||||
|
||||
switch (msgType)
|
||||
{
|
||||
case CB_CLIP_CAPS:
|
||||
|
@ -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;
|
||||
|
35
channels/cliprdr/server/CMakeLists.txt
Normal file
35
channels/cliprdr/server/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
define_channel_server("cliprdr")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
cliprdr_main.c
|
||||
cliprdr_main.h)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
536
channels/cliprdr/server/cliprdr_main.c
Normal file
536
channels/cliprdr/server/cliprdr_main.c
Normal file
@ -0,0 +1,536 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Clipboard Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "cliprdr_main.h"
|
||||
|
||||
/**
|
||||
* Initialization Sequence\n
|
||||
* Client Server\n
|
||||
* | |\n
|
||||
* |<----------------------Server Clipboard Capabilities PDU-----------------|\n
|
||||
* |<-----------------------------Monitor Ready PDU--------------------------|\n
|
||||
* |-----------------------Client Clipboard Capabilities PDU---------------->|\n
|
||||
* |---------------------------Temporary Directory PDU---------------------->|\n
|
||||
* |-------------------------------Format List PDU-------------------------->|\n
|
||||
* |<--------------------------Format List Response PDU----------------------|\n
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data Transfer Sequences\n
|
||||
* Shared Local\n
|
||||
* Clipboard Owner Clipboard Owner\n
|
||||
* | |\n
|
||||
* |-------------------------------------------------------------------------|\n _
|
||||
* |-------------------------------Format List PDU-------------------------->|\n |
|
||||
* |<--------------------------Format List Response PDU----------------------|\n _| Copy Sequence
|
||||
* |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n
|
||||
* |-------------------------------------------------------------------------|\n
|
||||
* |-------------------------------------------------------------------------|\n _
|
||||
* |<--------------------------Format Data Request PDU-----------------------|\n | Paste Sequence Palette,
|
||||
* |---------------------------Format Data Response PDU--------------------->|\n _| Metafile, File List Data
|
||||
* |-------------------------------------------------------------------------|\n
|
||||
* |-------------------------------------------------------------------------|\n _
|
||||
* |<------------------------Format Contents Request PDU---------------------|\n | Paste Sequence
|
||||
* |-------------------------Format Contents Response PDU------------------->|\n _| File Stream Data
|
||||
* |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n
|
||||
* |-------------------------------------------------------------------------|\n
|
||||
*
|
||||
*/
|
||||
|
||||
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 = 16;
|
||||
|
||||
generalFlags = 0;
|
||||
|
||||
if (context->priv->UseLongFormatNames)
|
||||
generalFlags |= CB_USE_LONG_FORMAT_NAMES;
|
||||
|
||||
s = Stream_New(NULL, header.dataLen + CLIPRDR_HEADER_LENGTH);
|
||||
|
||||
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, (PCHAR) 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 = 0;
|
||||
|
||||
s = Stream_New(NULL, header.dataLen + CLIPRDR_HEADER_LENGTH);
|
||||
|
||||
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, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cliprdr_server_send_format_list_response(CliprdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
CLIPRDR_HEADER header;
|
||||
|
||||
printf("CliprdrServerSendFormatListResponse\n");
|
||||
|
||||
header.msgType = CB_FORMAT_LIST_RESPONSE;
|
||||
header.msgFlags = CB_RESPONSE_OK;
|
||||
header.dataLen = 0;
|
||||
|
||||
s = Stream_New(NULL, header.dataLen + CLIPRDR_HEADER_LENGTH);
|
||||
|
||||
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, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_temporary_directory(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
WCHAR* wszTempDir;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 520)
|
||||
return -1;
|
||||
|
||||
wszTempDir = (WCHAR*) Stream_Pointer(s);
|
||||
|
||||
if (wszTempDir[260] != 0)
|
||||
return -1;
|
||||
|
||||
ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1,
|
||||
&(context->priv->ClientTemporaryDirectory), 0, NULL, NULL);
|
||||
|
||||
printf("ClientTemporaryDirectory: %s\n", context->priv->ClientTemporaryDirectory);
|
||||
|
||||
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 void cliprdr_free_format_list(UINT32 count, CLIPRDR_FORMAT_NAME* formatNames)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (formatNames)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
free(formatNames[i].name);
|
||||
}
|
||||
|
||||
free(formatNames);
|
||||
}
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
int i;
|
||||
WCHAR* end;
|
||||
int length;
|
||||
int position;
|
||||
|
||||
printf("%s\n", __FUNCTION__);
|
||||
|
||||
position = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, Stream_Length(s));
|
||||
end = (WCHAR*) Stream_Pointer(s);
|
||||
Stream_SetPosition(s, position);
|
||||
|
||||
cliprdr_free_format_list(context->priv->ClientFormatNameCount, context->priv->ClientFormatNames);
|
||||
context->priv->ClientFormatNameCount = 0;
|
||||
context->priv->ClientFormatNames = NULL;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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) */
|
||||
|
||||
length = cliprdr_wcslen((WCHAR*) Stream_Pointer(s), end);
|
||||
|
||||
context->priv->ClientFormatNames[i].name = NULL;
|
||||
|
||||
if (length)
|
||||
{
|
||||
context->priv->ClientFormatNames[i].length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
||||
-1, &(context->priv->ClientFormatNames[i].name), 0, NULL, NULL) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->priv->ClientFormatNames[i].length = 0;
|
||||
}
|
||||
|
||||
Stream_Seek(s, (length + 1) * 2); /* wszFormatName */
|
||||
}
|
||||
|
||||
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
|
||||
{
|
||||
printf("Format %d: Id: 0x%04X Name: %s Length: %d\n", i,
|
||||
context->priv->ClientFormatNames[i].id,
|
||||
context->priv->ClientFormatNames[i].name,
|
||||
context->priv->ClientFormatNames[i].length);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
cliprdr_server_send_format_list_response(context);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
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:
|
||||
cliprdr_server_receive_temporary_directory(context, s, header);
|
||||
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;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
void* buffer;
|
||||
int position;
|
||||
HANDLE events[8];
|
||||
HANDLE ChannelEvent;
|
||||
DWORD BytesReturned;
|
||||
CLIPRDR_HEADER header;
|
||||
CliprdrServerContext* context;
|
||||
|
||||
context = (CliprdrServerContext*) arg;
|
||||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = NULL;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
cliprdr_server_send_capabilities(context);
|
||||
cliprdr_server_send_monitor_ready(context);
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
|
||||
{
|
||||
if (BytesReturned)
|
||||
Stream_Seek(s, BytesReturned);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
}
|
||||
|
||||
if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH)
|
||||
{
|
||||
position = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
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) */
|
||||
|
||||
Stream_SetPosition(s, position);
|
||||
|
||||
if (Stream_GetPosition(s) >= (header.dataLen + CLIPRDR_HEADER_LENGTH))
|
||||
{
|
||||
Stream_SealLength(s);
|
||||
Stream_SetPosition(s, CLIPRDR_HEADER_LENGTH);
|
||||
|
||||
cliprdr_server_receive_pdu(context, s, &header);
|
||||
Stream_SetPosition(s, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int cliprdr_server_start(CliprdrServerContext* context)
|
||||
{
|
||||
context->priv->ChannelHandle = WTSVirtualChannelManagerOpenEx(context->vcm, "cliprdr", 0);
|
||||
|
||||
if (!context->priv->ChannelHandle)
|
||||
return -1;
|
||||
|
||||
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) cliprdr_server_thread, (void*) context, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cliprdr_server_stop(CliprdrServerContext* context)
|
||||
{
|
||||
SetEvent(context->priv->StopEvent);
|
||||
|
||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||
CloseHandle(context->priv->Thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
CliprdrServerContext* context;
|
||||
|
||||
context = (CliprdrServerContext*) malloc(sizeof(CliprdrServerContext));
|
||||
|
||||
if (context)
|
||||
{
|
||||
ZeroMemory(context, sizeof(CliprdrServerContext));
|
||||
|
||||
context->vcm = vcm;
|
||||
|
||||
context->Start = cliprdr_server_start;
|
||||
context->Stop = cliprdr_server_stop;
|
||||
|
||||
context->priv = (CliprdrServerPrivate*) malloc(sizeof(CliprdrServerPrivate));
|
||||
|
||||
if (context->priv)
|
||||
{
|
||||
ZeroMemory(context->priv, sizeof(CliprdrServerPrivate));
|
||||
|
||||
context->priv->UseLongFormatNames = TRUE;
|
||||
context->priv->StreamFileClipEnabled = TRUE;
|
||||
context->priv->FileClipNoFilePaths = TRUE;
|
||||
context->priv->CanLockClipData = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void cliprdr_server_context_free(CliprdrServerContext* context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
if (context->priv)
|
||||
{
|
||||
free(context->priv);
|
||||
}
|
||||
|
||||
free(context);
|
||||
}
|
||||
}
|
56
channels/cliprdr/server/cliprdr_main.h
Normal file
56
channels/cliprdr/server/cliprdr_main.h
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Clipboard Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H
|
||||
#define FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <freerdp/server/cliprdr.h>
|
||||
|
||||
#define CLIPRDR_HEADER_LENGTH 8
|
||||
|
||||
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;
|
||||
|
||||
char* ClientTemporaryDirectory;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */
|
@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_CHANNELS)
|
||||
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT ON)
|
||||
|
||||
define_channel_options(NAME "drdynvc" TYPE "static"
|
||||
DESCRIPTION "Dynamic Virtual Channel Extension"
|
||||
|
35
channels/drdynvc/server/CMakeLists.txt
Normal file
35
channels/drdynvc/server/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
define_channel_server("drdynvc")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
drdynvc_main.c
|
||||
drdynvc_main.h)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
149
channels/drdynvc/server/drdynvc_main.c
Normal file
149
channels/drdynvc/server/drdynvc_main.c
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Dynamic Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "drdynvc_main.h"
|
||||
|
||||
static void* drdynvc_server_thread(void* arg)
|
||||
{
|
||||
wStream* s;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
void* buffer;
|
||||
HANDLE events[8];
|
||||
HANDLE ChannelEvent;
|
||||
DWORD BytesReturned;
|
||||
DrdynvcServerContext* context;
|
||||
|
||||
context = (DrdynvcServerContext*) arg;
|
||||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = NULL;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
|
||||
{
|
||||
if (BytesReturned)
|
||||
Stream_Seek(s, BytesReturned);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int drdynvc_server_start(DrdynvcServerContext* context)
|
||||
{
|
||||
context->priv->ChannelHandle = WTSVirtualChannelManagerOpenEx(context->vcm, "rdpdr", 0);
|
||||
|
||||
if (!context->priv->ChannelHandle)
|
||||
return -1;
|
||||
|
||||
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) drdynvc_server_thread, (void*) context, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drdynvc_server_stop(DrdynvcServerContext* context)
|
||||
{
|
||||
SetEvent(context->priv->StopEvent);
|
||||
|
||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||
CloseHandle(context->priv->Thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DrdynvcServerContext* drdynvc_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
DrdynvcServerContext* context;
|
||||
|
||||
context = (DrdynvcServerContext*) malloc(sizeof(DrdynvcServerContext));
|
||||
|
||||
if (context)
|
||||
{
|
||||
ZeroMemory(context, sizeof(DrdynvcServerContext));
|
||||
|
||||
context->vcm = vcm;
|
||||
|
||||
context->Start = drdynvc_server_start;
|
||||
context->Stop = drdynvc_server_stop;
|
||||
|
||||
context->priv = (DrdynvcServerPrivate*) malloc(sizeof(DrdynvcServerPrivate));
|
||||
|
||||
if (context->priv)
|
||||
{
|
||||
ZeroMemory(context->priv, sizeof(DrdynvcServerPrivate));
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void drdynvc_server_context_free(DrdynvcServerContext* context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
if (context->priv)
|
||||
{
|
||||
free(context->priv);
|
||||
}
|
||||
|
||||
free(context);
|
||||
}
|
||||
}
|
37
channels/drdynvc/server/drdynvc_main.h
Normal file
37
channels/drdynvc/server/drdynvc_main.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Dynamic Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_DRDYNVC_MAIN_H
|
||||
#define FREERDP_CHANNEL_SERVER_DRDYNVC_MAIN_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/server/drdynvc.h>
|
||||
|
||||
struct _drdynvc_server_private
|
||||
{
|
||||
HANDLE Thread;
|
||||
HANDLE StopEvent;
|
||||
void* ChannelHandle;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_DRDYNVC_MAIN_H */
|
@ -20,3 +20,7 @@ define_channel("rdpdr")
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_CHANNELS)
|
||||
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT ON)
|
||||
|
||||
define_channel_options(NAME "rdpdr" TYPE "static"
|
||||
DESCRIPTION "Device Redirection Virtual Channel Extension"
|
||||
|
@ -33,132 +33,132 @@
|
||||
#include "rdpdr_capabilities.h"
|
||||
|
||||
/* Output device redirection capability set header */
|
||||
static void rdpdr_write_capset_header(wStream* data_out, UINT16 capabilityType, UINT16 capabilityLength, UINT32 version)
|
||||
static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 capabilityLength, UINT32 version)
|
||||
{
|
||||
Stream_Write_UINT16(data_out, capabilityType);
|
||||
Stream_Write_UINT16(data_out, capabilityLength);
|
||||
Stream_Write_UINT32(data_out, version);
|
||||
Stream_Write_UINT16(s, capabilityType);
|
||||
Stream_Write_UINT16(s, capabilityLength);
|
||||
Stream_Write_UINT32(s, version);
|
||||
}
|
||||
|
||||
/* Output device direction general capability set */
|
||||
static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* data_out)
|
||||
static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
rdpdr_write_capset_header(data_out, CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02);
|
||||
rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02);
|
||||
|
||||
Stream_Write_UINT32(data_out, 0); /* osType, ignored on receipt */
|
||||
Stream_Write_UINT32(data_out, 0); /* osVersion, unused and must be set to zero */
|
||||
Stream_Write_UINT16(data_out, 1); /* protocolMajorVersion, must be set to 1 */
|
||||
Stream_Write_UINT16(data_out, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */
|
||||
Stream_Write_UINT32(data_out, 0x0000FFFF); /* ioCode1 */
|
||||
Stream_Write_UINT32(data_out, 0); /* ioCode2, must be set to zero, reserved for future use */
|
||||
Stream_Write_UINT32(data_out, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */
|
||||
Stream_Write_UINT32(data_out, ENABLE_ASYNCIO); /* extraFlags1 */
|
||||
Stream_Write_UINT32(data_out, 0); /* extraFlags2, must be set to zero, reserved for future use */
|
||||
Stream_Write_UINT32(data_out, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */
|
||||
Stream_Write_UINT32(s, 0); /* osType, ignored on receipt */
|
||||
Stream_Write_UINT32(s, 0); /* osVersion, unused and must be set to zero */
|
||||
Stream_Write_UINT16(s, 1); /* protocolMajorVersion, must be set to 1 */
|
||||
Stream_Write_UINT16(s, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */
|
||||
Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */
|
||||
Stream_Write_UINT32(s, 0); /* ioCode2, must be set to zero, reserved for future use */
|
||||
Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */
|
||||
Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */
|
||||
Stream_Write_UINT32(s, 0); /* extraFlags2, must be set to zero, reserved for future use */
|
||||
Stream_Write_UINT32(s, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */
|
||||
}
|
||||
|
||||
/* Process device direction general capability set */
|
||||
static void rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
static void rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
UINT16 capabilityLength;
|
||||
|
||||
Stream_Read_UINT16(data_in, capabilityLength);
|
||||
Stream_Seek(data_in, capabilityLength - 4);
|
||||
Stream_Read_UINT16(s, capabilityLength);
|
||||
Stream_Seek(s, capabilityLength - 4);
|
||||
}
|
||||
|
||||
/* Output printer direction capability set */
|
||||
static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* data_out)
|
||||
static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
rdpdr_write_capset_header(data_out, CAP_PRINTER_TYPE, 8, PRINT_CAPABILITY_VERSION_01);
|
||||
rdpdr_write_capset_header(s, CAP_PRINTER_TYPE, 8, PRINT_CAPABILITY_VERSION_01);
|
||||
}
|
||||
|
||||
/* Process printer direction capability set */
|
||||
static void rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
static void rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
UINT16 capabilityLength;
|
||||
|
||||
Stream_Read_UINT16(data_in, capabilityLength);
|
||||
Stream_Seek(data_in, capabilityLength - 4);
|
||||
Stream_Read_UINT16(s, capabilityLength);
|
||||
Stream_Seek(s, capabilityLength - 4);
|
||||
}
|
||||
|
||||
/* Output port redirection capability set */
|
||||
static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* data_out)
|
||||
static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
rdpdr_write_capset_header(data_out, CAP_PORT_TYPE, 8, PORT_CAPABILITY_VERSION_01);
|
||||
rdpdr_write_capset_header(s, CAP_PORT_TYPE, 8, PORT_CAPABILITY_VERSION_01);
|
||||
}
|
||||
|
||||
/* Process port redirection capability set */
|
||||
static void rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
static void rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
UINT16 capabilityLength;
|
||||
|
||||
Stream_Read_UINT16(data_in, capabilityLength);
|
||||
Stream_Seek(data_in, capabilityLength - 4);
|
||||
Stream_Read_UINT16(s, capabilityLength);
|
||||
Stream_Seek(s, capabilityLength - 4);
|
||||
}
|
||||
|
||||
/* Output drive redirection capability set */
|
||||
static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* data_out)
|
||||
static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
rdpdr_write_capset_header(data_out, CAP_DRIVE_TYPE, 8, DRIVE_CAPABILITY_VERSION_02);
|
||||
rdpdr_write_capset_header(s, CAP_DRIVE_TYPE, 8, DRIVE_CAPABILITY_VERSION_02);
|
||||
}
|
||||
|
||||
/* Process drive redirection capability set */
|
||||
static void rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
static void rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
UINT16 capabilityLength;
|
||||
|
||||
Stream_Read_UINT16(data_in, capabilityLength);
|
||||
Stream_Seek(data_in, capabilityLength - 4);
|
||||
Stream_Read_UINT16(s, capabilityLength);
|
||||
Stream_Seek(s, capabilityLength - 4);
|
||||
}
|
||||
|
||||
/* Output smart card redirection capability set */
|
||||
static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* data_out)
|
||||
static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
rdpdr_write_capset_header(data_out, CAP_SMARTCARD_TYPE, 8, SMARTCARD_CAPABILITY_VERSION_01);
|
||||
rdpdr_write_capset_header(s, CAP_SMARTCARD_TYPE, 8, SMARTCARD_CAPABILITY_VERSION_01);
|
||||
}
|
||||
|
||||
/* Process smartcard redirection capability set */
|
||||
static void rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
static void rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
UINT16 capabilityLength;
|
||||
|
||||
Stream_Read_UINT16(data_in, capabilityLength);
|
||||
Stream_Seek(data_in, capabilityLength - 4);
|
||||
Stream_Read_UINT16(s, capabilityLength);
|
||||
Stream_Seek(s, capabilityLength - 4);
|
||||
}
|
||||
|
||||
void rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
void rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
|
||||
{
|
||||
UINT16 i;
|
||||
UINT16 numCapabilities;
|
||||
UINT16 capabilityType;
|
||||
|
||||
Stream_Read_UINT16(data_in, numCapabilities);
|
||||
Stream_Seek(data_in, 2); /* pad (2 bytes) */
|
||||
Stream_Read_UINT16(s, numCapabilities);
|
||||
Stream_Seek(s, 2); /* pad (2 bytes) */
|
||||
|
||||
for(i = 0; i < numCapabilities; i++)
|
||||
for (i = 0; i < numCapabilities; i++)
|
||||
{
|
||||
Stream_Read_UINT16(data_in, capabilityType);
|
||||
Stream_Read_UINT16(s, capabilityType);
|
||||
|
||||
switch (capabilityType)
|
||||
{
|
||||
case CAP_GENERAL_TYPE:
|
||||
rdpdr_process_general_capset(rdpdr, data_in);
|
||||
rdpdr_process_general_capset(rdpdr, s);
|
||||
break;
|
||||
|
||||
case CAP_PRINTER_TYPE:
|
||||
rdpdr_process_printer_capset(rdpdr, data_in);
|
||||
rdpdr_process_printer_capset(rdpdr, s);
|
||||
break;
|
||||
|
||||
case CAP_PORT_TYPE:
|
||||
rdpdr_process_port_capset(rdpdr, data_in);
|
||||
rdpdr_process_port_capset(rdpdr, s);
|
||||
break;
|
||||
|
||||
case CAP_DRIVE_TYPE:
|
||||
rdpdr_process_drive_capset(rdpdr, data_in);
|
||||
rdpdr_process_drive_capset(rdpdr, s);
|
||||
break;
|
||||
|
||||
case CAP_SMARTCARD_TYPE:
|
||||
rdpdr_process_smartcard_capset(rdpdr, data_in);
|
||||
rdpdr_process_smartcard_capset(rdpdr, s);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -170,21 +170,21 @@ void rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* data_in)
|
||||
|
||||
void rdpdr_send_capability_response(rdpdrPlugin* rdpdr)
|
||||
{
|
||||
wStream* data_out;
|
||||
wStream* s;
|
||||
|
||||
data_out = Stream_New(NULL, 256);
|
||||
s = Stream_New(NULL, 256);
|
||||
|
||||
Stream_Write_UINT16(data_out, RDPDR_CTYP_CORE);
|
||||
Stream_Write_UINT16(data_out, PAKID_CORE_CLIENT_CAPABILITY);
|
||||
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
|
||||
Stream_Write_UINT16(s, PAKID_CORE_CLIENT_CAPABILITY);
|
||||
|
||||
Stream_Write_UINT16(data_out, 5); /* numCapabilities */
|
||||
Stream_Write_UINT16(data_out, 0); /* pad */
|
||||
Stream_Write_UINT16(s, 5); /* numCapabilities */
|
||||
Stream_Write_UINT16(s, 0); /* pad */
|
||||
|
||||
rdpdr_write_general_capset(rdpdr, data_out);
|
||||
rdpdr_write_printer_capset(rdpdr, data_out);
|
||||
rdpdr_write_port_capset(rdpdr, data_out);
|
||||
rdpdr_write_drive_capset(rdpdr, data_out);
|
||||
rdpdr_write_smartcard_capset(rdpdr, data_out);
|
||||
rdpdr_write_general_capset(rdpdr, s);
|
||||
rdpdr_write_printer_capset(rdpdr, s);
|
||||
rdpdr_write_port_capset(rdpdr, s);
|
||||
rdpdr_write_drive_capset(rdpdr, s);
|
||||
rdpdr_write_smartcard_capset(rdpdr, s);
|
||||
|
||||
svc_plugin_send((rdpSvcPlugin*)rdpdr, data_out);
|
||||
svc_plugin_send((rdpSvcPlugin*)rdpdr, s);
|
||||
}
|
||||
|
35
channels/rdpdr/server/CMakeLists.txt
Normal file
35
channels/rdpdr/server/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
define_channel_server("rdpdr")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
rdpdr_main.c
|
||||
rdpdr_main.h)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
699
channels/rdpdr/server/rdpdr_main.c
Normal file
699
channels/rdpdr/server/rdpdr_main.c
Normal file
@ -0,0 +1,699 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Device Redirection Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "rdpdr_main.h"
|
||||
|
||||
static UINT32 g_ClientId = 0;
|
||||
|
||||
static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
|
||||
printf("RdpdrServerSendAnnounceRequest\n");
|
||||
|
||||
header.Component = RDPDR_CTYP_CORE;
|
||||
header.PacketId = PAKID_CORE_SERVER_ANNOUNCE;
|
||||
|
||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8);
|
||||
|
||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||
|
||||
Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */
|
||||
Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
|
||||
Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_receive_announce_response(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
||||
{
|
||||
UINT32 ClientId;
|
||||
UINT16 VersionMajor;
|
||||
UINT16 VersionMinor;
|
||||
|
||||
Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */
|
||||
Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */
|
||||
Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */
|
||||
|
||||
printf("Client Announce Response: VersionMajor: 0x%04X VersionMinor: 0x%04X ClientId: 0x%04X\n",
|
||||
VersionMajor, VersionMinor, ClientId);
|
||||
|
||||
context->priv->ClientId = ClientId;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
||||
{
|
||||
UINT32 UnicodeFlag;
|
||||
UINT32 ComputerNameLen;
|
||||
|
||||
Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */
|
||||
Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */
|
||||
Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */
|
||||
|
||||
/**
|
||||
* Caution: ComputerNameLen is given *bytes*,
|
||||
* not in characters, including the NULL terminator!
|
||||
*/
|
||||
|
||||
if (context->priv->ClientComputerName)
|
||||
{
|
||||
free(context->priv->ClientComputerName);
|
||||
context->priv->ClientComputerName = NULL;
|
||||
}
|
||||
|
||||
if (UnicodeFlag)
|
||||
{
|
||||
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
||||
-1, &(context->priv->ClientComputerName), 0, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
context->priv->ClientComputerName = _strdup((char*) Stream_Pointer(s));
|
||||
}
|
||||
|
||||
Stream_Seek(s, ComputerNameLen);
|
||||
|
||||
printf("ClientComputerName: %s\n", context->priv->ClientComputerName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_read_capability_set_header(wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
Stream_Read_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
|
||||
Stream_Read_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
|
||||
Stream_Read_UINT32(s, header->Version); /* Version (4 bytes) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_write_capability_set_header(wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
Stream_Write_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */
|
||||
Stream_Write_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */
|
||||
Stream_Write_UINT32(s, header->Version); /* Version (4 bytes) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context, wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
UINT32 ioCode1;
|
||||
UINT32 extraFlags1;
|
||||
UINT32 extendedPdu;
|
||||
UINT16 VersionMajor;
|
||||
UINT16 VersionMinor;
|
||||
UINT32 SpecialTypeDeviceCap;
|
||||
|
||||
Stream_Seek_UINT32(s); /* osType (4 bytes), ignored on receipt */
|
||||
Stream_Seek_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */
|
||||
Stream_Read_UINT16(s, VersionMajor); /* protocolMajorVersion (2 bytes) */
|
||||
Stream_Read_UINT16(s, VersionMinor); /* protocolMinorVersion (2 bytes) */
|
||||
Stream_Read_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */
|
||||
Stream_Seek_UINT32(s); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */
|
||||
Stream_Read_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */
|
||||
Stream_Read_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
|
||||
Stream_Seek_UINT32(s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
|
||||
Stream_Read_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
|
||||
|
||||
context->priv->UserLoggedOnPdu = (extendedPdu & RDPDR_USER_LOGGEDON_PDU) ? TRUE : FALSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context, wStream* s)
|
||||
{
|
||||
UINT32 ioCode1;
|
||||
UINT32 extendedPdu;
|
||||
UINT32 extraFlags1;
|
||||
UINT32 SpecialTypeDeviceCap;
|
||||
RDPDR_CAPABILITY_HEADER header;
|
||||
|
||||
header.CapabilityType = CAP_GENERAL_TYPE;
|
||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH + 36;
|
||||
header.Version = GENERAL_CAPABILITY_VERSION_02;
|
||||
|
||||
ioCode1 = 0;
|
||||
ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_CLOSE; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_READ; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_WRITE; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_FLUSH_BUFFERS; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_SHUTDOWN; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_DEVICE_CONTROL; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_SET_VOLUME_INFORMATION; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_QUERY_INFORMATION; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_SET_INFORMATION; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_DIRECTORY_CONTROL; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */
|
||||
ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */
|
||||
ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */
|
||||
|
||||
extendedPdu = 0;
|
||||
extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */
|
||||
extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */
|
||||
|
||||
if (context->priv->UserLoggedOnPdu)
|
||||
extendedPdu |= RDPDR_USER_LOGGEDON_PDU; /* optional */
|
||||
|
||||
extraFlags1 = 0;
|
||||
extraFlags1 |= ENABLE_ASYNCIO; /* optional */
|
||||
|
||||
SpecialTypeDeviceCap = 0;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||
rdpdr_server_write_capability_set_header(s, &header);
|
||||
|
||||
Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */
|
||||
Stream_Write_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */
|
||||
Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */
|
||||
Stream_Write_UINT16(s, context->priv->VersionMinor); /* protocolMinorVersion (2 bytes) */
|
||||
Stream_Write_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */
|
||||
Stream_Write_UINT32(s, 0); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */
|
||||
Stream_Write_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */
|
||||
Stream_Write_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
|
||||
Stream_Write_UINT32(s, 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
|
||||
Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_read_printer_capability_set(RdpdrServerContext* context, wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s)
|
||||
{
|
||||
RDPDR_CAPABILITY_HEADER header;
|
||||
|
||||
header.CapabilityType = CAP_PRINTER_TYPE;
|
||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||
header.Version = PRINT_CAPABILITY_VERSION_01;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||
rdpdr_server_write_capability_set_header(s, &header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s)
|
||||
{
|
||||
RDPDR_CAPABILITY_HEADER header;
|
||||
|
||||
header.CapabilityType = CAP_PORT_TYPE;
|
||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||
header.Version = PORT_CAPABILITY_VERSION_01;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||
rdpdr_server_write_capability_set_header(s, &header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s)
|
||||
{
|
||||
RDPDR_CAPABILITY_HEADER header;
|
||||
|
||||
header.CapabilityType = CAP_DRIVE_TYPE;
|
||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||
header.Version = DRIVE_CAPABILITY_VERSION_02;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||
rdpdr_server_write_capability_set_header(s, &header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* context, wStream* s, RDPDR_CAPABILITY_HEADER* header)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s)
|
||||
{
|
||||
RDPDR_CAPABILITY_HEADER header;
|
||||
|
||||
header.CapabilityType = CAP_SMARTCARD_TYPE;
|
||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||
header.Version = SMARTCARD_CAPABILITY_VERSION_01;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||
rdpdr_server_write_capability_set_header(s, &header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
UINT16 numCapabilities;
|
||||
|
||||
printf("RdpdrServerSendCoreCapabilityRequest\n");
|
||||
|
||||
header.Component = RDPDR_CTYP_CORE;
|
||||
header.PacketId = PAKID_CORE_SERVER_CAPABILITY;
|
||||
|
||||
numCapabilities = 5;
|
||||
|
||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 512);
|
||||
|
||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||
|
||||
Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
|
||||
Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */
|
||||
|
||||
rdpdr_server_write_general_capability_set(context, s);
|
||||
rdpdr_server_write_printer_capability_set(context, s);
|
||||
rdpdr_server_write_port_capability_set(context, s);
|
||||
rdpdr_server_write_drive_capability_set(context, s);
|
||||
rdpdr_server_write_smartcard_capability_set(context, s);
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
||||
{
|
||||
int i;
|
||||
UINT16 numCapabilities;
|
||||
RDPDR_CAPABILITY_HEADER capabilityHeader;
|
||||
|
||||
Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
|
||||
Stream_Seek_UINT16(s); /* Padding (2 bytes) */
|
||||
|
||||
for (i = 0; i < numCapabilities; i++)
|
||||
{
|
||||
rdpdr_server_read_capability_set_header(s, &capabilityHeader);
|
||||
|
||||
switch (capabilityHeader.CapabilityType)
|
||||
{
|
||||
case CAP_GENERAL_TYPE:
|
||||
rdpdr_server_read_general_capability_set(context, s, &capabilityHeader);
|
||||
break;
|
||||
|
||||
case CAP_PRINTER_TYPE:
|
||||
rdpdr_server_read_printer_capability_set(context, s, &capabilityHeader);
|
||||
break;
|
||||
|
||||
case CAP_PORT_TYPE:
|
||||
rdpdr_server_read_port_capability_set(context, s, &capabilityHeader);
|
||||
break;
|
||||
|
||||
case CAP_DRIVE_TYPE:
|
||||
rdpdr_server_read_drive_capability_set(context, s, &capabilityHeader);
|
||||
break;
|
||||
|
||||
case CAP_SMARTCARD_TYPE:
|
||||
rdpdr_server_read_smartcard_capability_set(context, s, &capabilityHeader);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown capabilityType %d\n", capabilityHeader.CapabilityType);
|
||||
Stream_Seek(s, capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
|
||||
printf("RdpdrServerSendClientIdConfirm\n");
|
||||
|
||||
header.Component = RDPDR_CTYP_CORE;
|
||||
header.PacketId = PAKID_CORE_CLIENTID_CONFIRM;
|
||||
|
||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8);
|
||||
|
||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||
|
||||
Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */
|
||||
Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
|
||||
Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
||||
{
|
||||
int i;
|
||||
UINT32 DeviceCount;
|
||||
UINT32 DeviceType;
|
||||
UINT32 DeviceId;
|
||||
char PreferredDosName[9];
|
||||
UINT32 DeviceDataLength;
|
||||
|
||||
PreferredDosName[8] = 0;
|
||||
|
||||
Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */
|
||||
|
||||
printf("%s: DeviceCount: %d\n", __FUNCTION__, DeviceCount);
|
||||
|
||||
for (i = 0; i < DeviceCount; i++)
|
||||
{
|
||||
Stream_Read_UINT32(s, DeviceType); /* DeviceType (4 bytes) */
|
||||
Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */
|
||||
Stream_Read(s, PreferredDosName, 8); /* PreferredDosName (8 bytes) */
|
||||
Stream_Read_UINT32(s, DeviceDataLength); /* DeviceDataLength (4 bytes) */
|
||||
|
||||
printf("Device %d Name: %s Id: 0x%04X DataLength: %d\n",
|
||||
i, PreferredDosName, DeviceId, DeviceDataLength);
|
||||
|
||||
switch (DeviceId)
|
||||
{
|
||||
case RDPDR_DTYP_FILESYSTEM:
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_PRINT:
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_SERIAL:
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_PARALLEL:
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_SMARTCARD:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Seek(s, DeviceDataLength);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
|
||||
printf("%s\n", __FUNCTION__);
|
||||
|
||||
header.Component = RDPDR_CTYP_CORE;
|
||||
header.PacketId = PAKID_CORE_USER_LOGGEDON;
|
||||
|
||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH);
|
||||
|
||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
||||
{
|
||||
printf("RdpdrServerReceivePdu: Component: 0x%04X PacketId: 0x%04X\n",
|
||||
header->Component, header->PacketId);
|
||||
|
||||
winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
|
||||
|
||||
if (header->Component == RDPDR_CTYP_CORE)
|
||||
{
|
||||
switch (header->PacketId)
|
||||
{
|
||||
case PAKID_CORE_CLIENTID_CONFIRM:
|
||||
rdpdr_server_receive_announce_response(context, s, header);
|
||||
break;
|
||||
|
||||
case PAKID_CORE_CLIENT_NAME:
|
||||
rdpdr_server_receive_client_name_request(context, s, header);
|
||||
rdpdr_server_send_core_capability_request(context);
|
||||
break;
|
||||
|
||||
case PAKID_CORE_CLIENT_CAPABILITY:
|
||||
rdpdr_server_receive_core_capability_response(context, s, header);
|
||||
rdpdr_server_send_client_id_confirm(context);
|
||||
|
||||
if (context->priv->UserLoggedOnPdu)
|
||||
rdpdr_server_send_user_logged_on(context);
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICELIST_ANNOUNCE:
|
||||
rdpdr_server_receive_device_list_announce_request(context, s, header);
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_REPLY:
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_IOREQUEST:
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_IOCOMPLETION:
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICELIST_REMOVE:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (header->Component == RDPDR_CTYP_PRN)
|
||||
{
|
||||
switch (header->PacketId)
|
||||
{
|
||||
case PAKID_PRN_CACHE_DATA:
|
||||
break;
|
||||
|
||||
case PAKID_PRN_USING_XPS:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown RDPDR_HEADER.Component: 0x%04X\n", header->Component);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void* rdpdr_server_thread(void* arg)
|
||||
{
|
||||
wStream* s;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
void* buffer;
|
||||
int position;
|
||||
HANDLE events[8];
|
||||
RDPDR_HEADER header;
|
||||
HANDLE ChannelEvent;
|
||||
DWORD BytesReturned;
|
||||
RdpdrServerContext* context;
|
||||
|
||||
context = (RdpdrServerContext*) arg;
|
||||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = NULL;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
rdpdr_server_send_announce_request(context);
|
||||
|
||||
while (1)
|
||||
{
|
||||
BytesReturned = 0;
|
||||
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Pointer(s),
|
||||
Stream_Capacity(s) - Stream_GetPosition(s), &BytesReturned))
|
||||
{
|
||||
if (BytesReturned)
|
||||
Stream_Seek(s, BytesReturned);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
}
|
||||
|
||||
if (Stream_GetPosition(s) >= RDPDR_HEADER_LENGTH)
|
||||
{
|
||||
position = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||
Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||
|
||||
Stream_SetPosition(s, position);
|
||||
|
||||
Stream_SealLength(s);
|
||||
Stream_SetPosition(s, RDPDR_HEADER_LENGTH);
|
||||
|
||||
rdpdr_server_receive_pdu(context, s, &header);
|
||||
Stream_SetPosition(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rdpdr_server_start(RdpdrServerContext* context)
|
||||
{
|
||||
context->priv->ChannelHandle = WTSVirtualChannelManagerOpenEx(context->vcm, "rdpdr", 0);
|
||||
|
||||
if (!context->priv->ChannelHandle)
|
||||
return -1;
|
||||
|
||||
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpdr_server_thread, (void*) context, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpdr_server_stop(RdpdrServerContext* context)
|
||||
{
|
||||
SetEvent(context->priv->StopEvent);
|
||||
|
||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||
CloseHandle(context->priv->Thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RdpdrServerContext* rdpdr_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
RdpdrServerContext* context;
|
||||
|
||||
context = (RdpdrServerContext*) malloc(sizeof(RdpdrServerContext));
|
||||
|
||||
if (context)
|
||||
{
|
||||
ZeroMemory(context, sizeof(RdpdrServerContext));
|
||||
|
||||
context->vcm = vcm;
|
||||
|
||||
context->Start = rdpdr_server_start;
|
||||
context->Stop = rdpdr_server_stop;
|
||||
|
||||
context->priv = (RdpdrServerPrivate*) malloc(sizeof(RdpdrServerPrivate));
|
||||
|
||||
if (context->priv)
|
||||
{
|
||||
ZeroMemory(context->priv, sizeof(RdpdrServerPrivate));
|
||||
|
||||
context->priv->VersionMajor = RDPDR_VERSION_MAJOR;
|
||||
context->priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
|
||||
context->priv->ClientId = g_ClientId++;
|
||||
|
||||
context->priv->UserLoggedOnPdu = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void rdpdr_server_context_free(RdpdrServerContext* context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
if (context->priv)
|
||||
{
|
||||
free(context->priv);
|
||||
}
|
||||
|
||||
free(context);
|
||||
}
|
||||
}
|
70
channels/rdpdr/server/rdpdr_main.h
Normal file
70
channels/rdpdr/server/rdpdr_main.h
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Device Redirection Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_RDPDR_MAIN_H
|
||||
#define FREERDP_CHANNEL_SERVER_RDPDR_MAIN_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/server/rdpdr.h>
|
||||
|
||||
struct _rdpdr_server_private
|
||||
{
|
||||
HANDLE Thread;
|
||||
HANDLE StopEvent;
|
||||
void* ChannelHandle;
|
||||
|
||||
UINT32 ClientId;
|
||||
UINT16 VersionMajor;
|
||||
UINT16 VersionMinor;
|
||||
char* ClientComputerName;
|
||||
|
||||
BOOL UserLoggedOnPdu;
|
||||
};
|
||||
|
||||
#define RDPDR_HEADER_LENGTH 4
|
||||
|
||||
struct _RDPDR_HEADER
|
||||
{
|
||||
UINT16 Component;
|
||||
UINT16 PacketId;
|
||||
};
|
||||
typedef struct _RDPDR_HEADER RDPDR_HEADER;
|
||||
|
||||
#define RDPDR_VERSION_MAJOR 0x0001
|
||||
|
||||
#define RDPDR_VERSION_MINOR_RDP50 0x0002
|
||||
#define RDPDR_VERSION_MINOR_RDP51 0x0005
|
||||
#define RDPDR_VERSION_MINOR_RDP52 0x000A
|
||||
#define RDPDR_VERSION_MINOR_RDP6X 0x000C
|
||||
|
||||
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
|
||||
|
||||
struct _RDPDR_CAPABILITY_HEADER
|
||||
{
|
||||
UINT16 CapabilityType;
|
||||
UINT16 CapabilityLength;
|
||||
UINT32 Version;
|
||||
};
|
||||
typedef struct _RDPDR_CAPABILITY_HEADER RDPDR_CAPABILITY_HEADER;
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_RDPDR_MAIN_H */
|
@ -18,7 +18,8 @@
|
||||
define_channel_server("rdpsnd")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
rdpsnd.c)
|
||||
rdpsnd_main.c
|
||||
rdpsnd_main.h)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||
|
||||
|
@ -1,560 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Server Audio Virtual Channel
|
||||
*
|
||||
* Copyright 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
typedef struct _rdpsnd_server
|
||||
{
|
||||
rdpsnd_server_context context;
|
||||
|
||||
HANDLE thread;
|
||||
HANDLE StopEvent;
|
||||
void* rdpsnd_channel;
|
||||
wStream* rdpsnd_pdu;
|
||||
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
BYTE* out_buffer;
|
||||
int out_buffer_size;
|
||||
int out_frames;
|
||||
int out_pending_frames;
|
||||
|
||||
UINT32 src_bytes_per_sample;
|
||||
UINT32 src_bytes_per_frame;
|
||||
} rdpsnd_server;
|
||||
|
||||
|
||||
static BOOL rdpsnd_server_send_formats(rdpsnd_server* rdpsnd, wStream* s)
|
||||
{
|
||||
int pos;
|
||||
UINT16 i;
|
||||
BOOL status;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_FORMATS);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
Stream_Write_UINT32(s, 0); /* dwFlags */
|
||||
Stream_Write_UINT32(s, 0); /* dwVolume */
|
||||
Stream_Write_UINT32(s, 0); /* dwPitch */
|
||||
Stream_Write_UINT16(s, 0); /* wDGramPort */
|
||||
Stream_Write_UINT16(s, rdpsnd->context.num_server_formats); /* wNumberOfFormats */
|
||||
Stream_Write_UINT8(s, rdpsnd->context.block_no); /* cLastBlockConfirmed */
|
||||
Stream_Write_UINT16(s, 0x06); /* wVersion */
|
||||
Stream_Write_UINT8(s, 0); /* bPad */
|
||||
|
||||
for (i = 0; i < rdpsnd->context.num_server_formats; i++)
|
||||
{
|
||||
Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */
|
||||
Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].nChannels); /* nChannels */
|
||||
Stream_Write_UINT32(s, rdpsnd->context.server_formats[i].nSamplesPerSec); /* nSamplesPerSec */
|
||||
|
||||
Stream_Write_UINT32(s, rdpsnd->context.server_formats[i].nSamplesPerSec *
|
||||
rdpsnd->context.server_formats[i].nChannels *
|
||||
rdpsnd->context.server_formats[i].wBitsPerSample / 8); /* nAvgBytesPerSec */
|
||||
|
||||
Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].nBlockAlign); /* nBlockAlign */
|
||||
Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].wBitsPerSample); /* wBitsPerSample */
|
||||
Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].cbSize); /* cbSize */
|
||||
|
||||
if (rdpsnd->context.server_formats[i].cbSize > 0)
|
||||
{
|
||||
Stream_Write(s, rdpsnd->context.server_formats[i].data, rdpsnd->context.server_formats[i].cbSize);
|
||||
}
|
||||
}
|
||||
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void rdpsnd_server_recv_waveconfirm(rdpsnd_server* rdpsnd, wStream* s)
|
||||
{
|
||||
//unhandled for now
|
||||
|
||||
UINT16 timestamp = 0;
|
||||
BYTE confirmBlockNum = 0;
|
||||
Stream_Read_UINT16(s, timestamp);
|
||||
Stream_Read_UINT8(s, confirmBlockNum);
|
||||
Stream_Seek_UINT8(s); // padding
|
||||
}
|
||||
|
||||
static void rdpsnd_server_recv_quality_mode(rdpsnd_server* rdpsnd, wStream* s)
|
||||
{
|
||||
//unhandled for now
|
||||
UINT16 quality;
|
||||
|
||||
Stream_Read_UINT16(s, quality);
|
||||
Stream_Seek_UINT16(s); // reserved
|
||||
|
||||
fprintf(stderr, "Client requested sound quality: %#0X\n", quality);
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_recv_formats(rdpsnd_server* rdpsnd, wStream* s)
|
||||
{
|
||||
int i, num_known_format = 0;
|
||||
UINT32 flags, vol, pitch;
|
||||
UINT16 udpPort, version;
|
||||
BYTE lastblock;
|
||||
|
||||
|
||||
Stream_Read_UINT32(s, flags); /* dwFlags */
|
||||
Stream_Read_UINT32(s, vol); /* dwVolume */
|
||||
Stream_Read_UINT32(s, pitch); /* dwPitch */
|
||||
Stream_Read_UINT16(s, udpPort); /* wDGramPort */
|
||||
Stream_Read_UINT16(s, rdpsnd->context.num_client_formats); /* wNumberOfFormats */
|
||||
Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
|
||||
Stream_Read_UINT16(s, version); /* wVersion */
|
||||
Stream_Seek_UINT8(s); /* bPad */
|
||||
|
||||
if (rdpsnd->context.num_client_formats > 0)
|
||||
{
|
||||
rdpsnd->context.client_formats = (AUDIO_FORMAT*) malloc(rdpsnd->context.num_client_formats * sizeof(AUDIO_FORMAT));
|
||||
ZeroMemory(rdpsnd->context.client_formats, sizeof(AUDIO_FORMAT));
|
||||
|
||||
for (i = 0; i < rdpsnd->context.num_client_formats; i++)
|
||||
{
|
||||
Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].wFormatTag);
|
||||
Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].nChannels);
|
||||
Stream_Read_UINT32(s, rdpsnd->context.client_formats[i].nSamplesPerSec);
|
||||
Stream_Read_UINT32(s, rdpsnd->context.client_formats[i].nAvgBytesPerSec);
|
||||
Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].nBlockAlign);
|
||||
Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].wBitsPerSample);
|
||||
Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].cbSize);
|
||||
|
||||
if (rdpsnd->context.client_formats[i].cbSize > 0)
|
||||
{
|
||||
Stream_Seek(s, rdpsnd->context.client_formats[i].cbSize);
|
||||
}
|
||||
|
||||
if (rdpsnd->context.client_formats[i].wFormatTag != 0)
|
||||
{
|
||||
//lets call this a known format
|
||||
//TODO: actually look through our own list of known formats
|
||||
num_known_format++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_known_format == 0)
|
||||
{
|
||||
fprintf(stderr, "Client doesnt support any known formats!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void* rdpsnd_server_thread_func(void* arg)
|
||||
{
|
||||
void* fd;
|
||||
wStream* s;
|
||||
void* buffer;
|
||||
DWORD status;
|
||||
BYTE msgType;
|
||||
UINT16 BodySize;
|
||||
HANDLE events[2];
|
||||
UINT32 bytes_returned = 0;
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) arg;
|
||||
|
||||
events[0] = rdpsnd->StopEvent;
|
||||
|
||||
if (WTSVirtualChannelQuery(rdpsnd->rdpsnd_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE)
|
||||
{
|
||||
fd = *((void**) buffer);
|
||||
WTSFreeMemory(buffer);
|
||||
|
||||
events[1] = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd);
|
||||
}
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
rdpsnd_server_send_formats(rdpsnd, s);
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(2, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(rdpsnd->StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, Stream_Buffer(s),
|
||||
Stream_Capacity(s), &bytes_returned) == FALSE)
|
||||
{
|
||||
if (bytes_returned == 0)
|
||||
break;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, (int) bytes_returned);
|
||||
|
||||
if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, Stream_Buffer(s),
|
||||
Stream_Capacity(s), &bytes_returned) == FALSE)
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, msgType);
|
||||
Stream_Seek_UINT8(s); /* bPad */
|
||||
Stream_Read_UINT16(s, BodySize);
|
||||
|
||||
switch (msgType)
|
||||
{
|
||||
case SNDC_WAVECONFIRM:
|
||||
rdpsnd_server_recv_waveconfirm(rdpsnd, s);
|
||||
break;
|
||||
|
||||
case SNDC_QUALITYMODE:
|
||||
rdpsnd_server_recv_quality_mode(rdpsnd, s);
|
||||
break;
|
||||
case SNDC_FORMATS:
|
||||
if (rdpsnd_server_recv_formats(rdpsnd, s))
|
||||
{
|
||||
IFCALL(rdpsnd->context.Activated, &rdpsnd->context);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "UNKOWN MESSAGE TYPE!! (%#0X)\n\n", msgType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_initialize(rdpsnd_server_context* context)
|
||||
{
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
|
||||
|
||||
rdpsnd->rdpsnd_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpsnd", 0);
|
||||
|
||||
if (rdpsnd->rdpsnd_channel != NULL)
|
||||
{
|
||||
rdpsnd->rdpsnd_pdu = Stream_New(NULL, 4096);
|
||||
|
||||
rdpsnd->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
rdpsnd->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpsnd_server_thread_func, (void*) rdpsnd, 0, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void rdpsnd_server_select_format(rdpsnd_server_context* context, int client_format_index)
|
||||
{
|
||||
int bs;
|
||||
int out_buffer_size;
|
||||
AUDIO_FORMAT *format;
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
|
||||
|
||||
if (client_format_index < 0 || client_format_index >= context->num_client_formats)
|
||||
{
|
||||
fprintf(stderr, "rdpsnd_server_select_format: index %d is not correct.\n", client_format_index);
|
||||
return;
|
||||
}
|
||||
|
||||
rdpsnd->src_bytes_per_sample = context->src_format.wBitsPerSample / 8;
|
||||
rdpsnd->src_bytes_per_frame = rdpsnd->src_bytes_per_sample * context->src_format.nChannels;
|
||||
|
||||
context->selected_client_format = client_format_index;
|
||||
format = &context->client_formats[client_format_index];
|
||||
|
||||
if (format->nSamplesPerSec == 0)
|
||||
{
|
||||
fprintf(stderr, "Invalid Client Sound Format!!\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM)
|
||||
{
|
||||
bs = (format->nBlockAlign - 4 * format->nChannels) * 4;
|
||||
rdpsnd->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2);
|
||||
}
|
||||
else if (format->wFormatTag == WAVE_FORMAT_ADPCM)
|
||||
{
|
||||
bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
|
||||
rdpsnd->out_frames = bs * 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdpsnd->out_frames = 0x4000 / rdpsnd->src_bytes_per_frame;
|
||||
}
|
||||
|
||||
if (format->nSamplesPerSec != context->src_format.nSamplesPerSec)
|
||||
{
|
||||
rdpsnd->out_frames = (rdpsnd->out_frames * context->src_format.nSamplesPerSec + format->nSamplesPerSec - 100) / format->nSamplesPerSec;
|
||||
}
|
||||
rdpsnd->out_pending_frames = 0;
|
||||
|
||||
out_buffer_size = rdpsnd->out_frames * rdpsnd->src_bytes_per_frame;
|
||||
|
||||
if (rdpsnd->out_buffer_size < out_buffer_size)
|
||||
{
|
||||
rdpsnd->out_buffer = (BYTE*) realloc(rdpsnd->out_buffer, out_buffer_size);
|
||||
rdpsnd->out_buffer_size = out_buffer_size;
|
||||
}
|
||||
|
||||
freerdp_dsp_context_reset_adpcm(rdpsnd->dsp_context);
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_send_audio_pdu(rdpsnd_server* rdpsnd)
|
||||
{
|
||||
int size;
|
||||
BYTE* src;
|
||||
int frames;
|
||||
int fill_size;
|
||||
BOOL status;
|
||||
AUDIO_FORMAT* format;
|
||||
int tbytes_per_frame;
|
||||
wStream* s = rdpsnd->rdpsnd_pdu;
|
||||
|
||||
format = &rdpsnd->context.client_formats[rdpsnd->context.selected_client_format];
|
||||
tbytes_per_frame = format->nChannels * rdpsnd->src_bytes_per_sample;
|
||||
|
||||
if ((format->nSamplesPerSec == rdpsnd->context.src_format.nSamplesPerSec) &&
|
||||
(format->nChannels == rdpsnd->context.src_format.nChannels))
|
||||
{
|
||||
src = rdpsnd->out_buffer;
|
||||
frames = rdpsnd->out_pending_frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdpsnd->dsp_context->resample(rdpsnd->dsp_context, rdpsnd->out_buffer, rdpsnd->src_bytes_per_sample,
|
||||
rdpsnd->context.src_format.nChannels, rdpsnd->context.src_format.nSamplesPerSec, rdpsnd->out_pending_frames,
|
||||
format->nChannels, format->nSamplesPerSec);
|
||||
frames = rdpsnd->dsp_context->resampled_frames;
|
||||
src = rdpsnd->dsp_context->resampled_buffer;
|
||||
}
|
||||
size = frames * tbytes_per_frame;
|
||||
|
||||
if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM)
|
||||
{
|
||||
rdpsnd->dsp_context->encode_ima_adpcm(rdpsnd->dsp_context,
|
||||
src, size, format->nChannels, format->nBlockAlign);
|
||||
src = rdpsnd->dsp_context->adpcm_buffer;
|
||||
size = rdpsnd->dsp_context->adpcm_size;
|
||||
}
|
||||
else if (format->wFormatTag == WAVE_FORMAT_ADPCM)
|
||||
{
|
||||
rdpsnd->dsp_context->encode_ms_adpcm(rdpsnd->dsp_context,
|
||||
src, size, format->nChannels, format->nBlockAlign);
|
||||
src = rdpsnd->dsp_context->adpcm_buffer;
|
||||
size = rdpsnd->dsp_context->adpcm_size;
|
||||
}
|
||||
|
||||
rdpsnd->context.block_no = (rdpsnd->context.block_no + 1) % 256;
|
||||
|
||||
/* Fill to nBlockAlign for the last audio packet */
|
||||
|
||||
fill_size = 0;
|
||||
|
||||
if ((format->wFormatTag == WAVE_FORMAT_DVI_ADPCM || format->wFormatTag == WAVE_FORMAT_ADPCM) &&
|
||||
(rdpsnd->out_pending_frames < rdpsnd->out_frames) && ((size % format->nBlockAlign) != 0))
|
||||
{
|
||||
fill_size = format->nBlockAlign - (size % format->nBlockAlign);
|
||||
}
|
||||
|
||||
/* WaveInfo PDU */
|
||||
Stream_SetPosition(s, 0);
|
||||
Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
|
||||
Stream_Write_UINT8(s, 0); /* bPad */
|
||||
Stream_Write_UINT16(s, size + fill_size + 8); /* BodySize */
|
||||
|
||||
Stream_Write_UINT16(s, 0); /* wTimeStamp */
|
||||
Stream_Write_UINT16(s, rdpsnd->context.selected_client_format); /* wFormatNo */
|
||||
Stream_Write_UINT8(s, rdpsnd->context.block_no); /* cBlockNo */
|
||||
Stream_Seek(s, 3); /* bPad */
|
||||
Stream_Write(s, src, 4);
|
||||
|
||||
WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
/* Wave PDU */
|
||||
Stream_EnsureRemainingCapacity(s, size + fill_size);
|
||||
Stream_Write_UINT32(s, 0); /* bPad */
|
||||
Stream_Write(s, src + 4, size - 4);
|
||||
|
||||
if (fill_size > 0)
|
||||
Stream_Zero(s, fill_size);
|
||||
|
||||
status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
rdpsnd->out_pending_frames = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_send_samples(rdpsnd_server_context* context, const void* buf, int nframes)
|
||||
{
|
||||
int cframes;
|
||||
int cframesize;
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
|
||||
|
||||
if (rdpsnd->context.selected_client_format < 0)
|
||||
return FALSE;
|
||||
|
||||
while (nframes > 0)
|
||||
{
|
||||
cframes = MIN(nframes, rdpsnd->out_frames - rdpsnd->out_pending_frames);
|
||||
cframesize = cframes * rdpsnd->src_bytes_per_frame;
|
||||
|
||||
CopyMemory(rdpsnd->out_buffer + (rdpsnd->out_pending_frames * rdpsnd->src_bytes_per_frame), buf, cframesize);
|
||||
buf = (BYTE*) buf + cframesize;
|
||||
nframes -= cframes;
|
||||
rdpsnd->out_pending_frames += cframes;
|
||||
|
||||
if (rdpsnd->out_pending_frames >= rdpsnd->out_frames)
|
||||
{
|
||||
if (!rdpsnd_server_send_audio_pdu(rdpsnd))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_set_volume(rdpsnd_server_context* context, int left, int right)
|
||||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
|
||||
wStream* s = rdpsnd->rdpsnd_pdu;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_SETVOLUME);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
Stream_Write_UINT16(s, left);
|
||||
Stream_Write_UINT16(s, right);
|
||||
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_close(rdpsnd_server_context* context)
|
||||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
|
||||
wStream* s = rdpsnd->rdpsnd_pdu;
|
||||
|
||||
if (rdpsnd->context.selected_client_format < 0)
|
||||
return FALSE;
|
||||
|
||||
if (rdpsnd->out_pending_frames > 0)
|
||||
{
|
||||
if (!rdpsnd_server_send_audio_pdu(rdpsnd))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rdpsnd->context.selected_client_format = -1;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_CLOSE);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
rdpsnd_server_context* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
rdpsnd_server* rdpsnd;
|
||||
|
||||
rdpsnd = (rdpsnd_server*) malloc(sizeof(rdpsnd_server));
|
||||
ZeroMemory(rdpsnd, sizeof(rdpsnd_server));
|
||||
|
||||
rdpsnd->context.vcm = vcm;
|
||||
rdpsnd->context.selected_client_format = -1;
|
||||
rdpsnd->context.Initialize = rdpsnd_server_initialize;
|
||||
rdpsnd->context.SelectFormat = rdpsnd_server_select_format;
|
||||
rdpsnd->context.SendSamples = rdpsnd_server_send_samples;
|
||||
rdpsnd->context.SetVolume = rdpsnd_server_set_volume;
|
||||
rdpsnd->context.Close = rdpsnd_server_close;
|
||||
|
||||
rdpsnd->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
return (rdpsnd_server_context*) rdpsnd;
|
||||
}
|
||||
|
||||
void rdpsnd_server_context_free(rdpsnd_server_context* context)
|
||||
{
|
||||
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
|
||||
|
||||
SetEvent(rdpsnd->StopEvent);
|
||||
WaitForSingleObject(rdpsnd->thread, INFINITE);
|
||||
|
||||
if (rdpsnd->rdpsnd_channel)
|
||||
WTSVirtualChannelClose(rdpsnd->rdpsnd_channel);
|
||||
|
||||
if (rdpsnd->rdpsnd_pdu)
|
||||
Stream_Free(rdpsnd->rdpsnd_pdu, TRUE);
|
||||
|
||||
if (rdpsnd->out_buffer)
|
||||
free(rdpsnd->out_buffer);
|
||||
|
||||
if (rdpsnd->dsp_context)
|
||||
freerdp_dsp_context_free(rdpsnd->dsp_context);
|
||||
|
||||
if (rdpsnd->context.client_formats)
|
||||
free(rdpsnd->context.client_formats);
|
||||
|
||||
free(rdpsnd);
|
||||
}
|
572
channels/rdpsnd/server/rdpsnd_main.c
Normal file
572
channels/rdpsnd/server/rdpsnd_main.c
Normal file
@ -0,0 +1,572 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Server Audio Virtual Channel
|
||||
*
|
||||
* Copyright 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "rdpsnd_main.h"
|
||||
|
||||
static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
||||
{
|
||||
int pos;
|
||||
UINT16 i;
|
||||
BOOL status;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_FORMATS);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
Stream_Write_UINT32(s, 0); /* dwFlags */
|
||||
Stream_Write_UINT32(s, 0); /* dwVolume */
|
||||
Stream_Write_UINT32(s, 0); /* dwPitch */
|
||||
Stream_Write_UINT16(s, 0); /* wDGramPort */
|
||||
Stream_Write_UINT16(s, context->num_server_formats); /* wNumberOfFormats */
|
||||
Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */
|
||||
Stream_Write_UINT16(s, 0x06); /* wVersion */
|
||||
Stream_Write_UINT8(s, 0); /* bPad */
|
||||
|
||||
for (i = 0; i < context->num_server_formats; i++)
|
||||
{
|
||||
Stream_Write_UINT16(s, context->server_formats[i].wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */
|
||||
Stream_Write_UINT16(s, context->server_formats[i].nChannels); /* nChannels */
|
||||
Stream_Write_UINT32(s, context->server_formats[i].nSamplesPerSec); /* nSamplesPerSec */
|
||||
|
||||
Stream_Write_UINT32(s, context->server_formats[i].nSamplesPerSec *
|
||||
context->server_formats[i].nChannels *
|
||||
context->server_formats[i].wBitsPerSample / 8); /* nAvgBytesPerSec */
|
||||
|
||||
Stream_Write_UINT16(s, context->server_formats[i].nBlockAlign); /* nBlockAlign */
|
||||
Stream_Write_UINT16(s, context->server_formats[i].wBitsPerSample); /* wBitsPerSample */
|
||||
Stream_Write_UINT16(s, context->server_formats[i].cbSize); /* cbSize */
|
||||
|
||||
if (context->server_formats[i].cbSize > 0)
|
||||
{
|
||||
Stream_Write(s, context->server_formats[i].data, context->server_formats[i].cbSize);
|
||||
}
|
||||
}
|
||||
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s)
|
||||
{
|
||||
UINT16 timestamp = 0;
|
||||
BYTE confirmBlockNum = 0;
|
||||
Stream_Read_UINT16(s, timestamp);
|
||||
Stream_Read_UINT8(s, confirmBlockNum);
|
||||
Stream_Seek_UINT8(s);
|
||||
}
|
||||
|
||||
static void rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s)
|
||||
{
|
||||
UINT16 quality;
|
||||
|
||||
Stream_Read_UINT16(s, quality);
|
||||
Stream_Seek_UINT16(s); // reserved
|
||||
|
||||
fprintf(stderr, "Client requested sound quality: %#0X\n", quality);
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
|
||||
{
|
||||
int i, num_known_format = 0;
|
||||
UINT32 flags, vol, pitch;
|
||||
UINT16 udpPort, version;
|
||||
BYTE lastblock;
|
||||
|
||||
Stream_Read_UINT32(s, flags); /* dwFlags */
|
||||
Stream_Read_UINT32(s, vol); /* dwVolume */
|
||||
Stream_Read_UINT32(s, pitch); /* dwPitch */
|
||||
Stream_Read_UINT16(s, udpPort); /* wDGramPort */
|
||||
Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
|
||||
Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
|
||||
Stream_Read_UINT16(s, version); /* wVersion */
|
||||
Stream_Seek_UINT8(s); /* bPad */
|
||||
|
||||
if (context->num_client_formats > 0)
|
||||
{
|
||||
context->client_formats = (AUDIO_FORMAT*) malloc(context->num_client_formats * sizeof(AUDIO_FORMAT));
|
||||
ZeroMemory(context->client_formats, sizeof(AUDIO_FORMAT));
|
||||
|
||||
for (i = 0; i < context->num_client_formats; i++)
|
||||
{
|
||||
Stream_Read_UINT16(s, context->client_formats[i].wFormatTag);
|
||||
Stream_Read_UINT16(s, context->client_formats[i].nChannels);
|
||||
Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec);
|
||||
Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec);
|
||||
Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign);
|
||||
Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample);
|
||||
Stream_Read_UINT16(s, context->client_formats[i].cbSize);
|
||||
|
||||
if (context->client_formats[i].cbSize > 0)
|
||||
{
|
||||
Stream_Seek(s, context->client_formats[i].cbSize);
|
||||
}
|
||||
|
||||
if (context->client_formats[i].wFormatTag != 0)
|
||||
{
|
||||
//lets call this a known format
|
||||
//TODO: actually look through our own list of known formats
|
||||
num_known_format++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_known_format == 0)
|
||||
{
|
||||
fprintf(stderr, "Client doesn't support any known formats!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void* rdpsnd_server_thread(void* arg)
|
||||
{
|
||||
wStream* s;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
void* buffer;
|
||||
BYTE msgType;
|
||||
UINT16 BodySize;
|
||||
HANDLE events[8];
|
||||
HANDLE ChannelEvent;
|
||||
DWORD BytesReturned;
|
||||
RdpsndServerContext* context;
|
||||
|
||||
context = (RdpsndServerContext*) arg;
|
||||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = NULL;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
rdpsnd_server_send_formats(context, s);
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
|
||||
{
|
||||
if (BytesReturned)
|
||||
Stream_Seek(s, BytesReturned);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!BytesReturned)
|
||||
break;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, msgType);
|
||||
Stream_Seek_UINT8(s); /* bPad */
|
||||
Stream_Read_UINT16(s, BodySize);
|
||||
|
||||
switch (msgType)
|
||||
{
|
||||
case SNDC_WAVECONFIRM:
|
||||
rdpsnd_server_recv_waveconfirm(context, s);
|
||||
break;
|
||||
|
||||
case SNDC_QUALITYMODE:
|
||||
rdpsnd_server_recv_quality_mode(context, s);
|
||||
break;
|
||||
|
||||
case SNDC_FORMATS:
|
||||
if (rdpsnd_server_recv_formats(context, s))
|
||||
{
|
||||
IFCALL(context->Activated, context);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "UNKOWN MESSAGE TYPE!! (%#0X)\n\n", msgType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_initialize(RdpsndServerContext* context)
|
||||
{
|
||||
context->Start(context);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void rdpsnd_server_select_format(RdpsndServerContext* context, int client_format_index)
|
||||
{
|
||||
int bs;
|
||||
int out_buffer_size;
|
||||
AUDIO_FORMAT *format;
|
||||
|
||||
if (client_format_index < 0 || client_format_index >= context->num_client_formats)
|
||||
{
|
||||
fprintf(stderr, "rdpsnd_server_select_format: index %d is not correct.\n", client_format_index);
|
||||
return;
|
||||
}
|
||||
|
||||
context->priv->src_bytes_per_sample = context->src_format.wBitsPerSample / 8;
|
||||
context->priv->src_bytes_per_frame = context->priv->src_bytes_per_sample * context->src_format.nChannels;
|
||||
|
||||
context->selected_client_format = client_format_index;
|
||||
format = &context->client_formats[client_format_index];
|
||||
|
||||
if (format->nSamplesPerSec == 0)
|
||||
{
|
||||
fprintf(stderr, "Invalid Client Sound Format!!\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM)
|
||||
{
|
||||
bs = (format->nBlockAlign - 4 * format->nChannels) * 4;
|
||||
context->priv->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2);
|
||||
}
|
||||
else if (format->wFormatTag == WAVE_FORMAT_ADPCM)
|
||||
{
|
||||
bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
|
||||
context->priv->out_frames = bs * 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->priv->out_frames = 0x4000 / context->priv->src_bytes_per_frame;
|
||||
}
|
||||
|
||||
if (format->nSamplesPerSec != context->src_format.nSamplesPerSec)
|
||||
{
|
||||
context->priv->out_frames = (context->priv->out_frames * context->src_format.nSamplesPerSec + format->nSamplesPerSec - 100) / format->nSamplesPerSec;
|
||||
}
|
||||
context->priv->out_pending_frames = 0;
|
||||
|
||||
out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
|
||||
|
||||
if (context->priv->out_buffer_size < out_buffer_size)
|
||||
{
|
||||
context->priv->out_buffer = (BYTE*) realloc(context->priv->out_buffer, out_buffer_size);
|
||||
context->priv->out_buffer_size = out_buffer_size;
|
||||
}
|
||||
|
||||
freerdp_dsp_context_reset_adpcm(context->priv->dsp_context);
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
||||
{
|
||||
int size;
|
||||
BYTE* src;
|
||||
int frames;
|
||||
int fill_size;
|
||||
BOOL status;
|
||||
AUDIO_FORMAT* format;
|
||||
int tbytes_per_frame;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
format = &context->client_formats[context->selected_client_format];
|
||||
tbytes_per_frame = format->nChannels * context->priv->src_bytes_per_sample;
|
||||
|
||||
if ((format->nSamplesPerSec == context->src_format.nSamplesPerSec) &&
|
||||
(format->nChannels == context->src_format.nChannels))
|
||||
{
|
||||
src = context->priv->out_buffer;
|
||||
frames = context->priv->out_pending_frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->priv->dsp_context->resample(context->priv->dsp_context, context->priv->out_buffer,
|
||||
context->priv->src_bytes_per_sample, context->src_format.nChannels,
|
||||
context->src_format.nSamplesPerSec, context->priv->out_pending_frames,
|
||||
format->nChannels, format->nSamplesPerSec);
|
||||
frames = context->priv->dsp_context->resampled_frames;
|
||||
src = context->priv->dsp_context->resampled_buffer;
|
||||
}
|
||||
size = frames * tbytes_per_frame;
|
||||
|
||||
if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM)
|
||||
{
|
||||
context->priv->dsp_context->encode_ima_adpcm(context->priv->dsp_context,
|
||||
src, size, format->nChannels, format->nBlockAlign);
|
||||
src = context->priv->dsp_context->adpcm_buffer;
|
||||
size = context->priv->dsp_context->adpcm_size;
|
||||
}
|
||||
else if (format->wFormatTag == WAVE_FORMAT_ADPCM)
|
||||
{
|
||||
context->priv->dsp_context->encode_ms_adpcm(context->priv->dsp_context,
|
||||
src, size, format->nChannels, format->nBlockAlign);
|
||||
src = context->priv->dsp_context->adpcm_buffer;
|
||||
size = context->priv->dsp_context->adpcm_size;
|
||||
}
|
||||
|
||||
context->block_no = (context->block_no + 1) % 256;
|
||||
|
||||
/* Fill to nBlockAlign for the last audio packet */
|
||||
|
||||
fill_size = 0;
|
||||
|
||||
if ((format->wFormatTag == WAVE_FORMAT_DVI_ADPCM || format->wFormatTag == WAVE_FORMAT_ADPCM) &&
|
||||
(context->priv->out_pending_frames < context->priv->out_frames) && ((size % format->nBlockAlign) != 0))
|
||||
{
|
||||
fill_size = format->nBlockAlign - (size % format->nBlockAlign);
|
||||
}
|
||||
|
||||
/* WaveInfo PDU */
|
||||
Stream_SetPosition(s, 0);
|
||||
Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
|
||||
Stream_Write_UINT8(s, 0); /* bPad */
|
||||
Stream_Write_UINT16(s, size + fill_size + 8); /* BodySize */
|
||||
|
||||
Stream_Write_UINT16(s, 0); /* wTimeStamp */
|
||||
Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
|
||||
Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
|
||||
Stream_Seek(s, 3); /* bPad */
|
||||
Stream_Write(s, src, 4);
|
||||
|
||||
WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
/* Wave PDU */
|
||||
Stream_EnsureRemainingCapacity(s, size + fill_size);
|
||||
Stream_Write_UINT32(s, 0); /* bPad */
|
||||
Stream_Write(s, src + 4, size - 4);
|
||||
|
||||
if (fill_size > 0)
|
||||
Stream_Zero(s, fill_size);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
context->priv->out_pending_frames = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf, int nframes)
|
||||
{
|
||||
int cframes;
|
||||
int cframesize;
|
||||
|
||||
if (context->selected_client_format < 0)
|
||||
return FALSE;
|
||||
|
||||
while (nframes > 0)
|
||||
{
|
||||
cframes = MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
|
||||
cframesize = cframes * context->priv->src_bytes_per_frame;
|
||||
|
||||
CopyMemory(context->priv->out_buffer +
|
||||
(context->priv->out_pending_frames * context->priv->src_bytes_per_frame), buf, cframesize);
|
||||
buf = (BYTE*) buf + cframesize;
|
||||
nframes -= cframes;
|
||||
context->priv->out_pending_frames += cframes;
|
||||
|
||||
if (context->priv->out_pending_frames >= context->priv->out_frames)
|
||||
{
|
||||
if (!rdpsnd_server_send_audio_pdu(context))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int right)
|
||||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_SETVOLUME);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
Stream_Write_UINT16(s, left);
|
||||
Stream_Write_UINT16(s, right);
|
||||
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
||||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
if (context->selected_client_format < 0)
|
||||
return FALSE;
|
||||
|
||||
if (context->priv->out_pending_frames > 0)
|
||||
{
|
||||
if (!rdpsnd_server_send_audio_pdu(context))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
context->selected_client_format = -1;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_CLOSE);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int rdpsnd_server_start(RdpsndServerContext* context)
|
||||
{
|
||||
context->priv->ChannelHandle = WTSVirtualChannelManagerOpenEx(context->vcm, "rdpsnd", 0);
|
||||
|
||||
if (!context->priv->ChannelHandle)
|
||||
return -1;
|
||||
|
||||
context->priv->rdpsnd_pdu = Stream_New(NULL, 4096);
|
||||
|
||||
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpsnd_server_stop(RdpsndServerContext* context)
|
||||
{
|
||||
SetEvent(context->priv->StopEvent);
|
||||
|
||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||
CloseHandle(context->priv->Thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RdpsndServerContext* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
RdpsndServerContext* context;
|
||||
|
||||
context = (RdpsndServerContext*) malloc(sizeof(RdpsndServerContext));
|
||||
|
||||
if (context)
|
||||
{
|
||||
ZeroMemory(context, sizeof(RdpsndServerContext));
|
||||
|
||||
context->vcm = vcm;
|
||||
|
||||
context->Start = rdpsnd_server_start;
|
||||
context->Stop = rdpsnd_server_stop;
|
||||
|
||||
context->selected_client_format = -1;
|
||||
context->Initialize = rdpsnd_server_initialize;
|
||||
context->SelectFormat = rdpsnd_server_select_format;
|
||||
context->SendSamples = rdpsnd_server_send_samples;
|
||||
context->SetVolume = rdpsnd_server_set_volume;
|
||||
context->Close = rdpsnd_server_close;
|
||||
|
||||
context->priv = (RdpsndServerPrivate*) malloc(sizeof(RdpsndServerPrivate));
|
||||
|
||||
if (context->priv)
|
||||
{
|
||||
ZeroMemory(context->priv, sizeof(RdpsndServerPrivate));
|
||||
|
||||
context->priv->dsp_context = freerdp_dsp_context_new();
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void rdpsnd_server_context_free(RdpsndServerContext* context)
|
||||
{
|
||||
SetEvent(context->priv->StopEvent);
|
||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||
|
||||
if (context->priv->ChannelHandle)
|
||||
WTSVirtualChannelClose(context->priv->ChannelHandle);
|
||||
|
||||
if (context->priv->rdpsnd_pdu)
|
||||
Stream_Free(context->priv->rdpsnd_pdu, TRUE);
|
||||
|
||||
if (context->priv->out_buffer)
|
||||
free(context->priv->out_buffer);
|
||||
|
||||
if (context->priv->dsp_context)
|
||||
freerdp_dsp_context_free(context->priv->dsp_context);
|
||||
|
||||
if (context->client_formats)
|
||||
free(context->client_formats);
|
||||
|
||||
free(context);
|
||||
}
|
48
channels/rdpsnd/server/rdpsnd_main.h
Normal file
48
channels/rdpsnd/server/rdpsnd_main.h
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Server Audio Virtual Channel
|
||||
*
|
||||
* Copyright 2012 Vic Lee
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_RDPSND_MAIN_H
|
||||
#define FREERDP_CHANNEL_SERVER_RDPSND_MAIN_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
|
||||
struct _rdpsnd_server_private
|
||||
{
|
||||
HANDLE Thread;
|
||||
HANDLE StopEvent;
|
||||
void* ChannelHandle;
|
||||
|
||||
wStream* rdpsnd_pdu;
|
||||
BYTE* out_buffer;
|
||||
int out_buffer_size;
|
||||
int out_frames;
|
||||
int out_pending_frames;
|
||||
UINT32 src_bytes_per_sample;
|
||||
UINT32 src_bytes_per_frame;
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_RDPSND_MAIN_H */
|
@ -42,6 +42,9 @@
|
||||
|
||||
#include <freerdp/server/audin.h>
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include <freerdp/server/cliprdr.h>
|
||||
#include <freerdp/server/rdpdr.h>
|
||||
#include <freerdp/server/drdynvc.h>
|
||||
|
||||
void freerdp_channels_dummy()
|
||||
{
|
||||
@ -50,6 +53,15 @@ void freerdp_channels_dummy()
|
||||
|
||||
rdpsnd_server_context_new(NULL);
|
||||
rdpsnd_server_context_free(NULL);
|
||||
|
||||
cliprdr_server_context_new(NULL);
|
||||
cliprdr_server_context_free(NULL);
|
||||
|
||||
rdpdr_server_context_new(NULL);
|
||||
rdpdr_server_context_free(NULL);
|
||||
|
||||
drdynvc_server_context_new(NULL);
|
||||
drdynvc_server_context_free(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +432,7 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
|
||||
|
||||
vcm = (WTSVirtualChannelManager*) malloc(sizeof(WTSVirtualChannelManager));
|
||||
|
||||
if (vcm != NULL)
|
||||
if (vcm)
|
||||
{
|
||||
ZeroMemory(vcm, sizeof(WTSVirtualChannelManager));
|
||||
|
||||
@ -470,8 +482,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;
|
||||
|
||||
@ -507,13 +518,13 @@ BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
|
||||
/* Initialize drdynvc channel once and only once. */
|
||||
vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
|
||||
|
||||
channel = WTSVirtualChannelOpenEx(vcm, "drdynvc", 0);
|
||||
channel = WTSVirtualChannelManagerOpenEx(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);
|
||||
WTSVirtualChannelWrite(channel, (PCHAR) &dynvc_caps, sizeof(dynvc_caps), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,10 +550,12 @@ BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
|
||||
return result;
|
||||
}
|
||||
|
||||
void* WTSVirtualChannelOpenEx(
|
||||
/* __in */ WTSVirtualChannelManager* vcm,
|
||||
/* __in */ const char* pVirtualName,
|
||||
/* __in */ UINT32 flags)
|
||||
HANDLE WTSVirtualChannelManagerGetEventHandle(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
return vcm->send_event;
|
||||
}
|
||||
|
||||
HANDLE WTSVirtualChannelManagerOpenEx(WTSVirtualChannelManager* vcm, LPSTR pVirtualName, DWORD flags)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
@ -592,7 +605,7 @@ void* WTSVirtualChannelOpenEx(
|
||||
|
||||
s = Stream_New(NULL, 64);
|
||||
wts_write_drdynvc_create_request(s, channel->channel_id, pVirtualName);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
DEBUG_DVC("ChannelId %d.%s (total %d)", channel->channel_id, pVirtualName, list_size(vcm->dvc_channel_list));
|
||||
@ -646,11 +659,7 @@ void* WTSVirtualChannelOpenEx(
|
||||
return channel;
|
||||
}
|
||||
|
||||
BOOL WTSVirtualChannelQuery(
|
||||
/* __in */ void* hChannelHandle,
|
||||
/* __in */ WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||
/* __out */ void** ppBuffer,
|
||||
/* __out */ UINT32* pBytesReturned)
|
||||
BOOL WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer, DWORD* pBytesReturned)
|
||||
{
|
||||
void* pfd;
|
||||
BOOL bval;
|
||||
@ -659,6 +668,7 @@ BOOL WTSVirtualChannelQuery(
|
||||
BOOL result = FALSE;
|
||||
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
|
||||
ZeroMemory(fds, sizeof(fds));
|
||||
|
||||
switch (WtsVirtualClass)
|
||||
{
|
||||
case WTSVirtualFileHandle:
|
||||
@ -677,6 +687,13 @@ BOOL WTSVirtualChannelQuery(
|
||||
result = TRUE;
|
||||
break;
|
||||
|
||||
case WTSVirtualEventHandle:
|
||||
*ppBuffer = malloc(sizeof(HANDLE));
|
||||
CopyMemory(*ppBuffer, &(channel->receive_event), sizeof(HANDLE));
|
||||
*pBytesReturned = sizeof(void*);
|
||||
result = TRUE;
|
||||
break;
|
||||
|
||||
case WTSVirtualChannelReady:
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
|
||||
{
|
||||
@ -715,25 +732,19 @@ BOOL WTSVirtualChannelQuery(
|
||||
return result;
|
||||
}
|
||||
|
||||
void WTSFreeMemory(
|
||||
/* __in */ void* pMemory)
|
||||
VOID WTSFreeMemory(PVOID pMemory)
|
||||
{
|
||||
free(pMemory);
|
||||
}
|
||||
|
||||
BOOL WTSVirtualChannelRead(
|
||||
/* __in */ void* hChannelHandle,
|
||||
/* __in */ UINT32 TimeOut,
|
||||
/* __out */ BYTE* Buffer,
|
||||
/* __in */ UINT32 BufferSize,
|
||||
/* __out */ UINT32* pBytesRead)
|
||||
BOOL WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead)
|
||||
{
|
||||
wts_data_item* item;
|
||||
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
|
||||
|
||||
item = (wts_data_item*) list_peek(channel->receive_queue);
|
||||
|
||||
if (item == NULL)
|
||||
if (!item)
|
||||
{
|
||||
ResetEvent(channel->receive_event);
|
||||
*pBytesRead = 0;
|
||||
@ -755,16 +766,12 @@ BOOL WTSVirtualChannelRead(
|
||||
ReleaseMutex(channel->mutex);
|
||||
|
||||
CopyMemory(Buffer, item->buffer, item->length);
|
||||
wts_data_item_free(item) ;
|
||||
wts_data_item_free(item);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WTSVirtualChannelWrite(
|
||||
/* __in */ void* hChannelHandle,
|
||||
/* __in */ BYTE* Buffer,
|
||||
/* __in */ UINT32 Length,
|
||||
/* __out */ UINT32* pBytesWritten)
|
||||
BOOL WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length, PULONG pBytesWritten)
|
||||
{
|
||||
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
|
||||
wts_data_item* item;
|
||||
@ -774,7 +781,7 @@ BOOL WTSVirtualChannelWrite(
|
||||
int first;
|
||||
UINT32 written;
|
||||
|
||||
if (channel == NULL)
|
||||
if (!channel)
|
||||
return FALSE;
|
||||
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
|
||||
@ -841,8 +848,7 @@ BOOL WTSVirtualChannelWrite(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WTSVirtualChannelClose(
|
||||
/* __in */ void* hChannelHandle)
|
||||
BOOL WTSVirtualChannelClose(HANDLE hChannelHandle)
|
||||
{
|
||||
wStream* s;
|
||||
wts_data_item* item;
|
||||
@ -868,7 +874,7 @@ BOOL WTSVirtualChannelClose(
|
||||
{
|
||||
s = Stream_New(NULL, 8);
|
||||
wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channel_id);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ BOOL wf_post_connect(freerdp* instance)
|
||||
if (settings->RemoteFxCodec)
|
||||
{
|
||||
wfc->tile = wf_image_new(wfc, 64, 64, 32, NULL);
|
||||
wfc->rfx_context = rfx_context_new();
|
||||
wfc->rfx_context = rfx_context_new(FALSE);
|
||||
}
|
||||
|
||||
if (settings->NSCodec)
|
||||
|
@ -92,8 +92,6 @@ if(WITH_MANPAGES)
|
||||
MODULE freerdp
|
||||
MODULES freerdp-core freerdp-utils)
|
||||
|
||||
message(WARNING "GAD_LIBS: ${GAD_LIBS}")
|
||||
|
||||
target_link_libraries(generate_argument_docbook ${GAD_LIBS})
|
||||
|
||||
add_custom_command(OUTPUT xfreerdp.1
|
||||
|
@ -908,7 +908,7 @@ BOOL xf_post_connect(freerdp* instance)
|
||||
|
||||
if (instance->settings->RemoteFxCodec)
|
||||
{
|
||||
rfx_context = (void*) rfx_context_new();
|
||||
rfx_context = (void*) rfx_context_new(FALSE);
|
||||
xfc->rfx_context = rfx_context;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#cmakedefine HAVE_EVENTFD_H
|
||||
#cmakedefine HAVE_TIMERFD_H
|
||||
#cmakedefine HAVE_TM_GMTOFF
|
||||
#cmakedefine HAVE_AIO_H
|
||||
|
||||
|
||||
/* Options */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#ifndef FREERDP_CHANNEL_RDPDR_H
|
||||
#define FREERDP_CHANNEL_RDPDR_H
|
||||
|
||||
#include <winpr/nt.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/synch.h>
|
||||
@ -113,43 +114,14 @@ enum FILE_CREATE_DISPOSITION
|
||||
};
|
||||
|
||||
/* DR_CREATE_REQ.CreateOptions [MS-SMB2] */
|
||||
enum FILE_CREATE_OPTION
|
||||
{
|
||||
FILE_DIRECTORY_FILE = 0x00000001,
|
||||
FILE_NON_DIRECTORY_FILE = 0x00000040,
|
||||
FILE_COMPLETE_IF_OPLOCKED = 0x00000100,
|
||||
FILE_DELETE_ON_CLOSE = 0x00001000,
|
||||
FILE_OPEN_REPARSE_POINT = 0x00200000,
|
||||
FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000
|
||||
};
|
||||
|
||||
/* DR_CREATE_REQ.DesiredAccess [MS-SMB2] */
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#if 0
|
||||
#define FILE_READ_DATA 0x00000001
|
||||
#define FILE_WRITE_DATA 0x00000002
|
||||
#define FILE_APPEND_DATA 0x00000004
|
||||
#define FILE_READ_EA 0x00000008
|
||||
#define FILE_WRITE_EA 0x00000010
|
||||
#define FILE_EXECUTE 0x00000020
|
||||
#define FILE_READ_ATTRIBUTES 0x00000080
|
||||
#define FILE_WRITE_ATTRIBUTES 0x00000100
|
||||
#endif
|
||||
|
||||
#include <winpr/io.h>
|
||||
|
||||
#endif
|
||||
|
||||
/* DR_CREATE_RSP.Information */
|
||||
/* DR_DRIVE_CREATE_RSP.DeviceCreateResponse */
|
||||
enum FILE_RESPONSE
|
||||
{
|
||||
FILE_SUPERSEDED = 0x00000000,
|
||||
FILE_OPENED = 0x00000001,
|
||||
FILE_OVERWRITTEN = 0x00000003
|
||||
};
|
||||
|
||||
#define FILE_OPENED 0x00000001
|
||||
#define FILE_OVERWRITTEN 0x00000003
|
||||
|
||||
/* DR_CORE_CLIENT_ANNOUNCE_RSP.VersionMinor */
|
||||
enum RDPDR_MINOR_RDP_VERSION
|
||||
@ -211,73 +183,6 @@ enum RDP_LOWIO_OP
|
||||
RDP_LOWIO_OP_UNLOCK_MULTIPLE = 0x00000005
|
||||
};
|
||||
|
||||
/* NTSTATUS values */
|
||||
/* http://msdn.microsoft.com/en-us/library/cc704588.aspx */
|
||||
enum NTSTATUS
|
||||
{
|
||||
STATUS_SUCCESS = 0x00000000,
|
||||
#ifndef _WIN32
|
||||
STATUS_TIMEOUT = 0x00000102,
|
||||
STATUS_PENDING = 0x00000103,
|
||||
#endif
|
||||
STATUS_REPARSE = 0x00000104,
|
||||
STATUS_MORE_ENTRIES = 0x00000105,
|
||||
STATUS_NOT_ALL_ASSIGNED = 0x00000106,
|
||||
STATUS_OPLOCK_BREAK_IN_PROGRESS = 0x00000108,
|
||||
STATUS_VOLUME_MOUNTED = 0x00000109,
|
||||
STATUS_NOTIFY_CLEANUP = 0x0000010B,
|
||||
STATUS_NOTIFY_ENUM_DIR = 0x0000010C,
|
||||
STATUS_NO_QUOTAS_FOR_ACCOUNT = 0x0000010D,
|
||||
STATUS_FILE_LOCKED_WITH_ONLY_READERS = 0x0000012A,
|
||||
STATUS_FILE_LOCKED_WITH_WRITERS = 0x0000012B,
|
||||
STATUS_WAIT_FOR_OPLOCK = 0x00000367,
|
||||
STATUS_OBJECT_NAME_EXISTS = 0x40000000,
|
||||
STATUS_BAD_CURRENT_DIRECTORY = 0x40000007,
|
||||
STATUS_NO_MORE_FILES = 0x80000006,
|
||||
STATUS_DEVICE_PAPER_EMPTY = 0x8000000E,
|
||||
STATUS_DEVICE_POWERED_OFF = 0x8000000F,
|
||||
STATUS_DEVICE_OFF_LINE = 0x80000010,
|
||||
STATUS_DEVICE_BUSY = 0x80000011,
|
||||
STATUS_NO_MORE_ENTRIES = 0x8000001A,
|
||||
STATUS_UNSUCCESSFUL = 0xC0000001,
|
||||
STATUS_NOT_IMPLEMENTED = 0xC0000002,
|
||||
STATUS_INVALID_INFO_CLASS = 0xC0000003,
|
||||
#ifndef _WIN32
|
||||
STATUS_INVALID_HANDLE = 0xC0000008,
|
||||
STATUS_INVALID_PARAMETER = 0xC000000D,
|
||||
#endif
|
||||
STATUS_NO_SUCH_DEVICE = 0xC000000E,
|
||||
STATUS_NO_SUCH_FILE = 0xC000000F,
|
||||
STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
|
||||
STATUS_END_OF_FILE = 0xC0000011,
|
||||
STATUS_NO_MEDIA_IN_DEVICE = 0xC0000013,
|
||||
STATUS_UNRECOGNIZED_MEDIA = 0xC0000014,
|
||||
STATUS_ACCESS_DENIED = 0xc0000022,
|
||||
STATUS_OBJECT_NAME_INVALID = 0xC0000033,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||
STATUS_OBJECT_NAME_COLLISION = 0xc0000035,
|
||||
STATUS_PORT_DISCONNECTED = 0xC0000037,
|
||||
STATUS_OBJECT_PATH_INVALID = 0xC0000039,
|
||||
STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A,
|
||||
STATUS_INVALID_PORT_HANDLE = 0xC0000042,
|
||||
STATUS_DELETE_PENDING = 0xC0000056,
|
||||
STATUS_DISK_FULL = 0xC000007F,
|
||||
STATUS_DEVICE_NOT_READY = 0xC00000A3,
|
||||
STATUS_IO_TIMEOUT = 0xC00000B5,
|
||||
STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA,
|
||||
STATUS_NOT_SUPPORTED = 0xC00000BB,
|
||||
STATUS_PRINT_QUEUE_FULL = 0xC00000C6,
|
||||
STATUS_PRINT_CANCELLED = 0xC00000C8,
|
||||
STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101,
|
||||
STATUS_FILE_CORRUPT_ERROR = 0xC0000102,
|
||||
STATUS_NOT_A_DIRECTORY = 0xC0000103,
|
||||
STATUS_NAME_TOO_LONG = 0xC0000106,
|
||||
STATUS_CANCELLED = 0xC0000120,
|
||||
STATUS_CANNOT_DELETE = 0xC0000121,
|
||||
STATUS_FILE_DELETED = 0xC0000123,
|
||||
STATUS_FILE_CLOSED = 0xC0000128
|
||||
};
|
||||
|
||||
enum RDPDR_PRINTER_ANNOUNCE_FLAG
|
||||
{
|
||||
RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII = 0x00000001,
|
||||
|
@ -35,17 +35,27 @@
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/peer.h>
|
||||
|
||||
typedef struct WTSVirtualChannelManager WTSVirtualChannelManager;
|
||||
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
//#include <winpr/wtsapi.h>
|
||||
|
||||
typedef enum _WTS_VIRTUAL_CLASS
|
||||
{
|
||||
WTSVirtualClientData,
|
||||
WTSVirtualFileHandle,
|
||||
WTSVirtualChannelReady
|
||||
WTSVirtualEventHandle, /* Extended */
|
||||
WTSVirtualChannelReady /* Extended */
|
||||
} WTS_VIRTUAL_CLASS;
|
||||
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000000
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000004
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000006
|
||||
#define WTS_CHANNEL_OPTION_DYNAMIC_NO_COMPRESS 0x00000008
|
||||
|
||||
typedef struct WTSVirtualChannelManager WTSVirtualChannelManager;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -55,9 +65,10 @@ extern "C" {
|
||||
*/
|
||||
FREERDP_API WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client);
|
||||
FREERDP_API void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
|
||||
void** fds, int* fds_count);
|
||||
|
||||
FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, 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
|
||||
@ -69,10 +80,10 @@ FREERDP_API BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelMa
|
||||
* Static virtual channels must be opened from the main thread. Dynamic virtual channels
|
||||
* can be opened from any thread.
|
||||
*/
|
||||
FREERDP_API void* WTSVirtualChannelOpenEx(
|
||||
/* __in */ WTSVirtualChannelManager* vcm,
|
||||
/* __in */ const char* pVirtualName,
|
||||
/* __in */ UINT32 flags);
|
||||
|
||||
// WINPR_API HANDLE WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags);
|
||||
|
||||
WINPR_API HANDLE WTSVirtualChannelManagerOpenEx(WTSVirtualChannelManager* vcm, LPSTR pVirtualName, DWORD flags);
|
||||
|
||||
/**
|
||||
* Returns information about a specified virtual channel.
|
||||
@ -80,17 +91,14 @@ FREERDP_API void* WTSVirtualChannelOpenEx(
|
||||
* Servers use this function to gain access to a virtual channel file handle
|
||||
* that can be used for asynchronous I/O.
|
||||
*/
|
||||
FREERDP_API BOOL WTSVirtualChannelQuery(
|
||||
/* __in */ void* hChannelHandle,
|
||||
/* __in */ WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||
/* __out */ void** ppBuffer,
|
||||
/* __out */ UINT32* pBytesReturned);
|
||||
|
||||
WINPR_API BOOL WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer, DWORD* pBytesReturned);
|
||||
|
||||
/**
|
||||
* Frees memory allocated by WTSVirtualChannelQuery
|
||||
*/
|
||||
FREERDP_API void WTSFreeMemory(
|
||||
/* __in */ void* pMemory);
|
||||
|
||||
WINPR_API VOID WTSFreeMemory(PVOID pMemory);
|
||||
|
||||
/**
|
||||
* Reads data from the server end of a virtual channel.
|
||||
@ -109,27 +117,20 @@ FREERDP_API void WTSFreeMemory(
|
||||
* The caller should use the file handle returned by WTSVirtualChannelQuery to
|
||||
* determine whether a packet has arrived.
|
||||
*/
|
||||
FREERDP_API BOOL WTSVirtualChannelRead(
|
||||
/* __in */ void* hChannelHandle,
|
||||
/* __in */ UINT32 TimeOut,
|
||||
/* __out */ BYTE* Buffer,
|
||||
/* __in */ UINT32 BufferSize,
|
||||
/* __out */ UINT32* pBytesRead);
|
||||
|
||||
WINPR_API BOOL WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead);
|
||||
|
||||
/**
|
||||
* Writes data to the server end of a virtual channel.
|
||||
*/
|
||||
FREERDP_API BOOL WTSVirtualChannelWrite(
|
||||
/* __in */ void* hChannelHandle,
|
||||
/* __in */ BYTE* Buffer,
|
||||
/* __in */ UINT32 Length,
|
||||
/* __out */ UINT32* pBytesWritten);
|
||||
|
||||
WINPR_API BOOL WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length, PULONG pBytesWritten);
|
||||
|
||||
/**
|
||||
* Closes an open virtual channel handle.
|
||||
*/
|
||||
FREERDP_API BOOL WTSVirtualChannelClose(
|
||||
/* __in */ void* hChannelHandle);
|
||||
|
||||
WINPR_API BOOL WTSVirtualChannelClose(HANDLE hChannelHandle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
#ifndef FREERDP_CHANNEL_CLIENT_CLIPRDR_H
|
||||
#define FREERDP_CHANNEL_CLIENT_CLIPRDR_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
|
||||
/**
|
||||
* Client Interface
|
||||
*/
|
||||
@ -52,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
|
||||
*/
|
||||
|
@ -50,6 +50,7 @@ struct _NSC_MESSAGE
|
||||
UINT32 height;
|
||||
BYTE* data;
|
||||
int scanline;
|
||||
BYTE* PlaneBuffer;
|
||||
UINT32 MaxPlaneSize;
|
||||
BYTE* PlaneBuffers[5];
|
||||
UINT32 OrgByteCount[4];
|
||||
|
@ -56,7 +56,6 @@ struct _RFX_TILE
|
||||
BYTE* data;
|
||||
int scanline;
|
||||
BOOL allocated;
|
||||
|
||||
BYTE quantIdxY;
|
||||
BYTE quantIdxCb;
|
||||
BYTE quantIdxCr;
|
||||
@ -68,6 +67,7 @@ struct _RFX_TILE
|
||||
BYTE* YData;
|
||||
BYTE* CbData;
|
||||
BYTE* CrData;
|
||||
BYTE* YCbCrData;
|
||||
};
|
||||
typedef struct _RFX_TILE RFX_TILE;
|
||||
|
||||
@ -118,6 +118,7 @@ struct _RFX_CONTEXT
|
||||
{
|
||||
RFX_STATE state;
|
||||
|
||||
BOOL encoder;
|
||||
UINT16 flags;
|
||||
UINT16 properties;
|
||||
UINT16 width;
|
||||
@ -153,7 +154,7 @@ struct _RFX_CONTEXT
|
||||
};
|
||||
typedef struct _RFX_CONTEXT RFX_CONTEXT;
|
||||
|
||||
FREERDP_API RFX_CONTEXT* rfx_context_new(void);
|
||||
FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder);
|
||||
FREERDP_API void rfx_context_free(RFX_CONTEXT* context);
|
||||
FREERDP_API void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format);
|
||||
FREERDP_API void rfx_context_reset(RFX_CONTEXT* context);
|
||||
|
51
include/freerdp/server/cliprdr.h
Normal file
51
include/freerdp/server/cliprdr.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Clipboard Virtual Channel Server Interface
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_CLIPRDR_H
|
||||
#define FREERDP_CHANNEL_SERVER_CLIPRDR_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
/**
|
||||
* Server Interface
|
||||
*/
|
||||
|
||||
typedef struct _cliprdr_server_context CliprdrServerContext;
|
||||
typedef struct _cliprdr_server_private CliprdrServerPrivate;
|
||||
|
||||
typedef int (*psCliprdrStart)(CliprdrServerContext* context);
|
||||
typedef int (*psCliprdrStop)(CliprdrServerContext* context);
|
||||
|
||||
struct _cliprdr_server_context
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
psCliprdrStart Start;
|
||||
psCliprdrStop Stop;
|
||||
|
||||
CliprdrServerPrivate* priv;
|
||||
};
|
||||
|
||||
FREERDP_API CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void cliprdr_server_context_free(CliprdrServerContext* context);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_H */
|
50
include/freerdp/server/drdynvc.h
Normal file
50
include/freerdp/server/drdynvc.h
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Dynamic Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_DRDYNVC_H
|
||||
#define FREERDP_CHANNEL_SERVER_DRDYNVC_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
|
||||
/**
|
||||
* Server Interface
|
||||
*/
|
||||
|
||||
typedef struct _drdynvc_client_context DrdynvcServerContext;
|
||||
typedef struct _drdynvc_server_private DrdynvcServerPrivate;
|
||||
|
||||
typedef int (*psDrdynvcStart)(DrdynvcServerContext* context);
|
||||
typedef int (*psDrdynvcStop)(DrdynvcServerContext* context);
|
||||
|
||||
struct _drdynvc_client_context
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
psDrdynvcStart Start;
|
||||
psDrdynvcStop Stop;
|
||||
|
||||
DrdynvcServerPrivate* priv;
|
||||
};
|
||||
|
||||
FREERDP_API DrdynvcServerContext* drdynvc_server_context_new(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void drdynvc_server_context_free(DrdynvcServerContext* context);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_DRDYNVC_H */
|
51
include/freerdp/server/rdpdr.h
Normal file
51
include/freerdp/server/rdpdr.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Device Redirection Virtual Channel Server Interface
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 FREERDP_CHANNEL_SERVER_RDPDR_H
|
||||
#define FREERDP_CHANNEL_SERVER_RDPDR_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
/**
|
||||
* Server Interface
|
||||
*/
|
||||
|
||||
typedef struct _rdpdr_server_context RdpdrServerContext;
|
||||
typedef struct _rdpdr_server_private RdpdrServerPrivate;
|
||||
|
||||
typedef int (*psRdpdrStart)(RdpdrServerContext* context);
|
||||
typedef int (*psRdpdrStop)(RdpdrServerContext* context);
|
||||
|
||||
struct _rdpdr_server_context
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
psRdpdrStart Start;
|
||||
psRdpdrStop Stop;
|
||||
|
||||
RdpdrServerPrivate* priv;
|
||||
};
|
||||
|
||||
FREERDP_API RdpdrServerContext* rdpdr_server_context_new(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void rdpdr_server_context_free(RdpdrServerContext* context);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_RDPDR_H */
|
@ -23,20 +23,30 @@
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/channels/rdpsnd.h>
|
||||
|
||||
typedef struct _rdpsnd_server_context RdpsndServerContext;
|
||||
typedef struct _rdpsnd_server_context rdpsnd_server_context;
|
||||
typedef struct _rdpsnd_server_private RdpsndServerPrivate;
|
||||
|
||||
typedef BOOL (*psRdpsndServerInitialize)(rdpsnd_server_context* context);
|
||||
typedef void (*psRdpsndServerSelectFormat)(rdpsnd_server_context* context, int client_format_index);
|
||||
typedef BOOL (*psRdpsndServerSendSamples)(rdpsnd_server_context* context, const void* buf, int nframes);
|
||||
typedef BOOL (*psRdpsndServerSetVolume)(rdpsnd_server_context* context, int left, int right);
|
||||
typedef BOOL (*psRdpsndServerClose)(rdpsnd_server_context* context);
|
||||
typedef int (*psRdpsndStart)(RdpsndServerContext* context);
|
||||
typedef int (*psRdpsndStop)(RdpsndServerContext* context);
|
||||
|
||||
typedef void (*psRdpsndServerActivated)(rdpsnd_server_context* context);
|
||||
typedef BOOL (*psRdpsndServerInitialize)(RdpsndServerContext* context);
|
||||
typedef void (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, int client_format_index);
|
||||
typedef BOOL (*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes);
|
||||
typedef BOOL (*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right);
|
||||
typedef BOOL (*psRdpsndServerClose)(RdpsndServerContext* context);
|
||||
|
||||
typedef void (*psRdpsndServerActivated)(RdpsndServerContext* context);
|
||||
|
||||
struct _rdpsnd_server_context
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
psRdpsndStart Start;
|
||||
psRdpsndStop Stop;
|
||||
|
||||
RdpsndServerPrivate* priv;
|
||||
|
||||
/* Server self-defined pointer. */
|
||||
void* data;
|
||||
|
||||
@ -95,8 +105,8 @@ struct _rdpsnd_server_context
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FREERDP_API rdpsnd_server_context* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void rdpsnd_server_context_free(rdpsnd_server_context* context);
|
||||
FREERDP_API RdpsndServerContext* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void rdpsnd_server_context_free(RdpsndServerContext* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -390,6 +390,7 @@ NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y,
|
||||
UINT32 MaxPlaneSize;
|
||||
UINT32 MaxMessageSize;
|
||||
NSC_MESSAGE* messages;
|
||||
UINT32 PaddedMaxPlaneSize;
|
||||
|
||||
k = 0;
|
||||
MaxRegionWidth = 64 * 4;
|
||||
@ -430,11 +431,15 @@ NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y,
|
||||
|
||||
for (i = 0; i < *numMessages; i++)
|
||||
{
|
||||
messages[i].PlaneBuffers[0] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
|
||||
messages[i].PlaneBuffers[1] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
|
||||
messages[i].PlaneBuffers[2] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
|
||||
messages[i].PlaneBuffers[3] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
|
||||
messages[i].PlaneBuffers[4] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
|
||||
PaddedMaxPlaneSize = messages[i].MaxPlaneSize + 32;
|
||||
|
||||
messages[i].PlaneBuffer = (BYTE*) BufferPool_Take(context->priv->PlanePool, PaddedMaxPlaneSize * 5);
|
||||
|
||||
messages[i].PlaneBuffers[0] = (BYTE*) &(messages[i].PlaneBuffer[(PaddedMaxPlaneSize * 0) + 16]);
|
||||
messages[i].PlaneBuffers[1] = (BYTE*) &(messages[i].PlaneBuffer[(PaddedMaxPlaneSize * 1) + 16]);
|
||||
messages[i].PlaneBuffers[2] = (BYTE*) &(messages[i].PlaneBuffer[(PaddedMaxPlaneSize * 2) + 16]);
|
||||
messages[i].PlaneBuffers[3] = (BYTE*) &(messages[i].PlaneBuffer[(PaddedMaxPlaneSize * 3) + 16]);
|
||||
messages[i].PlaneBuffers[4] = (BYTE*) &(messages[i].PlaneBuffer[(PaddedMaxPlaneSize * 4) + 16]);
|
||||
}
|
||||
|
||||
for (i = 0; i < *numMessages; i++)
|
||||
@ -504,11 +509,7 @@ int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message)
|
||||
|
||||
int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message)
|
||||
{
|
||||
BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[0]);
|
||||
BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[1]);
|
||||
BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[2]);
|
||||
BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[3]);
|
||||
BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[4]);
|
||||
BufferPool_Return(context->priv->PlanePool, message->PlaneBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ void rfx_tile_init(RFX_TILE* tile)
|
||||
}
|
||||
}
|
||||
|
||||
RFX_TILE* rfx_tile_new()
|
||||
RFX_TILE* rfx_decoder_tile_new()
|
||||
{
|
||||
RFX_TILE* tile = NULL;
|
||||
|
||||
@ -170,7 +170,7 @@ RFX_TILE* rfx_tile_new()
|
||||
return tile;
|
||||
}
|
||||
|
||||
void rfx_tile_free(RFX_TILE* tile)
|
||||
void rfx_decoder_tile_free(RFX_TILE* tile)
|
||||
{
|
||||
if (tile)
|
||||
{
|
||||
@ -180,7 +180,29 @@ void rfx_tile_free(RFX_TILE* tile)
|
||||
}
|
||||
}
|
||||
|
||||
RFX_CONTEXT* rfx_context_new(void)
|
||||
RFX_TILE* rfx_encoder_tile_new()
|
||||
{
|
||||
RFX_TILE* tile = NULL;
|
||||
|
||||
tile = (RFX_TILE*) malloc(sizeof(RFX_TILE));
|
||||
|
||||
if (tile)
|
||||
{
|
||||
ZeroMemory(tile, sizeof(RFX_TILE));
|
||||
}
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
void rfx_encoder_tile_free(RFX_TILE* tile)
|
||||
{
|
||||
if (tile)
|
||||
{
|
||||
free(tile);
|
||||
}
|
||||
}
|
||||
|
||||
RFX_CONTEXT* rfx_context_new(BOOL encoder)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
@ -193,13 +215,24 @@ RFX_CONTEXT* rfx_context_new(void)
|
||||
context = (RFX_CONTEXT*) malloc(sizeof(RFX_CONTEXT));
|
||||
ZeroMemory(context, sizeof(RFX_CONTEXT));
|
||||
|
||||
context->encoder = encoder;
|
||||
|
||||
context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV));
|
||||
ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV));
|
||||
|
||||
context->priv->TilePool = ObjectPool_New(TRUE);
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_tile_new;
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init;
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_tile_free;
|
||||
|
||||
if (context->encoder)
|
||||
{
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_encoder_tile_new;
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_encoder_tile_free;
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_decoder_tile_new;
|
||||
ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_decoder_tile_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* align buffers to 16 byte boundary (needed for SSE/NEON instructions)
|
||||
@ -211,9 +244,11 @@ RFX_CONTEXT* rfx_context_new(void)
|
||||
* in order to allow optimized functions (SEE, NEON) to read from positions
|
||||
* that are actually in front/beyond the buffer. Offset calculations are
|
||||
* performed at the BufferPool_Take function calls in rfx_encode/decode.c.
|
||||
*
|
||||
* We then multiply by 3 to use a single, partioned buffer for all 3 channels.
|
||||
*/
|
||||
|
||||
context->priv->BufferPool = BufferPool_New(TRUE, 8192 + 32, 16);
|
||||
context->priv->BufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16);
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
@ -903,14 +938,11 @@ void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message)
|
||||
{
|
||||
tile = message->tiles[i];
|
||||
|
||||
if (tile->YData)
|
||||
BufferPool_Return(context->priv->BufferPool, tile->YData);
|
||||
|
||||
if (tile->CbData)
|
||||
BufferPool_Return(context->priv->BufferPool, tile->CbData);
|
||||
|
||||
if (tile->CrData)
|
||||
BufferPool_Return(context->priv->BufferPool, tile->CrData);
|
||||
if (tile->YCbCrData)
|
||||
{
|
||||
BufferPool_Return(context->priv->BufferPool, tile->YCbCrData);
|
||||
tile->YCbCrData = NULL;
|
||||
}
|
||||
|
||||
ObjectPool_Return(context->priv->TilePool, (void*) tile);
|
||||
}
|
||||
@ -1068,7 +1100,7 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects,
|
||||
{
|
||||
context->numQuant = 1;
|
||||
context->quants = (UINT32*) malloc(sizeof(rfx_default_quantization_values));
|
||||
memcpy(context->quants, rfx_default_quantization_values, sizeof(rfx_default_quantization_values));
|
||||
CopyMemory(context->quants, &rfx_default_quantization_values, sizeof(rfx_default_quantization_values));
|
||||
context->quantIdxY = 0;
|
||||
context->quantIdxCb = 0;
|
||||
context->quantIdxCr = 0;
|
||||
@ -1128,9 +1160,12 @@ RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects,
|
||||
tile->YLen = 0;
|
||||
tile->CbLen = 0;
|
||||
tile->CrLen = 0;
|
||||
tile->YData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1);
|
||||
tile->CbData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1);
|
||||
tile->CrData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1);
|
||||
|
||||
tile->YCbCrData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1);
|
||||
|
||||
tile->YData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 0) + 16]);
|
||||
tile->CbData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 1) + 16]);
|
||||
tile->CrData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 2) + 16]);
|
||||
|
||||
if (context->priv->UseThreads)
|
||||
{
|
||||
@ -1233,9 +1268,6 @@ RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_RECT* rects, in
|
||||
RFX_MESSAGE* message;
|
||||
RFX_MESSAGE* messages;
|
||||
|
||||
printf("rfx_encode_messages: numRects: %d maxDataSize: %d x: %d y: %d w: %d/%d h: %d/%d\n", numRects, maxDataSize,
|
||||
rects[0].x, rects[0].y, rects[0].width, width, rects[0].height, height);
|
||||
|
||||
message = rfx_encode_message(context, rects, numRects, data, width, height, scanline);
|
||||
messages = rfx_split_message(context, message, numMessages, maxDataSize);
|
||||
rfx_message_free(context, message);
|
||||
|
@ -128,6 +128,7 @@ static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantizatio
|
||||
/* stride is bytes between rows in the output buffer. */
|
||||
BOOL rfx_decode_rgb(RFX_CONTEXT* context, RFX_TILE* tile, BYTE* rgb_buffer, int stride)
|
||||
{
|
||||
BYTE* pBuffer;
|
||||
INT16* pSrcDst[3];
|
||||
UINT32 *y_quants, *cb_quants, *cr_quants;
|
||||
static const prim_size_t roi_64x64 = { 64, 64 };
|
||||
@ -139,9 +140,10 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, RFX_TILE* tile, BYTE* rgb_buffer, int
|
||||
cb_quants = context->quants + (tile->quantIdxCb * 10);
|
||||
cr_quants = context->quants + (tile->quantIdxCr * 10);
|
||||
|
||||
pSrcDst[0] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* y_r_buffer */
|
||||
pSrcDst[1] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cb_g_buffer */
|
||||
pSrcDst[2] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cr_b_buffer */
|
||||
pBuffer = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1);
|
||||
pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* y_r_buffer */
|
||||
pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* cb_g_buffer */
|
||||
pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* cr_b_buffer */
|
||||
|
||||
rfx_decode_component(context, y_quants, tile->YData, tile->YLen, pSrcDst[0]); /* YData */
|
||||
|
||||
@ -161,9 +163,7 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, RFX_TILE* tile, BYTE* rgb_buffer, int
|
||||
|
||||
PROFILER_EXIT(context->priv->prof_rfx_decode_rgb);
|
||||
|
||||
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[0] - 16);
|
||||
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[1] - 16);
|
||||
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[2] - 16);
|
||||
BufferPool_Return(context->priv->BufferPool, pBuffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -219,6 +219,7 @@ static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantizatio
|
||||
|
||||
void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile)
|
||||
{
|
||||
BYTE* pBuffer;
|
||||
INT16* pSrcDst[3];
|
||||
int YLen, CbLen, CrLen;
|
||||
UINT32 *YQuant, *CbQuant, *CrQuant;
|
||||
@ -230,9 +231,10 @@ void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile)
|
||||
CbQuant = context->quants + (tile->quantIdxCb * 10);
|
||||
CrQuant = context->quants + (tile->quantIdxCr * 10);
|
||||
|
||||
pSrcDst[0] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* y_r_buffer */
|
||||
pSrcDst[1] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cb_g_buffer */
|
||||
pSrcDst[2] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cr_b_buffer */
|
||||
pBuffer = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1);
|
||||
pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* y_r_buffer */
|
||||
pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* cb_g_buffer */
|
||||
pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* cr_b_buffer */
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_encode_rgb);
|
||||
|
||||
@ -265,7 +267,5 @@ void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile)
|
||||
|
||||
PROFILER_EXIT(context->priv->prof_rfx_encode_rgb);
|
||||
|
||||
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[0] - 16);
|
||||
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[1] - 16);
|
||||
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[2] - 16);
|
||||
BufferPool_Return(context->priv->BufferPool, pBuffer);
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings)
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily */
|
||||
Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress */
|
||||
|
||||
@ -149,6 +150,7 @@ BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings)
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 10)
|
||||
return FALSE;
|
||||
|
||||
Stream_Seek_UINT32(s); /* clientSessionId, should be set to 0 */
|
||||
Stream_Read_UINT32(s, settings->PerformanceFlags); /* performanceFlags */
|
||||
|
||||
|
@ -191,11 +191,15 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type)
|
||||
sec_flags = SEC_LICENSE_PKT;
|
||||
wMsgSize = length - LICENSE_PACKET_HEADER_MAX_LENGTH + 4;
|
||||
|
||||
flags = PREAMBLE_VERSION_3_0;
|
||||
|
||||
/**
|
||||
* Using EXTENDED_ERROR_MSG_SUPPORTED here would cause mstsc to crash when
|
||||
* running in server mode! This flag seems to be incorrectly documented.
|
||||
*/
|
||||
flags = PREAMBLE_VERSION_3_0 | EXTENDED_ERROR_MSG_SUPPORTED;
|
||||
|
||||
if (!license->rdp->settings->ServerMode)
|
||||
flags |= EXTENDED_ERROR_MSG_SUPPORTED;
|
||||
|
||||
rdp_write_header(license->rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
|
||||
rdp_write_security_header(s, sec_flags);
|
||||
|
@ -30,6 +30,10 @@
|
||||
|
||||
#include "peer.h"
|
||||
|
||||
#ifdef WITH_DEBUG_RDP
|
||||
extern const char* DATA_PDU_TYPE_STRINGS[80];
|
||||
#endif
|
||||
|
||||
static BOOL freerdp_peer_initialize(freerdp_peer* client)
|
||||
{
|
||||
client->context->rdp->settings->ServerMode = TRUE;
|
||||
@ -85,6 +89,11 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s)
|
||||
if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len))
|
||||
return FALSE;
|
||||
|
||||
#ifdef WITH_DEBUG_RDP
|
||||
printf("recv %s Data PDU (0x%02X), length: %d\n",
|
||||
type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length);
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_PDU_TYPE_SYNCHRONIZE:
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <freerdp/crypto/per.h>
|
||||
|
||||
#ifdef WITH_DEBUG_RDP
|
||||
static const char* const DATA_PDU_TYPE_STRINGS[] =
|
||||
const char* DATA_PDU_TYPE_STRINGS[80] =
|
||||
{
|
||||
"?", "?", /* 0x00 - 0x01 */
|
||||
"Update", /* 0x02 */
|
||||
@ -65,7 +65,7 @@ static const char* const DATA_PDU_TYPE_STRINGS[] =
|
||||
"?", "?", "?", /* 0x33 - 0x35 */
|
||||
"Status Info", /* 0x36 */
|
||||
"Monitor Layout" /* 0x37 */
|
||||
"?", "?", "?", /* 0x38 - 0x40 */
|
||||
"FrameAcknowledge", "?", "?", /* 0x38 - 0x40 */
|
||||
"?", "?", "?", "?", "?", "?" /* 0x41 - 0x46 */
|
||||
};
|
||||
#endif
|
||||
@ -133,20 +133,21 @@ void rdp_write_share_control_header(wStream* s, UINT16 length, UINT16 type, UINT
|
||||
Stream_Write_UINT16(s, channel_id); /* pduSource */
|
||||
}
|
||||
|
||||
BOOL rdp_read_share_data_header(wStream* s, UINT16* length, BYTE* type, UINT32* share_id,
|
||||
BYTE *compressed_type, UINT16 *compressed_len)
|
||||
BOOL rdp_read_share_data_header(wStream* s, UINT16* length, BYTE* type, UINT32* shareId,
|
||||
BYTE *compressedType, UINT16 *compressedLen)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 12)
|
||||
return FALSE;
|
||||
|
||||
/* Share Data Header */
|
||||
Stream_Read_UINT32(s, *share_id); /* shareId (4 bytes) */
|
||||
Stream_Read_UINT32(s, *shareId); /* shareId (4 bytes) */
|
||||
Stream_Seek_UINT8(s); /* pad1 (1 byte) */
|
||||
Stream_Seek_UINT8(s); /* streamId (1 byte) */
|
||||
Stream_Read_UINT16(s, *length); /* uncompressedLength (2 bytes) */
|
||||
Stream_Read_UINT8(s, *type); /* pduType2, Data PDU Type (1 byte) */
|
||||
Stream_Read_UINT8(s, *compressed_type); /* compressedType (1 byte) */
|
||||
Stream_Read_UINT16(s, *compressed_len); /* compressedLength (2 bytes) */
|
||||
Stream_Read_UINT8(s, *compressedType); /* compressedType (1 byte) */
|
||||
Stream_Read_UINT16(s, *compressedLen); /* compressedLength (2 bytes) */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -567,9 +568,8 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s)
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_RDP
|
||||
/* if (type != DATA_PDU_TYPE_UPDATE) */
|
||||
DEBUG_RDP("recv %s Data PDU (0x%02X), length:%d",
|
||||
type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length);
|
||||
printf("recv %s Data PDU (0x%02X), length: %d\n",
|
||||
type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length);
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
|
@ -1052,7 +1052,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer)
|
||||
|
||||
gdi_register_graphics(instance->context->graphics);
|
||||
|
||||
gdi->rfx_context = rfx_context_new();
|
||||
gdi->rfx_context = rfx_context_new(FALSE);
|
||||
gdi->nsc_context = nsc_context_new();
|
||||
|
||||
return 0;
|
||||
|
@ -66,7 +66,7 @@ struct mf_peer_context
|
||||
//#endif
|
||||
|
||||
//#ifdef CHANNEL_RDPSND_SERVER
|
||||
rdpsnd_server_context* rdpsnd;
|
||||
RdpsndServerContext* rdpsnd;
|
||||
//#endif
|
||||
};
|
||||
|
||||
|
@ -175,7 +175,7 @@ void mf_peer_rfx_update(freerdp_peer* client)
|
||||
int mf_peer_context_new(freerdp_peer* client, mfPeerContext* context)
|
||||
{
|
||||
context->info = mf_info_get_instance();
|
||||
context->rfx_context = rfx_context_new();
|
||||
context->rfx_context = rfx_context_new(TRUE);
|
||||
context->rfx_context->mode = RLGR3;
|
||||
context->rfx_context->width = client->settings->DesktopWidth;
|
||||
context->rfx_context->height = client->settings->DesktopHeight;
|
||||
|
@ -34,7 +34,7 @@ static const AUDIO_FORMAT supported_audio_formats[] =
|
||||
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, NULL }
|
||||
};
|
||||
|
||||
static void mf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
||||
static void mf_peer_rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
OSStatus status;
|
||||
int i, j;
|
||||
|
@ -53,7 +53,7 @@ struct _AQRecorderState
|
||||
UInt32 bufferByteSize;
|
||||
SInt64 currentPacket;
|
||||
bool isRunning;
|
||||
rdpsnd_server_context* snd_context;
|
||||
RdpsndServerContext* snd_context;
|
||||
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,7 @@ static const AUDIO_FORMAT test_audio_formats[] =
|
||||
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL }
|
||||
};
|
||||
|
||||
static void sf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
||||
static void sf_peer_rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
printf("RDPSND Activated\n");
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ static BOOL test_dump_rfx_realtime = TRUE;
|
||||
|
||||
void test_peer_context_new(freerdp_peer* client, testPeerContext* context)
|
||||
{
|
||||
context->rfx_context = rfx_context_new();
|
||||
context->rfx_context = rfx_context_new(TRUE);
|
||||
context->rfx_context->mode = RLGR3;
|
||||
context->rfx_context->width = SAMPLE_SERVER_DEFAULT_WIDTH;
|
||||
context->rfx_context->height = SAMPLE_SERVER_DEFAULT_HEIGHT;
|
||||
@ -398,10 +398,10 @@ static void* tf_debug_channel_thread_func(void* arg)
|
||||
void* fd;
|
||||
wStream* s;
|
||||
void* buffer;
|
||||
UINT32 bytes_returned = 0;
|
||||
DWORD BytesReturned = 0;
|
||||
testPeerContext* context = (testPeerContext*) arg;
|
||||
|
||||
if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE)
|
||||
if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &BytesReturned) == TRUE)
|
||||
{
|
||||
fd = *((void**) buffer);
|
||||
WTSFreeMemory(buffer);
|
||||
@ -411,7 +411,7 @@ static void* tf_debug_channel_thread_func(void* arg)
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
WTSVirtualChannelWrite(context->debug_channel, (BYTE*) "test1", 5, NULL);
|
||||
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test1", 5, NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -422,25 +422,25 @@ static void* tf_debug_channel_thread_func(void* arg)
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_Buffer(s),
|
||||
Stream_Capacity(s), &bytes_returned) == FALSE)
|
||||
if (WTSVirtualChannelRead(context->debug_channel, 0, (PCHAR) Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
if (bytes_returned == 0)
|
||||
if (BytesReturned == 0)
|
||||
break;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, bytes_returned);
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
|
||||
if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_Buffer(s),
|
||||
Stream_Capacity(s), &bytes_returned) == FALSE)
|
||||
if (WTSVirtualChannelRead(context->debug_channel, 0, (PCHAR) Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
/* should not happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Stream_SetPosition(s, bytes_returned);
|
||||
Stream_SetPosition(s, BytesReturned);
|
||||
|
||||
printf("got %d bytes\n", bytes_returned);
|
||||
printf("got %d bytes\n", BytesReturned);
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
@ -498,7 +498,7 @@ BOOL tf_peer_post_connect(freerdp_peer* client)
|
||||
{
|
||||
if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpdbg", 6) == 0)
|
||||
{
|
||||
context->debug_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpdbg", 0);
|
||||
context->debug_channel = WTSVirtualChannelManagerOpenEx(context->vcm, "rdpdbg", 0);
|
||||
|
||||
if (context->debug_channel != NULL)
|
||||
{
|
||||
@ -580,7 +580,7 @@ void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
if (context->debug_channel)
|
||||
{
|
||||
WTSVirtualChannelWrite(context->debug_channel, (BYTE*) "test2", 5, NULL);
|
||||
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test2", 5, NULL);
|
||||
}
|
||||
}
|
||||
else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */
|
||||
|
@ -54,7 +54,7 @@ struct test_peer_context
|
||||
audin_server_context* audin;
|
||||
BOOL audin_open;
|
||||
UINT32 frame_id;
|
||||
rdpsnd_server_context* rdpsnd;
|
||||
RdpsndServerContext* rdpsnd;
|
||||
};
|
||||
typedef struct test_peer_context testPeerContext;
|
||||
|
||||
|
@ -26,7 +26,7 @@ int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wf_directsound_activate(rdpsnd_server_context* context)
|
||||
int wf_directsound_activate(RdpsndServerContext* context)
|
||||
{
|
||||
HRESULT hr;
|
||||
wfInfo* wfi;
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer);
|
||||
|
||||
int wf_directsound_activate(rdpsnd_server_context* context);
|
||||
int wf_directsound_activate(RdpsndServerContext* context);
|
||||
|
||||
DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam);
|
||||
|
||||
|
@ -100,7 +100,7 @@ struct wf_peer_context
|
||||
HANDLE socketSemaphore;
|
||||
|
||||
WTSVirtualChannelManager* vcm;
|
||||
rdpsnd_server_context* rdpsnd;
|
||||
RdpsndServerContext* rdpsnd;
|
||||
};
|
||||
|
||||
struct wf_server
|
||||
|
@ -46,7 +46,7 @@ static const AUDIO_FORMAT supported_audio_formats[] =
|
||||
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL }
|
||||
};
|
||||
|
||||
static void wf_peer_rdpsnd_activated(rdpsnd_server_context* context)
|
||||
static void wf_peer_rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
wfInfo* wfi;
|
||||
int i, j;
|
||||
|
@ -198,7 +198,7 @@ void wf_update_encoder_reset(wfInfo* wfi)
|
||||
}
|
||||
else
|
||||
{
|
||||
wfi->rfx_context = rfx_context_new();
|
||||
wfi->rfx_context = rfx_context_new(TRUE);
|
||||
wfi->rfx_context->mode = RLGR3;
|
||||
wfi->rfx_context->width = wfi->servscreen_width;
|
||||
wfi->rfx_context->height = wfi->servscreen_height;
|
||||
|
@ -34,7 +34,7 @@ int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
||||
}
|
||||
|
||||
|
||||
int wf_wasapi_activate(rdpsnd_server_context* context)
|
||||
int wf_wasapi_activate(RdpsndServerContext* context)
|
||||
{
|
||||
wchar_t * pattern = L"Stereo Mix";
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer);
|
||||
|
||||
int wf_wasapi_activate(rdpsnd_server_context* context);
|
||||
int wf_wasapi_activate(RdpsndServerContext* context);
|
||||
|
||||
int wf_wasapi_get_device_string(LPWSTR pattern, LPWSTR * deviceStr);
|
||||
|
||||
|
@ -295,7 +295,7 @@ xfInfo* xf_info_init()
|
||||
void xf_peer_context_new(freerdp_peer* client, xfPeerContext* context)
|
||||
{
|
||||
context->info = xf_info_init();
|
||||
context->rfx_context = rfx_context_new();
|
||||
context->rfx_context = rfx_context_new(TRUE);
|
||||
context->rfx_context->mode = RLGR3;
|
||||
context->rfx_context->width = context->info->width;
|
||||
context->rfx_context->height = context->info->height;
|
||||
|
@ -321,11 +321,15 @@ typedef struct _wBufferPoolItem wBufferPoolItem;
|
||||
|
||||
struct _wBufferPool
|
||||
{
|
||||
int defaultSize;
|
||||
int fixedSize;
|
||||
DWORD alignment;
|
||||
BOOL synchronized;
|
||||
CRITICAL_SECTION lock;
|
||||
|
||||
int size;
|
||||
int capacity;
|
||||
void** array;
|
||||
|
||||
int aSize;
|
||||
int aCapacity;
|
||||
wBufferPoolItem* aArray;
|
||||
|
@ -67,9 +67,6 @@
|
||||
#define CREDUIWIN_SECURE_PROMPT 0x00001000
|
||||
#define CREDUIWIN_PACK_32_WOW 0x10000000
|
||||
|
||||
typedef HANDLE HWND;
|
||||
typedef HANDLE HBITMAP;
|
||||
|
||||
typedef struct _CREDUI_INFOA
|
||||
{
|
||||
DWORD cbSize;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
#include <winpr/io.h>
|
||||
#include <winpr/error.h>
|
||||
|
||||
@ -37,30 +38,6 @@
|
||||
#define INVALID_SET_FILE_POINTER ((DWORD) - 1)
|
||||
#define INVALID_FILE_ATTRIBUTES ((DWORD) - 1)
|
||||
|
||||
#define FILE_READ_DATA 0x0001
|
||||
#define FILE_LIST_DIRECTORY 0x0001
|
||||
#define FILE_WRITE_DATA 0x0002
|
||||
#define FILE_ADD_FILE 0x0002
|
||||
#define FILE_APPEND_DATA 0x0004
|
||||
#define FILE_ADD_SUBDIRECTORY 0x0004
|
||||
#define FILE_CREATE_PIPE_INSTANCE 0x0004
|
||||
#define FILE_READ_EA 0x0008
|
||||
#define FILE_WRITE_EA 0x0010
|
||||
#define FILE_EXECUTE 0x0020
|
||||
#define FILE_TRAVERSE 0x0020
|
||||
#define FILE_DELETE_CHILD 0x0040
|
||||
#define FILE_READ_ATTRIBUTES 0x0080
|
||||
#define FILE_WRITE_ATTRIBUTES 0x0100
|
||||
|
||||
#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
|
||||
#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
|
||||
#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
|
||||
#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
|
||||
|
||||
#define FILE_SHARE_READ 0x00000001
|
||||
#define FILE_SHARE_WRITE 0x00000002
|
||||
#define FILE_SHARE_DELETE 0x00000004
|
||||
|
||||
#define FILE_ATTRIBUTE_READONLY 0x00000001
|
||||
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
|
||||
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
|
||||
|
@ -25,24 +25,7 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define GENERIC_READ 0x80000000
|
||||
#define GENERIC_WRITE 0x40000000
|
||||
#define GENERIC_EXECUTE 0x20000000
|
||||
#define GENERIC_ALL 0x10000000
|
||||
|
||||
#define DELETE 0x00010000
|
||||
#define READ_CONTROL 0x00020000
|
||||
#define WRITE_DAC 0x00040000
|
||||
#define WRITE_OWNER 0x00080000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define STANDARD_RIGHTS_REQUIRED 0x000F0000
|
||||
#define STANDARD_RIGHTS_READ 0x00020000
|
||||
#define STANDARD_RIGHTS_WRITE 0x00020000
|
||||
#define STANDARD_RIGHTS_EXECUTE 0x00020000
|
||||
#define STANDARD_RIGHTS_ALL 0x001F0000
|
||||
#define SPECIFIC_RIGHTS_ALL 0x0000FFFF
|
||||
#define ACCESS_SYSTEM_SECURITY 0x01000000
|
||||
#define MAXIMUM_ALLOWED 0x02000000
|
||||
#include <winpr/nt.h>
|
||||
|
||||
typedef struct _OVERLAPPED
|
||||
{
|
||||
|
1405
winpr/include/winpr/nt.h
Normal file
1405
winpr/include/winpr/nt.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,8 @@
|
||||
#ifndef WINPR_UTILS_PRINT_H
|
||||
#define WINPR_UTILS_PRINT_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
@ -32,6 +34,8 @@ extern "C" {
|
||||
WINPR_API void winpr_HexDump(BYTE* data, int length);
|
||||
|
||||
WINPR_API int wprintfx(const char *fmt, ...);
|
||||
WINPR_API int wvprintfx(const char *fmt, va_list args);
|
||||
WINPR_API int wvsnprintfx(char *buffer, size_t bufferSize, const char* fmt, va_list args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ extern "C" {
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
#include <winpr/io.h>
|
||||
#include <winpr/error.h>
|
||||
|
||||
@ -106,9 +107,6 @@ extern "C" {
|
||||
typedef HANDLE HKEY;
|
||||
typedef HANDLE* PHKEY;
|
||||
|
||||
typedef DWORD ACCESS_MASK;
|
||||
typedef ACCESS_MASK* PACCESS_MASK;
|
||||
|
||||
typedef ACCESS_MASK REGSAM;
|
||||
|
||||
#define HKEY_CLASSES_ROOT ((HKEY) (LONG_PTR) (LONG) 0x80000000)
|
||||
|
@ -30,12 +30,7 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef struct _LSA_UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
|
||||
#include <winpr/nt.h>
|
||||
|
||||
#define SECURITY_MANDATORY_UNTRUSTED_RID 0x0000
|
||||
#define SECURITY_MANDATORY_LOW_RID 0x1000
|
||||
|
166
winpr/include/winpr/wlog.h
Normal file
166
winpr/include/winpr/wlog.h
Normal file
@ -0,0 +1,166 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* WinPR Logger
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 WINPR_LOG_H
|
||||
#define WINPR_LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
typedef struct _wLog wLog;
|
||||
typedef struct _wLogMessage wLogMessage;
|
||||
typedef struct _wLogLayout wLogLayout;
|
||||
typedef struct _wLogAppender wLogAppender;
|
||||
|
||||
/**
|
||||
* Log Levels
|
||||
*/
|
||||
|
||||
#define WLOG_TRACE 0
|
||||
#define WLOG_DEBUG 1
|
||||
#define WLOG_INFO 2
|
||||
#define WLOG_WARN 3
|
||||
#define WLOG_ERROR 4
|
||||
#define WLOG_FATAL 5
|
||||
#define WLOG_OFF 6
|
||||
|
||||
/**
|
||||
* Log Message
|
||||
*/
|
||||
|
||||
#define WLOG_MESSAGE_STRING 0
|
||||
|
||||
struct _wLogMessage
|
||||
{
|
||||
DWORD Type;
|
||||
|
||||
DWORD Level;
|
||||
|
||||
LPSTR PrefixString;
|
||||
|
||||
LPSTR FormatString;
|
||||
LPSTR TextString;
|
||||
|
||||
DWORD LineNumber; /* __LINE__ */
|
||||
LPCSTR FileName; /* __FILE__ */
|
||||
LPCSTR FunctionName; /* __FUNCTION__ */
|
||||
};
|
||||
|
||||
/**
|
||||
* Log Layout
|
||||
*/
|
||||
|
||||
struct _wLogLayout
|
||||
{
|
||||
DWORD Type;
|
||||
|
||||
LPSTR FormatString;
|
||||
};
|
||||
|
||||
/**
|
||||
* Log Appenders
|
||||
*/
|
||||
|
||||
#define WLOG_APPENDER_CONSOLE 0
|
||||
#define WLOG_APPENDER_FILE 1
|
||||
|
||||
typedef int (*WLOG_APPENDER_OPEN_FN)(wLog* log, wLogAppender* appender);
|
||||
typedef int (*WLOG_APPENDER_CLOSE_FN)(wLog* log, wLogAppender* appender);
|
||||
typedef int (*WLOG_APPENDER_WRITE_MESSAGE_FN)(wLog* log, wLogAppender* appender, wLogMessage* message);
|
||||
|
||||
#define WLOG_APPENDER_COMMON() \
|
||||
DWORD Type; \
|
||||
wLogLayout* Layout; \
|
||||
WLOG_APPENDER_OPEN_FN Open; \
|
||||
WLOG_APPENDER_CLOSE_FN Close; \
|
||||
WLOG_APPENDER_WRITE_MESSAGE_FN WriteMessage
|
||||
|
||||
struct _wLogAppender
|
||||
{
|
||||
WLOG_APPENDER_COMMON();
|
||||
};
|
||||
|
||||
#define WLOG_CONSOLE_STDOUT 1
|
||||
#define WLOG_CONSOLE_STDERR 2
|
||||
|
||||
struct _wLogConsoleAppender
|
||||
{
|
||||
WLOG_APPENDER_COMMON();
|
||||
|
||||
int outputStream;
|
||||
};
|
||||
typedef struct _wLogConsoleAppender wLogConsoleAppender;
|
||||
|
||||
struct _wLogFileAppender
|
||||
{
|
||||
WLOG_APPENDER_COMMON();
|
||||
|
||||
char* FileName;
|
||||
FILE* FileDescriptor;
|
||||
};
|
||||
typedef struct _wLogFileAppender wLogFileAppender;
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
|
||||
struct _wLog
|
||||
{
|
||||
LPSTR Name;
|
||||
DWORD Level;
|
||||
|
||||
wLogAppender* Appender;
|
||||
};
|
||||
|
||||
WINPR_API void WLog_PrintMessage(wLog* log, wLogMessage* message, ...);
|
||||
|
||||
#define WLog_Print(_log, _log_level, _fmt, ...) \
|
||||
if (_log_level <= _log->Level) { \
|
||||
wLogMessage _log_message; \
|
||||
_log_message.Type = WLOG_MESSAGE_STRING; \
|
||||
_log_message.Level = _log_level; \
|
||||
_log_message.FormatString = _fmt; \
|
||||
_log_message.LineNumber = __LINE__; \
|
||||
_log_message.FileName = __FILE__; \
|
||||
_log_message.FunctionName = __FUNCTION__; \
|
||||
WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
WINPR_API DWORD WLog_GetLogLevel(wLog* log);
|
||||
WINPR_API void WLog_SetLogLevel(wLog* log, DWORD logLevel);
|
||||
|
||||
WINPR_API wLogAppender* WLog_GetLogAppender(wLog* log);
|
||||
WINPR_API void WLog_SetLogAppenderType(wLog* log, DWORD logAppenderType);
|
||||
|
||||
WINPR_API int WLog_OpenAppender(wLog* log);
|
||||
WINPR_API int WLog_CloseAppender(wLog* log);
|
||||
|
||||
WINPR_API void WLog_ConsoleAppender_SetOutputStream(wLog* log, wLogConsoleAppender* appender, int outputStream);
|
||||
|
||||
WINPR_API void WLog_FileAppender_SetOutputFileName(wLog* log, wLogFileAppender* appender, const char* filename);
|
||||
|
||||
WINPR_API wLogLayout* WLog_GetLogLayout(wLog* log);
|
||||
WINPR_API void WLog_Layout_SetPrefixFormat(wLog* log, wLogLayout* layout, const char* format);
|
||||
|
||||
WINPR_API wLog* WLog_New(LPCSTR name);
|
||||
WINPR_API void WLog_Free(wLog* log);
|
||||
|
||||
#endif /* WINPR_WLOG_H */
|
1094
winpr/include/winpr/wtsapi.h
Normal file
1094
winpr/include/winpr/wtsapi.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -83,6 +83,8 @@ typedef short SHORT;
|
||||
typedef void* HANDLE, *PHANDLE, *LPHANDLE;
|
||||
typedef HANDLE HINSTANCE;
|
||||
typedef HANDLE HMODULE;
|
||||
typedef HANDLE HWND;
|
||||
typedef HANDLE HBITMAP;
|
||||
|
||||
typedef DWORD HCALL;
|
||||
typedef int INT, *LPINT;
|
||||
@ -113,7 +115,6 @@ typedef WCHAR* LPWSTR, *PWSTR, *LPWCH;
|
||||
typedef const WCHAR *LPCWSTR,*PCWSTR;
|
||||
|
||||
typedef unsigned __int64 QWORD;
|
||||
typedef UCHAR* STRING;
|
||||
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned char UINT8;
|
||||
@ -158,6 +159,9 @@ typedef struct _LUID
|
||||
LONG HighPart;
|
||||
} LUID, *PLUID;
|
||||
|
||||
typedef GUID IID;
|
||||
typedef IID* REFIID;
|
||||
|
||||
#ifdef UNICODE
|
||||
#define _T(x) L ## x
|
||||
#else
|
||||
|
49
winpr/libwinpr/com/CMakeLists.txt
Normal file
49
winpr/libwinpr/com/CMakeLists.txt
Normal file
@ -0,0 +1,49 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-com cmake build script
|
||||
#
|
||||
# Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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 "winpr-com")
|
||||
set(MODULE_PREFIX "WINPR_COM")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
com.c)
|
||||
|
||||
if(MSVC AND (NOT MONOLITHIC_BUILD))
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
|
||||
endif()
|
||||
|
||||
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
SOURCES ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
|
||||
|
||||
if(WIN32)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} credui)
|
||||
endif()
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(WINPR_LIBS ${WINPR_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 "WinPR")
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
9
winpr/libwinpr/com/ModuleOptions.cmake
Normal file
9
winpr/libwinpr/com/ModuleOptions.cmake
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
set(MINWIN_LAYER "1")
|
||||
set(MINWIN_GROUP "core")
|
||||
set(MINWIN_MAJOR_VERSION "1")
|
||||
set(MINWIN_MINOR_VERSION "0")
|
||||
set(MINWIN_SHORT_NAME "com")
|
||||
set(MINWIN_LONG_NAME "Component Object Model (COM)")
|
||||
set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}")
|
||||
|
115
winpr/libwinpr/com/com.c
Normal file
115
winpr/libwinpr/com/com.c
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Component Object Model (COM)
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 <winpr/crt.h>
|
||||
|
||||
/**
|
||||
* api-ms-win-core-com-l1-1-0.dll:
|
||||
*
|
||||
* CLSIDFromProgID
|
||||
* CLSIDFromString
|
||||
* CoAddRefServerProcess
|
||||
* CoAllowUnmarshalerCLSID
|
||||
* CoCancelCall
|
||||
* CoCopyProxy
|
||||
* CoCreateFreeThreadedMarshaler
|
||||
* CoCreateGuid
|
||||
* CoCreateInstance
|
||||
* CoCreateInstanceEx
|
||||
* CoCreateInstanceFromApp
|
||||
* CoDecodeProxy
|
||||
* CoDecrementMTAUsage
|
||||
* CoDisableCallCancellation
|
||||
* CoDisconnectContext
|
||||
* CoDisconnectObject
|
||||
* CoEnableCallCancellation
|
||||
* CoFreeUnusedLibraries
|
||||
* CoFreeUnusedLibrariesEx
|
||||
* CoGetApartmentType
|
||||
* CoGetCallContext
|
||||
* CoGetCallerTID
|
||||
* CoGetCancelObject
|
||||
* CoGetClassObject
|
||||
* CoGetContextToken
|
||||
* CoGetCurrentLogicalThreadId
|
||||
* CoGetCurrentProcess
|
||||
* CoGetDefaultContext
|
||||
* CoGetInterfaceAndReleaseStream
|
||||
* CoGetMalloc
|
||||
* CoGetMarshalSizeMax
|
||||
* CoGetObjectContext
|
||||
* CoGetPSClsid
|
||||
* CoGetStandardMarshal
|
||||
* CoGetStdMarshalEx
|
||||
* CoGetTreatAsClass
|
||||
* CoImpersonateClient
|
||||
* CoIncrementMTAUsage
|
||||
* CoInitializeEx
|
||||
* CoInitializeSecurity
|
||||
* CoInvalidateRemoteMachineBindings
|
||||
* CoIsHandlerConnected
|
||||
* CoLockObjectExternal
|
||||
* CoMarshalHresult
|
||||
* CoMarshalInterface
|
||||
* CoMarshalInterThreadInterfaceInStream
|
||||
* CoQueryAuthenticationServices
|
||||
* CoQueryClientBlanket
|
||||
* CoQueryProxyBlanket
|
||||
* CoRegisterClassObject
|
||||
* CoRegisterPSClsid
|
||||
* CoRegisterSurrogate
|
||||
* CoReleaseMarshalData
|
||||
* CoReleaseServerProcess
|
||||
* CoResumeClassObjects
|
||||
* CoRevertToSelf
|
||||
* CoRevokeClassObject
|
||||
* CoSetCancelObject
|
||||
* CoSetProxyBlanket
|
||||
* CoSuspendClassObjects
|
||||
* CoSwitchCallContext
|
||||
* CoTaskMemAlloc
|
||||
* CoTaskMemFree
|
||||
* CoTaskMemRealloc
|
||||
* CoTestCancel
|
||||
* CoUninitialize
|
||||
* CoUnmarshalHresult
|
||||
* CoUnmarshalInterface
|
||||
* CoWaitForMultipleHandles
|
||||
* CoWaitForMultipleObjects
|
||||
* CreateStreamOnHGlobal
|
||||
* FreePropVariantArray
|
||||
* GetHGlobalFromStream
|
||||
* IIDFromString
|
||||
* ProgIDFromCLSID
|
||||
* PropVariantClear
|
||||
* PropVariantCopy
|
||||
* StringFromCLSID
|
||||
* StringFromGUID2
|
||||
* StringFromIID
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
|
||||
|
||||
#endif
|
2
winpr/libwinpr/com/module.def
Normal file
2
winpr/libwinpr/com/module.def
Normal file
@ -0,0 +1,2 @@
|
||||
LIBRARY "libwinpr-com"
|
||||
EXPORTS
|
3
winpr/libwinpr/com/test/.gitignore
vendored
Normal file
3
winpr/libwinpr/com/test/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
TestCom
|
||||
TestCom.c
|
||||
|
31
winpr/libwinpr/com/test/CMakeLists.txt
Normal file
31
winpr/libwinpr/com/test/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
set(MODULE_NAME "TestCom")
|
||||
set(MODULE_PREFIX "TEST_COM")
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestComReference.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-com)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
|
8
winpr/libwinpr/com/test/TestComReference.c
Normal file
8
winpr/libwinpr/com/test/TestComReference.c
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
int TestComReference(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -31,10 +31,20 @@ add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE winpr
|
||||
MODULES winpr-nt)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
|
||||
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 "WinPR")
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
@ -23,25 +23,12 @@
|
||||
|
||||
#include <winpr/error.h>
|
||||
|
||||
/**
|
||||
* api-ms-win-core-errorhandling-l1-1-1.dll:
|
||||
*
|
||||
* GetErrorMode
|
||||
* SetErrorMode
|
||||
* GetLastError
|
||||
* SetLastError
|
||||
* RestoreLastError
|
||||
* RaiseException
|
||||
* UnhandledExceptionFilter
|
||||
* SetUnhandledExceptionFilter
|
||||
* AddVectoredExceptionHandler
|
||||
* RemoveVectoredExceptionHandler
|
||||
* AddVectoredContinueHandler
|
||||
* RemoveVectoredContinueHandler
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
|
||||
UINT GetErrorMode(void)
|
||||
{
|
||||
return 0;
|
||||
@ -54,12 +41,12 @@ UINT SetErrorMode(UINT uMode)
|
||||
|
||||
DWORD GetLastError(VOID)
|
||||
{
|
||||
return 0;
|
||||
return NtCurrentTeb()->LastErrorValue;
|
||||
}
|
||||
|
||||
VOID SetLastError(DWORD dwErrCode)
|
||||
{
|
||||
|
||||
NtCurrentTeb()->LastErrorValue = dwErrCode;
|
||||
}
|
||||
|
||||
VOID RestoreLastError(DWORD dwErrCode)
|
||||
|
3
winpr/libwinpr/error/test/.gitignore
vendored
Normal file
3
winpr/libwinpr/error/test/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
TestError
|
||||
TestError.c
|
||||
|
31
winpr/libwinpr/error/test/CMakeLists.txt
Normal file
31
winpr/libwinpr/error/test/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
set(MODULE_NAME "TestError")
|
||||
set(MODULE_PREFIX "TEST_ERROR")
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestErrorSetLastError.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-synch winpr-thread winpr-error)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
|
89
winpr/libwinpr/error/test/TestErrorSetLastError.c
Normal file
89
winpr/libwinpr/error/test/TestErrorSetLastError.c
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <winpr/error.h>
|
||||
|
||||
static int status = 0;
|
||||
|
||||
static DWORD errors[4] =
|
||||
{
|
||||
ERROR_INVALID_DATA,
|
||||
ERROR_BROKEN_PIPE,
|
||||
ERROR_INVALID_NAME,
|
||||
ERROR_BAD_ARGUMENTS
|
||||
};
|
||||
|
||||
static void* test_error_thread(void* arg)
|
||||
{
|
||||
int id;
|
||||
DWORD error;
|
||||
|
||||
id = (int) (size_t) arg;
|
||||
|
||||
error = errors[id];
|
||||
|
||||
SetLastError(error);
|
||||
|
||||
Sleep(10);
|
||||
|
||||
error = GetLastError();
|
||||
|
||||
if (error != errors[id])
|
||||
{
|
||||
printf("GetLastError() failure (thread %d): Expected: 0x%04X, Actual: 0x%04X\n",
|
||||
id, errors[id], error);
|
||||
|
||||
if (!status)
|
||||
status = -1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int TestErrorSetLastError(int argc, char* argv[])
|
||||
{
|
||||
DWORD error;
|
||||
HANDLE threads[4];
|
||||
|
||||
SetLastError(ERROR_ACCESS_DENIED);
|
||||
|
||||
error = GetLastError();
|
||||
|
||||
if (error != ERROR_ACCESS_DENIED)
|
||||
{
|
||||
printf("GetLastError() failure: Expected: 0x%04X, Actual: 0x%04X\n",
|
||||
ERROR_ACCESS_DENIED, error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 0, 0, NULL);
|
||||
threads[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 1, 0, NULL);
|
||||
threads[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 2, 0, NULL);
|
||||
threads[3] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 3, 0, NULL);
|
||||
|
||||
WaitForSingleObject(threads[0], INFINITE);
|
||||
WaitForSingleObject(threads[1], INFINITE);
|
||||
WaitForSingleObject(threads[2], INFINITE);
|
||||
WaitForSingleObject(threads[3], INFINITE);
|
||||
|
||||
CloseHandle(threads[0]);
|
||||
CloseHandle(threads[1]);
|
||||
CloseHandle(threads[2]);
|
||||
CloseHandle(threads[3]);
|
||||
|
||||
error = GetLastError();
|
||||
|
||||
if (error != ERROR_ACCESS_DENIED)
|
||||
{
|
||||
printf("GetLastError() failure: Expected: 0x%04X, Actual: 0x%04X\n",
|
||||
ERROR_ACCESS_DENIED, error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-handle winpr-path)
|
||||
MODULES winpr-crt winpr-handle winpr-path winpr-synch)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/handle.h>
|
||||
#include <winpr/platform.h>
|
||||
|
||||
#include <winpr/file.h>
|
||||
|
||||
@ -124,6 +125,21 @@
|
||||
* http://download.microsoft.com/download/4/3/8/43889780-8d45-4b2e-9d3a-c696a890309f/File%20System%20Behavior%20Overview.pdf
|
||||
*/
|
||||
|
||||
/**
|
||||
* Asynchronous I/O - The GNU C Library:
|
||||
* http://www.gnu.org/software/libc/manual/html_node/Asynchronous-I_002fO.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* aio.h - asynchronous input and output:
|
||||
* http://pubs.opengroup.org/onlinepubs/009695399/basedefs/aio.h.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Asynchronous I/O User Guide:
|
||||
* http://code.google.com/p/kernel/wiki/AIOUserGuide
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
@ -142,6 +158,14 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef HAVE_AIO_H
|
||||
#undef HAVE_AIO_H /* disable for now, incomplete */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AIO_H
|
||||
#include <aio.h>
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <sys/vfs.h>
|
||||
#else
|
||||
@ -184,6 +208,7 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
pNamedPipe->nOutBufferSize = 0;
|
||||
pNamedPipe->nInBufferSize = 0;
|
||||
pNamedPipe->nDefaultTimeOut = 0;
|
||||
pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
|
||||
|
||||
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
|
||||
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
|
||||
@ -255,20 +280,66 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
|
||||
pipe = (WINPR_NAMED_PIPE*) Object;
|
||||
|
||||
status = nNumberOfBytesToRead;
|
||||
|
||||
if (pipe->clientfd != -1)
|
||||
status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
if (status < 0)
|
||||
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
|
||||
{
|
||||
*lpNumberOfBytesRead = 0;
|
||||
return FALSE;
|
||||
}
|
||||
status = nNumberOfBytesToRead;
|
||||
|
||||
*lpNumberOfBytesRead = status;
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
*lpNumberOfBytesRead = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesRead = status;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Overlapped I/O */
|
||||
|
||||
if (!lpOverlapped)
|
||||
return FALSE;
|
||||
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
pipe->lpOverlapped = lpOverlapped;
|
||||
|
||||
#ifdef HAVE_AIO_H
|
||||
{
|
||||
struct aiocb cb;
|
||||
|
||||
ZeroMemory(&cb, sizeof(struct aiocb));
|
||||
cb.aio_nbytes = nNumberOfBytesToRead;
|
||||
cb.aio_fildes = pipe->clientfd;
|
||||
cb.aio_offset = lpOverlapped->Offset;
|
||||
cb.aio_buf = lpBuffer;
|
||||
|
||||
status = aio_read(&cb);
|
||||
|
||||
printf("aio_read status: %d\n", status);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
/* synchronous behavior */
|
||||
|
||||
lpOverlapped->Internal = 0;
|
||||
lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToRead;
|
||||
lpOverlapped->Pointer = (PVOID) lpBuffer;
|
||||
|
||||
SetEvent(lpOverlapped->hEvent);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -317,20 +388,66 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
|
||||
pipe = (WINPR_NAMED_PIPE*) Object;
|
||||
|
||||
status = nNumberOfBytesToWrite;
|
||||
|
||||
if (pipe->clientfd != -1)
|
||||
status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
if (status < 0)
|
||||
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
|
||||
{
|
||||
*lpNumberOfBytesWritten = 0;
|
||||
return FALSE;
|
||||
}
|
||||
status = nNumberOfBytesToWrite;
|
||||
|
||||
*lpNumberOfBytesWritten = status;
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
*lpNumberOfBytesWritten = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesWritten = status;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Overlapped I/O */
|
||||
|
||||
if (!lpOverlapped)
|
||||
return FALSE;
|
||||
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
pipe->lpOverlapped = lpOverlapped;
|
||||
|
||||
#ifdef HAVE_AIO_H
|
||||
{
|
||||
struct aiocb cb;
|
||||
|
||||
ZeroMemory(&cb, sizeof(struct aiocb));
|
||||
cb.aio_nbytes = nNumberOfBytesToWrite;
|
||||
cb.aio_fildes = pipe->clientfd;
|
||||
cb.aio_offset = lpOverlapped->Offset;
|
||||
cb.aio_buf = lpBuffer;
|
||||
|
||||
status = aio_write(&cb);
|
||||
|
||||
printf("aio_write status: %d\n", status);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
/* synchronous behavior */
|
||||
|
||||
lpOverlapped->Internal = 1;
|
||||
lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToWrite;
|
||||
lpOverlapped->Pointer = (PVOID) lpBuffer;
|
||||
|
||||
SetEvent(lpOverlapped->hEvent);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -23,25 +23,69 @@
|
||||
|
||||
#include <winpr/io.h>
|
||||
|
||||
/**
|
||||
* api-ms-win-core-io-l1-1-1.dll:
|
||||
*
|
||||
* GetOverlappedResult
|
||||
* GetOverlappedResultEx
|
||||
* DeviceIoControl
|
||||
* CreateIoCompletionPort
|
||||
* GetQueuedCompletionStatus
|
||||
* GetQueuedCompletionStatusEx
|
||||
* PostQueuedCompletionStatus
|
||||
* CancelIo
|
||||
* CancelIoEx
|
||||
* CancelSynchronousIo
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "../handle/handle.h"
|
||||
|
||||
#include "../pipe/pipe.h"
|
||||
|
||||
BOOL GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait)
|
||||
{
|
||||
ULONG Type;
|
||||
PVOID Object;
|
||||
|
||||
if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
|
||||
return FALSE;
|
||||
|
||||
else if (Type == HANDLE_TYPE_NAMED_PIPE)
|
||||
{
|
||||
int status;
|
||||
DWORD request;
|
||||
PVOID lpBuffer;
|
||||
DWORD nNumberOfBytes;
|
||||
WINPR_NAMED_PIPE* pipe;
|
||||
|
||||
pipe = (WINPR_NAMED_PIPE*) Object;
|
||||
|
||||
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
|
||||
return FALSE;
|
||||
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
lpBuffer = lpOverlapped->Pointer;
|
||||
request = (DWORD) lpOverlapped->Internal;
|
||||
nNumberOfBytes = (DWORD) lpOverlapped->InternalHigh;
|
||||
|
||||
if (request == 0)
|
||||
{
|
||||
status = read(pipe->clientfd, lpBuffer, nNumberOfBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = write(pipe->clientfd, lpBuffer, nNumberOfBytes);
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesTransferred = status;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
53
winpr/libwinpr/nt/CMakeLists.txt
Normal file
53
winpr/libwinpr/nt/CMakeLists.txt
Normal file
@ -0,0 +1,53 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-nt cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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 "winpr-nt")
|
||||
set(MODULE_PREFIX "WINPR_NT")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
nt.c)
|
||||
|
||||
if(MSVC AND (NOT MONOLITHIC_BUILD))
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
|
||||
endif()
|
||||
|
||||
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
SOURCES ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_DL_LIBS})
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES SunOS)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt)
|
||||
endif()
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(WINPR_LIBS ${WINPR_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 "WinPR")
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
8
winpr/libwinpr/nt/ModuleOptions.cmake
Normal file
8
winpr/libwinpr/nt/ModuleOptions.cmake
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
set(MINWIN_LAYER "0")
|
||||
set(MINWIN_GROUP "none")
|
||||
set(MINWIN_MAJOR_VERSION "0")
|
||||
set(MINWIN_MINOR_VERSION "0")
|
||||
set(MINWIN_SHORT_NAME "nt")
|
||||
set(MINWIN_LONG_NAME "Windows Native System Services")
|
||||
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")
|
3
winpr/libwinpr/nt/module.def
Normal file
3
winpr/libwinpr/nt/module.def
Normal file
@ -0,0 +1,3 @@
|
||||
LIBRARY "libwinpr-nt"
|
||||
EXPORTS
|
||||
|
387
winpr/libwinpr/nt/nt.c
Normal file
387
winpr/libwinpr/nt/nt.c
Normal file
@ -0,0 +1,387 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Windows Native System Services
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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 <winpr/nt.h>
|
||||
|
||||
/**
|
||||
* NtXxx Routines:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff557720/
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
/**
|
||||
* The current implementation of NtCurrentTeb() is not the most efficient
|
||||
* but it's a starting point. Beware of potential performance bottlenecks
|
||||
* caused by multithreaded usage of SetLastError/GetLastError.
|
||||
*/
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static PPEB g_ProcessEnvironmentBlock = NULL;
|
||||
|
||||
static void NtThreadEnvironmentBlockFree(PTEB teb);
|
||||
static void NtProcessEnvironmentBlockFree(PPEB peb);
|
||||
|
||||
static PTEB NtThreadEnvironmentBlockNew()
|
||||
{
|
||||
PTEB teb = NULL;
|
||||
pthread_key_t key;
|
||||
|
||||
teb = (PTEB) malloc(sizeof(TEB));
|
||||
|
||||
if (teb)
|
||||
{
|
||||
ZeroMemory(teb, sizeof(TEB));
|
||||
|
||||
/**
|
||||
* We are not really using the key, but it provides an automatic way
|
||||
* of calling NtThreadEnvironmentBlockFree on thread termination for
|
||||
* the current Thread Environment Block.
|
||||
*/
|
||||
|
||||
pthread_key_create(&key, (void (*)(void*)) NtThreadEnvironmentBlockFree);
|
||||
pthread_setspecific(key, (void*) teb);
|
||||
}
|
||||
|
||||
return teb;
|
||||
}
|
||||
|
||||
static void NtThreadEnvironmentBlockFree(PTEB teb)
|
||||
{
|
||||
DWORD index;
|
||||
PPEB peb = NULL;
|
||||
|
||||
peb = teb->ProcessEnvironmentBlock;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
for (index = 0; index < peb->ThreadArraySize; index++)
|
||||
{
|
||||
if (peb->Threads[index].ThreadEnvironmentBlock == teb)
|
||||
{
|
||||
peb->Threads[index].ThreadId = 0;
|
||||
peb->Threads[index].ThreadEnvironmentBlock = NULL;
|
||||
peb->ThreadCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!peb->ThreadCount)
|
||||
{
|
||||
NtProcessEnvironmentBlockFree(peb);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
free(teb);
|
||||
}
|
||||
|
||||
static PPEB NtProcessEnvironmentBlockNew()
|
||||
{
|
||||
PPEB peb = NULL;
|
||||
|
||||
peb = (PPEB) malloc(sizeof(PEB));
|
||||
|
||||
if (peb)
|
||||
{
|
||||
ZeroMemory(peb, sizeof(PEB));
|
||||
|
||||
peb->ThreadCount = 0;
|
||||
peb->ThreadArraySize = 64;
|
||||
peb->Threads = (THREAD_BLOCK_ID*) malloc(sizeof(THREAD_BLOCK_ID) * peb->ThreadArraySize);
|
||||
|
||||
if (peb->Threads)
|
||||
{
|
||||
ZeroMemory(peb->Threads, sizeof(THREAD_BLOCK_ID) * peb->ThreadArraySize);
|
||||
}
|
||||
}
|
||||
|
||||
return peb;
|
||||
}
|
||||
|
||||
static void NtProcessEnvironmentBlockFree(PPEB peb)
|
||||
{
|
||||
if (peb)
|
||||
{
|
||||
free(peb->Threads);
|
||||
free(peb);
|
||||
}
|
||||
|
||||
g_ProcessEnvironmentBlock = NULL;
|
||||
}
|
||||
|
||||
PPEB NtCurrentPeb(void)
|
||||
{
|
||||
PPEB peb = NULL;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
if (!g_ProcessEnvironmentBlock)
|
||||
g_ProcessEnvironmentBlock = NtProcessEnvironmentBlockNew();
|
||||
|
||||
peb = g_ProcessEnvironmentBlock;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
return peb;
|
||||
}
|
||||
|
||||
PTEB NtCurrentTeb(void)
|
||||
{
|
||||
DWORD index;
|
||||
int freeIndex;
|
||||
DWORD ThreadId;
|
||||
PPEB peb = NULL;
|
||||
PTEB teb = NULL;
|
||||
|
||||
peb = NtCurrentPeb();
|
||||
|
||||
ThreadId = (DWORD) pthread_self();
|
||||
|
||||
freeIndex = -1;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
for (index = 0; index < peb->ThreadArraySize; index++)
|
||||
{
|
||||
if (!peb->Threads[index].ThreadId)
|
||||
{
|
||||
if (freeIndex < 0)
|
||||
freeIndex = (int) index;
|
||||
}
|
||||
|
||||
if (peb->Threads[index].ThreadId == ThreadId)
|
||||
{
|
||||
teb = peb->Threads[index].ThreadEnvironmentBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!teb)
|
||||
{
|
||||
if (freeIndex >= 0)
|
||||
{
|
||||
teb = NtThreadEnvironmentBlockNew();
|
||||
peb->Threads[freeIndex].ThreadEnvironmentBlock = teb;
|
||||
peb->Threads[freeIndex].ThreadId = ThreadId;
|
||||
peb->ThreadCount++;
|
||||
|
||||
teb->ProcessEnvironmentBlock = peb;
|
||||
teb->LastErrorValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
return teb;
|
||||
}
|
||||
|
||||
/**
|
||||
* RtlInitAnsiString routine:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff561918/
|
||||
*/
|
||||
|
||||
VOID RtlInitAnsiString(PANSI_STRING DestinationString, PCSZ SourceString)
|
||||
{
|
||||
DestinationString->Buffer = (PCHAR) SourceString;
|
||||
|
||||
if (!SourceString)
|
||||
{
|
||||
DestinationString->Length = 0;
|
||||
DestinationString->MaximumLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
USHORT length = (USHORT) strlen(SourceString);
|
||||
DestinationString->Length = length;
|
||||
DestinationString->MaximumLength = length + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RtlInitUnicodeString routine:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff561934/
|
||||
*/
|
||||
|
||||
VOID RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
|
||||
{
|
||||
DestinationString->Buffer = (PWSTR) SourceString;
|
||||
|
||||
if (!SourceString)
|
||||
{
|
||||
DestinationString->Length = 0;
|
||||
DestinationString->MaximumLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
USHORT length = (USHORT) _wcslen(SourceString);
|
||||
DestinationString->Length = length * 2;
|
||||
DestinationString->MaximumLength = (length + 1) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RtlAnsiStringToUnicodeString function:
|
||||
* http://msdn.microsoft.com/en-us/library/ms648413/
|
||||
*/
|
||||
|
||||
NTSTATUS RtlAnsiStringToUnicodeString(PUNICODE_STRING DestinationString,
|
||||
PCANSI_STRING SourceString, BOOLEAN AllocateDestinationString)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!SourceString)
|
||||
{
|
||||
RtlInitUnicodeString(DestinationString, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AllocateDestinationString)
|
||||
{
|
||||
DestinationString->Length = SourceString->Length * 2;
|
||||
DestinationString->MaximumLength = SourceString->MaximumLength * 2;
|
||||
|
||||
DestinationString->Buffer = (PWSTR) malloc(DestinationString->MaximumLength);
|
||||
|
||||
for (index = 0; index < SourceString->MaximumLength; index++)
|
||||
{
|
||||
DestinationString->Buffer[index] = (WCHAR) SourceString->Buffer[index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* RtlFreeUnicodeString function:
|
||||
* http://msdn.microsoft.com/en-us/library/ms648418/
|
||||
*/
|
||||
|
||||
VOID RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
|
||||
{
|
||||
if (UnicodeString)
|
||||
{
|
||||
if (UnicodeString->Buffer)
|
||||
free(UnicodeString->Buffer);
|
||||
|
||||
UnicodeString->Length = 0;
|
||||
UnicodeString->MaximumLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RtlNtStatusToDosError function:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms680600/
|
||||
*/
|
||||
|
||||
ULONG RtlNtStatusToDosError(NTSTATUS status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* InitializeObjectAttributes macro
|
||||
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff547804/
|
||||
*/
|
||||
|
||||
VOID InitializeObjectAttributes(POBJECT_ATTRIBUTES InitializedAttributes,
|
||||
PUNICODE_STRING ObjectName, ULONG Attributes, HANDLE RootDirectory,
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor)
|
||||
{
|
||||
InitializedAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
|
||||
InitializedAttributes->ObjectName = ObjectName;
|
||||
InitializedAttributes->Attributes = Attributes;
|
||||
InitializedAttributes->RootDirectory = RootDirectory;
|
||||
InitializedAttributes->SecurityDescriptor = SecurityDescriptor;
|
||||
InitializedAttributes->SecurityQualityOfService = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* NtCreateFile function:
|
||||
* http://msdn.microsoft.com/en-us/library/bb432380/
|
||||
*/
|
||||
|
||||
NTSTATUS NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess,
|
||||
ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* NtOpenFile function:
|
||||
* http://msdn.microsoft.com/en-us/library/bb432381/
|
||||
*/
|
||||
|
||||
NTSTATUS NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG ShareAccess, ULONG OpenOptions)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* NtDeviceIoControlFile function:
|
||||
* http://msdn.microsoft.com/en-us/library/ms648411/
|
||||
*/
|
||||
|
||||
NTSTATUS NtDeviceIoControlFile(HANDLE FileHandle, HANDLE Event,
|
||||
PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength,
|
||||
PVOID OutputBuffer, ULONG OutputBufferLength)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* NtClose function:
|
||||
* http://msdn.microsoft.com/en-us/library/ms648410/
|
||||
*/
|
||||
|
||||
NTSTATUS NtClose(HANDLE Handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* NtWaitForSingleObject function:
|
||||
* http://msdn.microsoft.com/en-us/library/ms648412/
|
||||
*/
|
||||
|
||||
NTSTATUS NtWaitForSingleObject(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
3
winpr/libwinpr/nt/test/.gitignore
vendored
Normal file
3
winpr/libwinpr/nt/test/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
TestNt
|
||||
TestNt.c
|
||||
|
32
winpr/libwinpr/nt/test/CMakeLists.txt
Normal file
32
winpr/libwinpr/nt/test/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
set(MODULE_NAME "TestNt")
|
||||
set(MODULE_PREFIX "TEST_NT")
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestNtCreateFile.c
|
||||
TestNtCurrentTeb.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-nt)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
|
30
winpr/libwinpr/nt/test/TestNtCreateFile.c
Normal file
30
winpr/libwinpr/nt/test/TestNtCreateFile.c
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
|
||||
int TestNtCreateFile(int argc, char* argv[])
|
||||
{
|
||||
HANDLE handle;
|
||||
NTSTATUS ntstatus;
|
||||
ULONG CreateOptions;
|
||||
ANSI_STRING aString;
|
||||
UNICODE_STRING uString;
|
||||
ACCESS_MASK DesiredAccess = 0;
|
||||
OBJECT_ATTRIBUTES attributes;
|
||||
IO_STATUS_BLOCK ioStatusBlock;
|
||||
|
||||
RtlInitAnsiString(&aString, "\\Device\\FreeRDP\\TEST");
|
||||
RtlAnsiStringToUnicodeString(&uString, &aString, TRUE);
|
||||
|
||||
InitializeObjectAttributes(&attributes, NULL, 0, NULL, NULL);
|
||||
|
||||
DesiredAccess = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
|
||||
CreateOptions = FILE_DIRECTORY_FILE | FILE_WRITE_THROUGH;
|
||||
|
||||
ntstatus = NtCreateFile(&handle, DesiredAccess, &attributes, &ioStatusBlock, 0, 0, 0, CreateOptions, 0, 0, 0);
|
||||
|
||||
RtlFreeUnicodeString(&uString);
|
||||
|
||||
return 0;
|
||||
}
|
20
winpr/libwinpr/nt/test/TestNtCurrentTeb.c
Normal file
20
winpr/libwinpr/nt/test/TestNtCurrentTeb.c
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
|
||||
int TestNtCurrentTeb(int argc, char* argv[])
|
||||
{
|
||||
PTEB teb;
|
||||
|
||||
teb = NtCurrentTeb();
|
||||
|
||||
if (!teb)
|
||||
{
|
||||
printf("NtCurrentTeb() returned NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
||||
pNamedPipe->nOutBufferSize = nOutBufferSize;
|
||||
pNamedPipe->nInBufferSize = nInBufferSize;
|
||||
pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
|
||||
pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
|
||||
|
||||
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
|
||||
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName);
|
||||
@ -177,6 +178,14 @@ BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
|
||||
|
||||
pNamedPipe->clientfd = status;
|
||||
|
||||
if (pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
|
||||
{
|
||||
if (!lpOverlapped)
|
||||
return FALSE;
|
||||
|
||||
SetEvent(lpOverlapped->hEvent);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user