Merge remote-tracking branch 'upstream/master' into httpproxy

Conflicts:
	libfreerdp/core/settings.c
	libfreerdp/core/tcp.c
	libfreerdp/core/transport.c
This commit is contained in:
Christian Plattner 2015-01-22 14:32:15 +01:00
commit 33320a2e02
1292 changed files with 101745 additions and 49026 deletions

6
.gitignore vendored Executable file → Normal file
View File

@ -92,6 +92,7 @@ RelWithDebInfo
# Binaries
*.a
*.o
*.so
*.so.*
*.dylib
@ -105,6 +106,7 @@ client/DirectFB/dfreerdp
server/Sample/sfreerdp-server
server/X11/xfreerdp-server
xcode
libfreerdp/codec/test/TestOpenH264ASM
# Other
*~
@ -113,6 +115,7 @@ Release
Win32
build*/
*.orig
*.msrcIncident
default.log
*Amplifier XE*
@ -122,3 +125,6 @@ default.log
*.txt.user
*.autosave
# etags
TAGS

125
CMakeLists.txt Executable file → Normal file
View File

@ -44,7 +44,6 @@ include(CheckCmakeCompat)
include(CheckIncludeFiles)
include(CheckLibraryExists)
include(CheckStructHasMember)
include(CMakeDetermineSystem)
include(FindPkgConfig)
include(TestBigEndian)
@ -59,10 +58,15 @@ include(GNUInstallDirsWrapper)
include(CMakePackageConfigHelpers)
# Soname versioning
set(BUILD_NUMBER 0)
if ($ENV{BUILD_NUMBER})
set(BUILD_NUMBER $ENV{BUILD_NUMBER})
endif()
set(WITH_LIBRARY_VERSIONING "ON")
set(FREERDP_VERSION_MAJOR "1")
set(FREERDP_VERSION_MINOR "2")
set(FREERDP_VERSION_REVISION "0")
set(FREERDP_VERSION_SUFFIX "beta1")
set(FREERDP_VERSION_SUFFIX "dev")
set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}")
set(FREERDP_VERSION "${FREERDP_API_VERSION}.${FREERDP_VERSION_REVISION}")
if (FREERDP_VERSION_SUFFIX)
@ -76,11 +80,14 @@ if(ANDROID OR IOS)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
endif(ANDROID OR IOS)
include(GetGitRevisionDescription)
git_get_exact_tag(GIT_REVISION --tags --always)
if (${GIT_REVISION} STREQUAL "n/a")
git_rev_parse(GIT_REVISION --short)
endif()
if(ANDROID OR IOS)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
endif(ANDROID OR IOS)
git_describe(GIT_REVISION --match "[0-9]*" --abbrev=4 --tags --always)
message(STATUS "Git Revision ${GIT_REVISION}")
# Turn on solution folders (2.8.4+)
@ -232,9 +239,35 @@ endif()
if(WIN32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUNICODE -D_UNICODE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WIN32_WINNT=0x0501")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN")
# Set product and vendor for dll and exe version information.
set(RC_VERSION_VENDOR "FreeRDP")
set(RC_VERSION_PRODUCT "FreeRDP")
set(RC_VERSION_PATCH ${BUILD_NUMBER})
set(RC_VERSION_DESCRIPTION ${GIT_REVISION})
string(TIMESTAMP RC_VERSION_YEAR "%Y")
if(NOT DEFINED CMAKE_WINDOWS_VERSION)
set(CMAKE_WINDOWS_VERSION "WINXP")
endif()
if(CMAKE_WINDOWS_VERSION STREQUAL "WINXP")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0501 -DWIN32_WINNT=0x0501")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0501 -DWIN32_WINNT=0x0501")
elseif(CMAKE_WINDOWS_VERSION STREQUAL "WIN7")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0601 -DWIN32_WINNT=0x0601")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0601 -DWIN32_WINNT=0x0601")
elseif(CMAKE_WINDOWS_VERSION STREQUAL "WIN8")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0602 -DWIN32_WINNT=0x0602")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0602 -DWIN32_WINNT=0x0602")
endif()
if (FREERDP_EXTERNAL_SSL_PATH)
set(OPENSSL_ROOT_DIR ${FREERDP_EXTERNAL_SSL_PATH})
endif()
endif()
if(IOS)
@ -248,6 +281,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINPR_EXPORTS -DFREERDP_EXPORTS")
if(NOT IOS)
check_include_files(fcntl.h HAVE_FCNTL_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(execinfo.h HAVE_EXECINFO_H)
check_include_files(stdint.h HAVE_STDINT_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
@ -301,6 +335,8 @@ endif(APPLE)
# Android
if(ANDROID)
set(WITH_LIBRARY_VERSIONING "OFF")
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DNDK_DEBUG=1)
@ -369,9 +405,12 @@ 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)
check_include_files(poll.h HAVE_POLL_H)
set(X11_FEATURE_TYPE "RECOMMENDED")
set(WAYLAND_FEATURE_TYPE "RECOMMENDED")
else()
set(X11_FEATURE_TYPE "DISABLED")
set(WAYLAND_FEATURE_TYPE "DISABLED")
endif()
if(WITH_PCSC_WINPR)
@ -381,6 +420,9 @@ endif()
set(X11_FEATURE_PURPOSE "X11")
set(X11_FEATURE_DESCRIPTION "X11 client and server")
set(WAYLAND_FEATURE_PURPOSE "Wayland")
set(WAYLAND_FEATURE_DESCRIPTION "Wayland client")
set(DIRECTFB_FEATURE_TYPE "OPTIONAL")
set(DIRECTFB_FEATURE_PURPOSE "DirectFB")
set(DIRECTFB_FEATURE_DESCRIPTION "DirectFB client")
@ -417,9 +459,13 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED")
set(FFMPEG_FEATURE_PURPOSE "multimedia")
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
set(GSTREAMER_FEATURE_TYPE "RECOMMENDED")
set(GSTREAMER_FEATURE_PURPOSE "multimedia")
set(GSTREAMER_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED")
set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia")
set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
set(IPP_FEATURE_TYPE "OPTIONAL")
set(IPP_FEATURE_PURPOSE "performance")
@ -429,12 +475,17 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
set(JPEG_FEATURE_PURPOSE "codec")
set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
set(OPENH264_FEATURE_TYPE "OPTIONAL")
set(OPENH264_FEATURE_PURPOSE "codec")
set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library")
set(GSM_FEATURE_TYPE "OPTIONAL")
set(GSM_FEATURE_PURPOSE "codec")
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
if(WIN32)
set(X11_FEATURE_TYPE "DISABLED")
set(WAYLAND_FEATURE_TYPE "DISABLED")
set(ZLIB_FEATURE_TYPE "DISABLED")
set(DIRECTFB_FEATURE_TYPE "DISABLED")
set(ALSA_FEATURE_TYPE "DISABLED")
@ -442,40 +493,46 @@ if(WIN32)
set(CUPS_FEATURE_TYPE "DISABLED")
set(PCSC_FEATURE_TYPE "DISABLED")
set(FFMPEG_FEATURE_TYPE "DISABLED")
set(GSTREAMER_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
set(OPENSLES_FEATURE_TYPE "DISABLED")
endif()
if(APPLE)
set(DIRECTFB_FEATURE_TYPE "DISABLED")
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
set(GSTREAMER_FEATURE_TYPE "OPTIONAL")
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
set(X11_FEATURE_TYPE "OPTIONAL")
set(WAYLAND_FEATURE_TYPE "DISABLED")
if(IOS)
set(X11_FEATURE_TYPE "DISABLED")
set(ALSA_FEATURE_TYPE "DISABLED")
set(PULSE_FEATURE_TYPE "DISABLED")
set(CUPS_FEATURE_TYPE "DISABLED")
set(PCSC_FEATURE_TYPE "DISABLED")
set(GSTREAMER_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
endif()
set(OPENSLES_FEATURE_TYPE "DISABLED")
endif()
if(ANDROID)
set(X11_FEATURE_TYPE "DISABLED")
set(WAYLAND_FEATURE_TYPE "DISABLED")
set(DIRECTFB_FEATURE_TYPE "DISABLED")
set(ALSA_FEATURE_TYPE "DISABLED")
set(PULSE_FEATURE_TYPE "DISABLED")
set(CUPS_FEATURE_TYPE "DISABLED")
set(PCSC_FEATURE_TYPE "DISABLED")
set(FFMPEG_FEATURE_TYPE "DISABLED")
set(GSTREAMER_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
set(OPENSLES_FEATURE_TYPE "REQUIRED")
endif()
find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION})
find_feature(Wayland ${WAYLAND_FEATURE_TYPE} ${WAYLAND_FEATURE_PURPOSE} ${WAYLAND_FEATURE_DESCRIPTION})
find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION})
if (${WITH_DIRECTFB})
message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details")
@ -492,9 +549,12 @@ find_feature(Cups ${CUPS_FEATURE_TYPE} ${CUPS_FEATURE_PURPOSE} ${CUPS_FEATURE_DE
find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION})
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION})
find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION})
find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION})
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION})
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
if(TARGET_ARCH MATCHES "x86|x64")
@ -568,11 +628,6 @@ include_directories("${CMAKE_BINARY_DIR}/winpr/include")
add_subdirectory(winpr)
if(WITH_CUNIT)
message(FATAL_ERROR "cunit (WITH_CUNIT) is deprecated please use BUILD_TESTING to build ctest tests.
The cunit directory contains the old tests and is kept until all tests are converted.")
endif()
# Sub-directories
if(WITH_THIRD_PARTY)
@ -599,6 +654,12 @@ if (IOS)
endif()
endif()
# RdTk
include_directories("${CMAKE_SOURCE_DIR}/rdtk/include")
include_directories("${CMAKE_BINARY_DIR}/rdtk/include")
add_subdirectory(rdtk)
if(WITH_CLIENT)
add_subdirectory(client)
endif()
@ -616,7 +677,9 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.10")
set(FREERDP_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP")
set(FREERDP_INCLUDE_DIR "include")
set(FREERDP_MONOLITHIC_BUILD ${MONOLITHIC_BUILD})
# keep for legacy builds
set(FREERDP_MONOLITHIC_BUILD OFF)
configure_package_config_file(FreeRDPConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfig.cmake
INSTALL_DESTINATION ${FREERDP_CMAKE_INSTALL_DIR}
@ -648,27 +711,11 @@ endif()
include(${CMAKE_CPACK_INCLUDE_FILE})
if(MONOLITHIC_BUILD)
set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client")
set(WINPR_PC_LIBS "-lwinpr")
if (WITH_SERVER)
set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server")
endif()
else(MONOLITHIC_BUILD)
# freerdp exports
get_property(MEXPORTS GLOBAL PROPERTY "freerdp_EXPORTS")
foreach(EXPORT_MODULE ${MEXPORTS})
list(APPEND FREERDP_PC_LIBS "-lfreerdp-${EXPORT_MODULE}")
endforeach()
string(REPLACE ";" " " FREERDP_PC_LIBS "${FREERDP_PC_LIBS}")
# winpr exports
get_property(MEXPORTS GLOBAL PROPERTY "winpr_EXPORTS")
foreach(EXPORT_MODULE ${MEXPORTS})
list(APPEND WINPR_PC_LIBS "-lwinpr-${EXPORT_MODULE}")
endforeach()
string(REPLACE ";" " " WINPR_PC_LIBS "${WINPR_PC_LIBS}")
endif(MONOLITHIC_BUILD)
set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client")
set(WINPR_PC_LIBS "-lwinpr")
if (WITH_SERVER)
set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server")
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/winpr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc @ONLY)

View File

@ -158,7 +158,25 @@ macro(add_channel_client_library _module_prefix _module_name _channel_name _dyna
if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS))
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
endif()
if(${_dynamic} AND (NOT STATIC_CHANNELS))
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
set (RC_VERSION_PATCH 0)
set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${_module_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
configure_file(
${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
${CMAKE_CURRENT_BINARY_DIR}/version.rc
@ONLY)
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
@ -174,6 +192,23 @@ macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
endif()
if(${_dynamic} AND (NOT STATIC_CHANNELS))
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
set (RC_VERSION_PATCH 0)
set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${_module_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
configure_file(
${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
${CMAKE_CURRENT_BINARY_DIR}/version.rc
@ONLY)
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
@ -188,6 +223,22 @@ macro(add_channel_server_library _module_prefix _module_name _channel_name _dyna
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
endif()
if(${_dynamic} AND (NOT STATIC_CHANNELS))
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${_module_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
configure_file(
${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
${CMAKE_CURRENT_BINARY_DIR}/version.rc
@ONLY)
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
@ -202,8 +253,8 @@ set(FILENAME "ChannelOptions.cmake")
file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
foreach(FILEPATH ${FILEPATHS})
if(${FILEPATH} MATCHES "^([^/]*)//${FILENAME}")
string(REGEX REPLACE "^([^/]*)//${FILENAME}" "\\1" DIR ${FILEPATH})
if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}")
string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" DIR ${FILEPATH})
set(CHANNEL_OPTION)
include(${FILEPATH})
if(${CHANNEL_OPTION})

View File

@ -25,14 +25,9 @@ include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -25,14 +25,9 @@ include_directories(${ALSA_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})
set(${MODULE_PREFIX}_LIBS freerdp ${ALSA_LIBRARIES})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -72,8 +72,8 @@ static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_hand
if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
DEBUG_WARN("snd_pcm_hw_params_malloc (%s)",
snd_strerror(error));
WLog_ERR(TAG, "snd_pcm_hw_params_malloc (%s)",
snd_strerror(error));
return FALSE;
}
@ -206,7 +206,7 @@ static void* audin_alsa_thread_func(void* arg)
{
if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0)
{
DEBUG_WARN("snd_pcm_open (%s)", snd_strerror(error));
WLog_ERR(TAG, "snd_pcm_open (%s)", snd_strerror(error));
break;
}
@ -226,7 +226,7 @@ static void* audin_alsa_thread_func(void* arg)
}
else if (error < 0)
{
DEBUG_WARN("snd_pcm_readi (%s)", snd_strerror(error));
WLog_ERR(TAG, "snd_pcm_readi (%s)", snd_strerror(error));
break;
}
@ -354,17 +354,22 @@ static void audin_alsa_close(IAudinDevice* device)
DEBUG_DVC("");
SetEvent(alsa->stopEvent);
WaitForSingleObject(alsa->thread, INFINITE);
CloseHandle(alsa->stopEvent);
CloseHandle(alsa->thread);
if (alsa->stopEvent)
{
SetEvent(alsa->stopEvent);
WaitForSingleObject(alsa->thread, INFINITE);
CloseHandle(alsa->stopEvent);
alsa->stopEvent = NULL;
CloseHandle(alsa->thread);
alsa->thread = NULL;
}
if (alsa->buffer)
free(alsa->buffer);
alsa->buffer = NULL;
alsa->stopEvent = NULL;
alsa->thread = NULL;
alsa->receive = NULL;
alsa->user_data = NULL;
}

View File

@ -102,7 +102,7 @@ static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, w
out = Stream_New(NULL, 5);
Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
Stream_Write_UINT32(out, Version);
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(s), Stream_Buffer(s), NULL);
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), Stream_Buffer(out), NULL);
Stream_Free(out, TRUE);
return error;
@ -133,7 +133,7 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w
DEBUG_DVC("NumFormats %d", NumFormats);
if ((NumFormats < 1) || (NumFormats > 1000))
{
DEBUG_WARN("bad NumFormats %d", NumFormats);
WLog_ERR(TAG, "bad NumFormats %d", NumFormats);
return 1;
}
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */
@ -262,8 +262,8 @@ static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStr
if (initialFormat >= (UINT32) callback->formats_count)
{
DEBUG_WARN("invalid format index %d (total %d)",
initialFormat, callback->formats_count);
WLog_ERR(TAG, "invalid format index %d (total %d)",
initialFormat, callback->formats_count);
return 1;
}
@ -293,8 +293,8 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
if (NewFormat >= (UINT32) callback->formats_count)
{
DEBUG_WARN("invalid format index %d (total %d)",
NewFormat, callback->formats_count);
WLog_ERR(TAG, "invalid format index %d (total %d)",
NewFormat, callback->formats_count);
return 1;
}
@ -312,44 +312,39 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
return 0;
}
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
{
int error;
wStream* s;
BYTE MessageId;
s = Stream_New(pBuffer, cbSize);
Stream_Read_UINT8(s, MessageId);
Stream_Read_UINT8(data, MessageId);
DEBUG_DVC("MessageId=0x%x", MessageId);
switch (MessageId)
{
case MSG_SNDIN_VERSION:
error = audin_process_version(pChannelCallback, s);
error = audin_process_version(pChannelCallback, data);
break;
case MSG_SNDIN_FORMATS:
error = audin_process_formats(pChannelCallback, s);
error = audin_process_formats(pChannelCallback, data);
break;
case MSG_SNDIN_OPEN:
error = audin_process_open(pChannelCallback, s);
error = audin_process_open(pChannelCallback, data);
break;
case MSG_SNDIN_FORMATCHANGE:
error = audin_process_format_change(pChannelCallback, s);
error = audin_process_format_change(pChannelCallback, data);
break;
default:
DEBUG_WARN("unknown MessageId=0x%x", MessageId);
WLog_ERR(TAG, "unknown MessageId=0x%x", MessageId);
error = 1;
break;
}
Stream_Free(s, FALSE);
return error;
}
@ -422,6 +417,12 @@ static int audin_plugin_terminated(IWTSPlugin* pPlugin)
audin->device = NULL;
}
free(audin->subsystem);
audin->subsystem = NULL;
free(audin->device_name);
audin->device_name = NULL;
free(audin->listener_callback);
free(audin);
@ -434,7 +435,7 @@ static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi
if (audin->device)
{
DEBUG_WARN("existing device, abort.");
WLog_ERR(TAG, "existing device, abort.");
return;
}
@ -459,7 +460,7 @@ static BOOL audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI
if (entry(&entryPoints) != 0)
{
DEBUG_WARN("%s entry returns error.", name);
WLog_ERR(TAG, "%s entry returns error.", name);
return FALSE;
}
@ -618,7 +619,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
if (audin->device == NULL)
{
DEBUG_WARN("no sound device.");
WLog_ERR(TAG, "no sound device.");
}
return error;

View File

@ -27,13 +27,15 @@
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/utils/debug.h>
#include <freerdp/channels/log.h>
#include <freerdp/client/audin.h>
#define TAG CHANNELS_TAG("audin.client")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#define DEBUG_DVC(fmt, ...) do { } while (0)
#endif
#endif /* FREERDP_AUDIN_CLIENT_MAIN_H */

View File

@ -26,16 +26,9 @@ include_directories(${OPENSLES_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils
${OPENSLES_LIBRARIES}
)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES})
set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -96,7 +96,7 @@ static void* audin_opensles_thread_func(void* arg)
int rc = android_RecIn(opensles->stream, buffer.s, raw_size);
if (rc < 0)
{
DEBUG_WARN("android_RecIn %d", rc);
WLog_ERR(TAG, "android_RecIn %d", rc);
continue;
}
@ -250,9 +250,9 @@ static void audin_opensles_set_format(IAudinDevice* device,
break;
default:
DEBUG_WARN("Encoding '%d' [%08X] not supported",
(format->wFormatTag),
format->wFormatTag);
WLog_ERR(TAG, "Encoding '%d' [%08X] not supported",
(format->wFormatTag),
format->wFormatTag);
return;
}
@ -309,7 +309,7 @@ static void audin_opensles_close(IAudinDevice* device)
* ignore duplicate requests. */
if (!opensles->stopEvent)
{
DEBUG_WARN("[ERROR] function called without matching open.");
WLog_ERR(TAG, "[ERROR] function called without matching open.");
return;
}

View File

@ -362,7 +362,7 @@ int android_RecIn(OPENSL_STREAM *p,short *buffer,int size)
e = Queue_Dequeue(p->queue);
if (!e)
{
DEBUG_WARN("[ERROR] got e=%p from queue", e);
WLog_ERR(TAG, "[ERROR] got e=%p from queue", e);
return -1;
}

View File

@ -25,14 +25,9 @@ include_directories(${PULSE_INCLUDE_DIR})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY})
set(${MODULE_PREFIX}_LIBS freerdp ${PULSE_LIBRARY})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -94,16 +94,16 @@ static BOOL audin_pulse_connect(IAudinDevice* device)
if (pa_context_connect(pulse->context, NULL, 0, NULL))
{
DEBUG_WARN("pa_context_connect failed (%d)",
pa_context_errno(pulse->context));
WLog_ERR(TAG, "pa_context_connect failed (%d)",
pa_context_errno(pulse->context));
return FALSE;
}
pa_threaded_mainloop_lock(pulse->mainloop);
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
pa_context_errno(pulse->context));
WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)",
pa_context_errno(pulse->context));
return FALSE;
}
for (;;)
@ -113,8 +113,8 @@ static BOOL audin_pulse_connect(IAudinDevice* device)
break;
if (!PA_CONTEXT_IS_GOOD(state))
{
DEBUG_WARN("bad context state (%d)",
pa_context_errno(pulse->context));
WLog_ERR(TAG, "bad context state (%d)",
pa_context_errno(pulse->context));
break;
}
pa_threaded_mainloop_wait(pulse->mainloop);
@ -297,7 +297,7 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
*/
if (pulse->buffer == NULL)
{
/* fprintf(stderr, "%s: ignoring input, pulse buffer not ready.\n", __func__); */
/* WLog_ERR(TAG, "%s: ignoring input, pulse buffer not ready.\n", __func__); */
return;
}
@ -415,8 +415,8 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
&buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
DEBUG_WARN("pa_stream_connect_playback failed (%d)",
pa_context_errno(pulse->context));
WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)",
pa_context_errno(pulse->context));
return;
}
@ -427,8 +427,8 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
break;
if (!PA_STREAM_IS_GOOD(state))
{
DEBUG_WARN("bad stream state (%d)",
pa_context_errno(pulse->context));
WLog_ERR(TAG, "bad stream state (%d)",
pa_context_errno(pulse->context));
break;
}
pa_threaded_mainloop_wait(pulse->mainloop);
@ -512,7 +512,7 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
if (!pulse->mainloop)
{
DEBUG_WARN("pa_threaded_mainloop_new failed");
WLog_ERR(TAG, "pa_threaded_mainloop_new failed");
audin_pulse_free((IAudinDevice*) pulse);
return 1;
}
@ -521,7 +521,7 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
if (!pulse->context)
{
DEBUG_WARN("pa_context_new failed");
WLog_ERR(TAG, "pa_context_new failed");
audin_pulse_free((IAudinDevice*) pulse);
return 1;
}

View File

@ -24,14 +24,9 @@ include_directories(..)
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib)
set(${MODULE_PREFIX}_LIBS freerdp winmm.lib)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -22,14 +22,9 @@ set(${MODULE_PREFIX}_SRCS
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -34,7 +34,9 @@
#include <freerdp/codec/audio.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/server/audin.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("audin.server")
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
@ -77,9 +79,11 @@ static void audin_server_select_format(audin_server_context* context, int client
static void audin_server_send_version(audin_server* audin, wStream* s)
{
ULONG written;
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
}
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
@ -101,6 +105,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
{
int i;
UINT32 nAvgBytesPerSec;
ULONG written;
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
@ -131,7 +136,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
}
}
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
}
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
@ -181,6 +186,8 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
static void audin_server_send_open(audin_server* audin, wStream* s)
{
ULONG written;
if (audin->context.selected_client_format < 0)
return;
@ -203,7 +210,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, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
}
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
@ -340,24 +347,16 @@ static void* audin_server_thread_func(void* arg)
Stream_SetPosition(s, 0);
WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned);
if (BytesReturned < 1)
continue;
Stream_EnsureRemainingCapacity(s, BytesReturned);
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
Stream_Capacity(s), &BytesReturned) == FALSE)
{
if (BytesReturned == 0)
break;
Stream_EnsureRemainingCapacity(s, BytesReturned);
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
Stream_Capacity(s), &BytesReturned) == FALSE)
{
break;
}
break;
}
if (BytesReturned < 1)
continue;
Stream_Read_UINT8(s, MessageId);
BytesReturned--;
@ -388,7 +387,7 @@ static void* audin_server_thread_func(void* arg)
break;
default:
fprintf(stderr, "audin_server_thread_func: unknown MessageId %d\n", MessageId);
WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %d\n", MessageId);
break;
}
}

View File

@ -24,7 +24,9 @@ set(${MODULE_PREFIX}_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/addin.c
${CMAKE_CURRENT_SOURCE_DIR}/addin.h)
if(CHANNEL_STATIC_CLIENT_ENTRIES)
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
endif()
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
@ -96,15 +98,7 @@ set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NUL
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-path winpr-file winpr-synch winpr-library winpr-interlocked)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp winpr)
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)

View File

@ -156,19 +156,23 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
if (pszName && pszSubsystem && pszType)
{
sprintf_s(pszPattern, cchPattern, "%s-client-%s-%s.%s", pszName, pszSubsystem, pszType, pszExtension);
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s",
pszName, pszSubsystem, pszType, pszExtension);
}
else if (pszName && pszType)
{
sprintf_s(pszPattern, cchPattern, "%s-client-?-%s.%s", pszName, pszType, pszExtension);
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s",
pszName, pszType, pszExtension);
}
else if (pszName)
{
sprintf_s(pszPattern, cchPattern, "%s-client*.%s", pszName, pszExtension);
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client*.%s",
pszName, pszExtension);
}
else
{
sprintf_s(pszPattern, cchPattern, "?-client*.%s", pszExtension);
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"?-client*.%s",
pszExtension);
}
cchPattern = strlen(pszPattern);

View File

@ -25,17 +25,9 @@ set(${MODULE_PREFIX}_SRCS
add_channel_client_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)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt)
set(${MODULE_PREFIX}_LIBS freerdp winpr)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -22,484 +22,233 @@
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#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_main.h"
#include "cliprdr_format.h"
#define CFSTR_HTML "H\0T\0M\0L\0 \0F\0o\0r\0m\0a\0t\0\0"
#define CFSTR_PNG "P\0N\0G\0\0"
#define CFSTR_JPEG "J\0F\0I\0F\0\0"
#define CFSTR_GIF "G\0I\0F\0\0"
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event)
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
int i;
wStream* s;
UINT32 index;
UINT32 position;
BOOL asciiNames;
int formatNameLength;
char* szFormatName;
WCHAR* wszFormatName;
CLIPRDR_FORMAT* formats = NULL;
CLIPRDR_FORMAT_LIST formatList;
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
DEBUG_CLIPRDR("Sending Clipboard Format List");
if (!context->custom)
return;
asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE;
formatList.msgType = CB_FORMAT_LIST;
formatList.msgFlags = msgFlags;
formatList.dataLen = dataLen;
if (cb_event->raw_format_data)
index = 0;
formatList.numFormats = 0;
position = Stream_GetPosition(s);
if (!formatList.dataLen)
{
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, cb_event->raw_format_data_size);
Stream_Write(s, cb_event->raw_format_data, cb_event->raw_format_data_size);
/* empty format list */
formatList.formats = NULL;
formatList.numFormats = 0;
}
else
else if (!cliprdr->useLongFormatNames)
{
wStream* body = Stream_New(NULL, 64);
formatList.numFormats = (dataLen / 36);
for (i = 0; i < cb_event->num_formats; i++)
if ((formatList.numFormats * 36) != dataLen)
{
const char* name;
int name_length, short_name_length = 32, x;
switch (cb_event->formats[i])
{
case CB_FORMAT_HTML:
name = CFSTR_HTML;
name_length = sizeof(CFSTR_HTML);
break;
case CB_FORMAT_PNG:
name = CFSTR_PNG;
name_length = sizeof(CFSTR_PNG);
break;
case CB_FORMAT_JPEG:
name = CFSTR_JPEG;
name_length = sizeof(CFSTR_JPEG);
break;
case CB_FORMAT_GIF:
name = CFSTR_GIF;
name_length = sizeof(CFSTR_GIF);
break;
default:
name = "\0\0";
name_length = 2;
break;
}
WLog_ERR(TAG, "Invalid short format list length: %d", dataLen);
return;
}
if (formatList.numFormats)
formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
return;
formatList.formats = formats;
while (dataLen)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
dataLen -= 4;
if (!cliprdr->use_long_format_names)
{
x = (name_length > short_name_length) ?
name_length : short_name_length;
Stream_EnsureRemainingCapacity(body, 4 + short_name_length);
Stream_Write_UINT32(body, cb_event->formats[i]);
Stream_Write(body, name, x);
while (x++ < short_name_length)
Stream_Write(body, "\0", 1);
formats[index].formatName = NULL;
if (asciiNames)
{
szFormatName = (char*) Stream_Pointer(s);
if (szFormatName[0])
{
formats[index].formatName = (char*) malloc(32 + 1);
CopyMemory(formats[index].formatName, szFormatName, 32);
formats[index].formatName[32] = '\0';
}
}
else
{
Stream_EnsureRemainingCapacity(body, 4 + name_length);
Stream_Write_UINT32(body, cb_event->formats[i]);
Stream_Write(body, name, name_length);
}
}
wszFormatName = (WCHAR*) Stream_Pointer(s);
Stream_SealLength(body);
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, Stream_Length(body));
Stream_Write(s, Stream_Buffer(body), Stream_Length(body));
Stream_Free(body, TRUE);
}
cliprdr_packet_send(cliprdr, s);
}
static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr)
{
wStream* s;
DEBUG_CLIPRDR("Sending Clipboard Format List Response");
s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0);
cliprdr_packet_send(cliprdr, s);
}
void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
int i;
BOOL ascii;
int num_formats;
CLIPRDR_FORMAT_NAME* format_name;
num_formats = length / 36;
if (num_formats <= 0)
{
cliprdr->format_names = NULL;
cliprdr->num_format_names = 0;
return;
}
if (num_formats * 36 != length)
DEBUG_WARN("dataLen %d not divided by 36!", length);
ascii = (flags & CB_ASCII_NAMES) ? TRUE : FALSE;
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats);
cliprdr->num_format_names = num_formats;
for (i = 0; i < num_formats; i++)
{
format_name = &cliprdr->format_names[i];
Stream_Read_UINT32(s, format_name->id);
if (ascii)
{
format_name->name = _strdup((char*) s->pointer);
format_name->length = strlen(format_name->name);
if (wszFormatName[0])
{
ConvertFromUnicode(CP_UTF8, 0, wszFormatName,
16, &(formats[index].formatName), 0, NULL, NULL);
}
}
Stream_Seek(s, 32);
dataLen -= 32;
index++;
}
else
{
format_name->name = NULL;
format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) s->pointer, 32 / 2, &format_name->name, 0, NULL, NULL);
}
Stream_Seek(s, 32);
}
}
void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
{
int allocated_formats = 8;
BYTE* end_mark;
CLIPRDR_FORMAT_NAME* format_name;
Stream_GetPointer(s, end_mark);
end_mark += length;
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
cliprdr->num_format_names = 0;
while (Stream_GetRemainingLength(s) >= 6)
else
{
BYTE* p;
int name_len;
if (cliprdr->num_format_names >= allocated_formats)
{
allocated_formats *= 2;
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) realloc(cliprdr->format_names,
sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
}
format_name = &cliprdr->format_names[cliprdr->num_format_names++];
Stream_Read_UINT32(s, format_name->id);
format_name->name = NULL;
format_name->length = 0;
for (p = Stream_Pointer(s), name_len = 0; p + 1 < end_mark; p += 2, name_len += 2)
{
if (*((unsigned short*) p) == 0)
break;
}
format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), name_len / 2, &format_name->name, 0, NULL, NULL);
Stream_Seek(s, name_len + 2);
}
}
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
UINT32 index;
int formatNameLength;
CLIPRDR_FORMAT* formats;
CLIPRDR_FORMAT_LIST formatList;
formatList.msgType = CB_FORMAT_LIST;
formatList.msgFlags = msgFlags;
formatList.dataLen = dataLen;
formatList.cFormats = 0;
while (dataLen)
{
Stream_Seek(s, 4); /* formatId */
Stream_Seek(s, 4); /* formatId (4 bytes) */
dataLen -= 4;
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
wszFormatName = (WCHAR*) Stream_Pointer(s);
if (!wszFormatName[0])
formatNameLength = 0;
else
formatNameLength = _wcslen(wszFormatName);
Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);
formatList.cFormats++;
formatList.numFormats++;
}
index = 0;
dataLen = formatList.dataLen;
Stream_Rewind(s, dataLen);
Stream_SetPosition(s, position);
if (formatList.numFormats)
formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
return;
formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.cFormats);
formatList.formats = formats;
while (dataLen)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId */
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
dataLen -= 4;
formats[index].formatName = NULL;
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
wszFormatName = (WCHAR*) Stream_Pointer(s);
if (!wszFormatName[0])
formatNameLength = 0;
else
formatNameLength = _wcslen(wszFormatName);
if (formatNameLength)
{
formatNameLength = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
ConvertFromUnicode(CP_UTF8, 0, wszFormatName,
-1, &(formats[index].formatName), 0, NULL, NULL);
Stream_Seek(s, formatNameLength * 2);
dataLen -= (formatNameLength * 2);
}
else
{
Stream_Seek(s, 2);
dataLen -= 2;
}
Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);
index++;
}
if (context->ServerFormatList)
context->ServerFormatList(context, &formatList);
for (index = 0; index < formatList.cFormats; index++)
free(formats[index].formatName);
free(formats);
}
else
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d",
formatList.numFormats);
if (context->ServerFormatList)
context->ServerFormatList(context, &formatList);
for (index = 0; index < formatList.numFormats; index++)
{
int i;
UINT32 format;
BOOL supported;
CLIPRDR_FORMAT_NAME* format_name;
RDP_CB_FORMAT_LIST_EVENT* cb_event;
cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_FormatList, NULL, NULL);
if (dataLen > 0)
{
cb_event->raw_format_data = (BYTE*) malloc(dataLen);
memcpy(cb_event->raw_format_data, Stream_Pointer(s), dataLen);
cb_event->raw_format_data_size = dataLen;
cb_event->raw_format_unicode = (msgFlags & CB_ASCII_NAMES) ? FALSE : TRUE;
}
if (cliprdr->use_long_format_names)
cliprdr_process_long_format_names(cliprdr, s, dataLen, msgFlags);
else
cliprdr_process_short_format_names(cliprdr, s, dataLen, msgFlags);
if (cliprdr->num_format_names > 0)
cb_event->formats = (UINT32*) malloc(sizeof(UINT32) * cliprdr->num_format_names);
cb_event->num_formats = 0;
for (i = 0; i < cliprdr->num_format_names; i++)
{
supported = TRUE;
format_name = &cliprdr->format_names[i];
format = format_name->id;
switch (format)
{
case CB_FORMAT_TEXT:
case CB_FORMAT_DIB:
case CB_FORMAT_UNICODETEXT:
break;
default:
if (format_name->length > 0)
{
DEBUG_CLIPRDR("format: %s", format_name->name);
if (strcmp(format_name->name, "HTML Format") == 0)
{
format = CB_FORMAT_HTML;
break;
}
if (strcmp(format_name->name, "PNG") == 0)
{
format = CB_FORMAT_PNG;
break;
}
if (strcmp(format_name->name, "JFIF") == 0)
{
format = CB_FORMAT_JPEG;
break;
}
if (strcmp(format_name->name, "GIF") == 0)
{
format = CB_FORMAT_GIF;
break;
}
}
else
{
supported = FALSE;
}
break;
}
if (supported)
cb_event->formats[cb_event->num_formats++] = format;
if (format_name->length > 0)
free(format_name->name);
}
free(cliprdr->format_names);
cliprdr->format_names = NULL;
cliprdr->num_format_names = 0;
cliprdr_send_format_list_response(cliprdr);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
if (formats[index].formatName)
free(formats[index].formatName);
}
free(formats);
}
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse");
if (context->custom)
{
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
if (!context->custom)
return;
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
formatListResponse.msgFlags = msgFlags;
formatListResponse.dataLen = dataLen;
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
formatListResponse.msgFlags = msgFlags;
formatListResponse.dataLen = dataLen;
if (context->ServerFormatListResponse)
context->ServerFormatListResponse(context, &formatListResponse);
}
else
{
if ((msgFlags & CB_RESPONSE_FAIL) != 0)
{
/* In case of an error the clipboard will not be synchronized with the server.
* Post this event to restart format negotiation and data transfer. */
wMessage* event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event);
}
}
if (context->ServerFormatListResponse)
context->ServerFormatListResponse(context, &formatListResponse);
}
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest");
formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST;
formatDataRequest.msgFlags = msgFlags;
formatDataRequest.dataLen = dataLen;
if (!context->custom)
return;
Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */
formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST;
formatDataRequest.msgFlags = msgFlags;
formatDataRequest.dataLen = dataLen;
if (context->ServerFormatDataRequest)
context->ServerFormatDataRequest(context, &formatDataRequest);
}
else
{
RDP_CB_DATA_REQUEST_EVENT* cb_event;
Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */
cb_event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_DataRequest, NULL, NULL);
Stream_Read_UINT32(s, cb_event->format);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
}
}
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event)
{
wStream* s;
DEBUG_CLIPRDR("Sending Format Data Response");
if (cb_event->size > 0)
{
s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_OK, cb_event->size);
Stream_Write(s, cb_event->data, cb_event->size);
}
else
{
s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_FAIL, 0);
}
cliprdr_packet_send(cliprdr, s);
}
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event)
{
wStream* s;
DEBUG_CLIPRDR("Sending Format Data Request");
s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
Stream_Write_UINT32(s, cb_event->format);
cliprdr_packet_send(cliprdr, s);
if (context->ServerFormatDataRequest)
context->ServerFormatDataRequest(context, &formatDataRequest);
}
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
{
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
if (context->custom)
{
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
formatDataResponse.msgFlags = msgFlags;
formatDataResponse.dataLen = dataLen;
formatDataResponse.requestedFormatData = NULL;
if (dataLen)
{
formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen);
Stream_Read(s, formatDataResponse.requestedFormatData, dataLen);
}
if (context->ServerFormatDataResponse)
context->ServerFormatDataResponse(context, &formatDataResponse);
free(formatDataResponse.requestedFormatData);
}
else
{
RDP_CB_DATA_RESPONSE_EVENT* cb_event;
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse");
cb_event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class,
CliprdrChannel_DataResponse, NULL, NULL);
if (!context->custom)
return;
formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
formatDataResponse.msgFlags = msgFlags;
formatDataResponse.dataLen = dataLen;
formatDataResponse.requestedFormatData = NULL;
if (dataLen > 0)
{
cb_event->size = dataLen;
cb_event->data = (BYTE*) malloc(dataLen);
CopyMemory(cb_event->data, Stream_Pointer(s), dataLen);
}
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
if (dataLen)
{
formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen);
Stream_Read(s, formatDataResponse.requestedFormatData, dataLen);
}
if (context->ServerFormatDataResponse)
context->ServerFormatDataResponse(context, &formatDataResponse);
free(formatDataResponse.requestedFormatData);
}

View File

@ -21,14 +21,9 @@
#ifndef __CLIPRDR_FORMAT_H
#define __CLIPRDR_FORMAT_H
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event);
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event);
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event);
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
#endif /* __CLIPRDR_FORMAT_H */

File diff suppressed because it is too large Load Diff

View File

@ -23,18 +23,31 @@
#include <winpr/stream.h>
#include <freerdp/utils/debug.h>
#include <freerdp/svc.h>
#include <freerdp/addin.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("cliprdr.client")
struct cliprdr_plugin
{
rdpSvcPlugin plugin;
BOOL received_caps;
BOOL use_long_format_names;
BOOL stream_fileclip_enabled;
BOOL fileclip_no_file_paths;
BOOL can_lock_clipdata;
CLIPRDR_FORMAT_NAME* format_names;
int num_format_names;
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
CliprdrClientContext* context;
wLog* log;
HANDLE thread;
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;
wMessageQueue* queue;
BOOL capabilitiesReceived;
BOOL useLongFormatNames;
BOOL streamFileClipEnabled;
BOOL fileClipNoFilePaths;
BOOL canLockClipData;
};
typedef struct cliprdr_plugin cliprdrPlugin;
@ -44,9 +57,9 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* data_out);
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
#ifdef WITH_DEBUG_CLIPRDR
#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(CLIPRDR, fmt, ## __VA_ARGS__)
#define DEBUG_CLIPRDR(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#define DEBUG_CLIPRDR(fmt, ...) do { } while (0)
#endif
#endif /* __CLIPRDR_MAIN_H */

View File

@ -23,14 +23,9 @@ set(${MODULE_PREFIX}_SRCS
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})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

File diff suppressed because it is too large Load Diff

View File

@ -22,27 +22,32 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/stream.h>
#include <winpr/thread.h>
#include <freerdp/server/cliprdr.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("cliprdr.server")
#define CLIPRDR_HEADER_LENGTH 8
struct _cliprdr_server_private
{
HANDLE vcm;
HANDLE Thread;
HANDLE StopEvent;
void* ChannelHandle;
HANDLE ChannelEvent;
BOOL UseLongFormatNames;
BOOL StreamFileClipEnabled;
BOOL FileClipNoFilePaths;
BOOL CanLockClipData;
BOOL useLongFormatNames;
BOOL streamFileClipEnabled;
BOOL fileClipNoFilePaths;
BOOL canLockClipData;
UINT32 ClientFormatNameCount;
CLIPRDR_FORMAT_NAME* ClientFormatNames;
char* ClientTemporaryDirectory;
wStream* s;
char* temporaryDirectory;
};
typedef struct _cliprdr_server_private CliprdrServerPrivate;
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */

View File

@ -25,17 +25,9 @@ include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-sysinfo)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -66,8 +66,8 @@ struct _DISP_PLUGIN
DISP_LISTENER_CALLBACK* listener_callback;
UINT32 MaxNumMonitors;
UINT32 MaxMonitorWidth;
UINT32 MaxMonitorHeight;
UINT32 MaxMonitorAreaFactorA;
UINT32 MaxMonitorAreaFactorB;
};
typedef struct _DISP_PLUGIN DISP_PLUGIN;
@ -83,11 +83,7 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
disp = (DISP_PLUGIN*) callback->plugin;
#ifdef DISP_PREVIEW
MonitorLayoutSize = 32;
#else
MonitorLayoutSize = 40;
#endif
length = 8 + 8 + (NumMonitors * MonitorLayoutSize);
@ -101,15 +97,11 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
if (NumMonitors > disp->MaxNumMonitors)
NumMonitors = disp->MaxNumMonitors;
#ifdef DISP_PREVIEW
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
#else
Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
#endif
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
//fprintf(stderr, "NumMonitors: %d\n", NumMonitors);
//WLog_ERR(TAG, "NumMonitors: %d\n", NumMonitors);
for (index = 0; index < NumMonitors; index++)
{
@ -118,14 +110,17 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
if (Monitors[index].Width < 200)
Monitors[index].Width = 200;
if (Monitors[index].Width > disp->MaxMonitorWidth)
Monitors[index].Width = disp->MaxMonitorWidth;
if (Monitors[index].Width > 8192)
Monitors[index].Width = 8192;
if (Monitors[index].Width % 2)
Monitors[index].Width++;
if (Monitors[index].Height < 200)
Monitors[index].Height = 200;
if (Monitors[index].Height > disp->MaxMonitorHeight)
Monitors[index].Height = disp->MaxMonitorHeight;
if (Monitors[index].Height > 8192)
Monitors[index].Height = 8192;
Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */
@ -135,21 +130,18 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */
#if 0
fprintf(stderr, "\t: Flags: 0x%04X\n", Monitors[index].Flags);
fprintf(stderr, "\t: Left: %d\n", Monitors[index].Left);
fprintf(stderr, "\t: Top: %d\n", Monitors[index].Top);
fprintf(stderr, "\t: Width: %d\n", Monitors[index].Width);
fprintf(stderr, "\t: Height: %d\n", Monitors[index].Height);
fprintf(stderr, "\t: PhysicalWidth: %d\n", Monitors[index].PhysicalWidth);
fprintf(stderr, "\t: PhysicalHeight: %d\n", Monitors[index].PhysicalHeight);
fprintf(stderr, "\t: Orientation: %d\n", Monitors[index].Orientation);
#endif
#ifndef DISP_PREVIEW
Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
#if 0
WLog_DBG(TAG, "\t: Flags: 0x%04X\n", Monitors[index].Flags);
WLog_DBG(TAG, "\t: Left: %d\n", Monitors[index].Left);
WLog_DBG(TAG, "\t: Top: %d\n", Monitors[index].Top);
WLog_DBG(TAG, "\t: Width: %d\n", Monitors[index].Width);
WLog_DBG(TAG, "\t: Height: %d\n", Monitors[index].Height);
WLog_DBG(TAG, "\t: PhysicalWidth: %d\n", Monitors[index].PhysicalWidth);
WLog_DBG(TAG, "\t: PhysicalHeight: %d\n", Monitors[index].PhysicalHeight);
WLog_DBG(TAG, "\t: Orientation: %d\n", Monitors[index].Orientation);
#endif
}
@ -168,11 +160,13 @@ int disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream*
disp = (DISP_PLUGIN*) callback->plugin;
Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */
Stream_Read_UINT32(s, disp->MaxMonitorWidth); /* MaxMonitorWidth (4 bytes) */
Stream_Read_UINT32(s, disp->MaxMonitorHeight); /* MaxMonitorHeight (4 bytes) */
if (Stream_GetRemainingLength(s) < 12)
return -1;
//fprintf(stderr, "DisplayControlCapsPdu: MaxNumMonitors: %d MaxMonitorWidth: %d MaxMonitorHeight: %d\n",
Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */
Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorA); /* MaxMonitorAreaFactorA (4 bytes) */
Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorB); /* MaxMonitorAreaFactorB (4 bytes) */
//WLog_ERR(TAG, "DisplayControlCapsPdu: MaxNumMonitors: %d MaxMonitorWidth: %d MaxMonitorHeight: %d\n",
// disp->MaxNumMonitors, disp->MaxMonitorWidth, disp->MaxMonitorHeight);
return 0;
@ -183,10 +177,13 @@ int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
UINT32 type;
UINT32 length;
if (Stream_GetRemainingLength(s) < 8)
return -1;
Stream_Read_UINT32(s, type); /* Type (4 bytes) */
Stream_Read_UINT32(s, length); /* Length (4 bytes) */
//fprintf(stderr, "Type: %d Length: %d\n", type, length);
//WLog_ERR(TAG, "Type: %d Length: %d\n", type, length);
switch (type)
{
@ -201,17 +198,12 @@ int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
return 0;
}
static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
{
wStream* s;
int status = 0;
DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback;
s = Stream_New(pBuffer, cbSize);
status = disp_recv_pdu(callback, s);
Stream_Free(s, FALSE);
status = disp_recv_pdu(callback, data);
return status;
}
@ -235,8 +227,10 @@ static int disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallbac
DISP_CHANNEL_CALLBACK* callback;
DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback;
callback = (DISP_CHANNEL_CALLBACK*) malloc(sizeof(DISP_CHANNEL_CALLBACK));
ZeroMemory(callback, sizeof(DISP_CHANNEL_CALLBACK));
callback = (DISP_CHANNEL_CALLBACK*) calloc(1, sizeof(DISP_CHANNEL_CALLBACK));
if (!callback)
return -1;
callback->iface.OnDataReceived = disp_on_data_received;
callback->iface.OnClose = disp_on_close;
@ -255,8 +249,10 @@ static int disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager
int status;
DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin;
disp->listener_callback = (DISP_LISTENER_CALLBACK*) malloc(sizeof(DISP_LISTENER_CALLBACK));
ZeroMemory(disp->listener_callback, sizeof(DISP_LISTENER_CALLBACK));
disp->listener_callback = (DISP_LISTENER_CALLBACK*) calloc(1, sizeof(DISP_LISTENER_CALLBACK));
if (!disp->listener_callback)
return -1;
disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection;
disp->listener_callback->plugin = pPlugin;
@ -308,33 +304,37 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp");
if (disp == NULL)
if (!disp)
{
disp = (DISP_PLUGIN*) malloc(sizeof(DISP_PLUGIN));
disp = (DISP_PLUGIN*) calloc(1, sizeof(DISP_PLUGIN));
if (disp)
if (!disp)
return -1;
disp->iface.Initialize = disp_plugin_initialize;
disp->iface.Connected = NULL;
disp->iface.Disconnected = NULL;
disp->iface.Terminated = disp_plugin_terminated;
context = (DispClientContext*) calloc(1, sizeof(DispClientContext));
if (!context)
{
ZeroMemory(disp, sizeof(DISP_PLUGIN));
disp->iface.Initialize = disp_plugin_initialize;
disp->iface.Connected = NULL;
disp->iface.Disconnected = NULL;
disp->iface.Terminated = disp_plugin_terminated;
context = (DispClientContext*) malloc(sizeof(DispClientContext));
context->handle = (void*) disp;
context->SendMonitorLayout = disp_send_monitor_layout;
disp->iface.pInterface = (void*) context;
disp->MaxNumMonitors = 16;
disp->MaxMonitorWidth = 8192;
disp->MaxMonitorHeight = 8192;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
free(disp);
return -1;
}
context->handle = (void*) disp;
context->SendMonitorLayout = disp_send_monitor_layout;
disp->iface.pInterface = (void*) context;
disp->MaxNumMonitors = 16;
disp->MaxMonitorAreaFactorA = 8192;
disp->MaxMonitorAreaFactorB = 8192;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
}
return error;

View File

@ -27,14 +27,12 @@
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/utils/debug.h>
#include <freerdp/channels/log.h>
#include <freerdp/client/disp.h>
#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000005
#define DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002
#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000003
#define DISP_PREVIEW 1
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */

View File

@ -19,25 +19,10 @@ define_channel_client("drdynvc")
set(${MODULE_PREFIX}_SRCS
drdynvc_main.c
drdynvc_main.h
drdynvc_types.h
dvcman.c
dvcman.h)
drdynvc_main.h)
add_channel_client_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)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-synch)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,88 @@
#ifndef __DRDYNVC_MAIN_H
#define __DRDYNVC_MAIN_H
#include <winpr/wlog.h>
#include <winpr/synch.h>
#include <freerdp/settings.h>
#include <winpr/collections.h>
#include <freerdp/api.h>
#include <freerdp/svc.h>
#include <freerdp/dvc.h>
#include <freerdp/addin.h>
#include <freerdp/channels/log.h>
#include <freerdp/client/drdynvc.h>
#include <freerdp/utils/svc_plugin.h>
typedef struct drdynvc_plugin drdynvcPlugin;
#define MAX_PLUGINS 32
struct _DVCMAN
{
IWTSVirtualChannelManager iface;
drdynvcPlugin* drdynvc;
int num_plugins;
const char* plugin_names[MAX_PLUGINS];
IWTSPlugin* plugins[MAX_PLUGINS];
int num_listeners;
IWTSListener* listeners[MAX_PLUGINS];
wArrayList* channels;
wStreamPool* pool;
};
typedef struct _DVCMAN DVCMAN;
struct _DVCMAN_LISTENER
{
IWTSListener iface;
DVCMAN* dvcman;
char* channel_name;
UINT32 flags;
IWTSListenerCallback* listener_callback;
};
typedef struct _DVCMAN_LISTENER DVCMAN_LISTENER;
struct _DVCMAN_ENTRY_POINTS
{
IDRDYNVC_ENTRY_POINTS iface;
DVCMAN* dvcman;
ADDIN_ARGV* args;
rdpSettings* settings;
};
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
struct _DVCMAN_CHANNEL
{
IWTSVirtualChannel iface;
int status;
DVCMAN* dvcman;
void* pInterface;
UINT32 channel_id;
char* channel_name;
IWTSVirtualChannelCallback* channel_callback;
wStream* dvc_data;
UINT32 dvc_data_length;
CRITICAL_SECTION lock;
};
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
enum _DRDYNVC_STATE
{
DRDYNVC_STATE_INITIAL,
DRDYNVC_STATE_CAPABILITIES,
DRDYNVC_STATE_READY,
DRDYNVC_STATE_OPENING_CHANNEL,
DRDYNVC_STATE_SEND_RECEIVE,
DRDYNVC_STATE_FINAL
};
typedef enum _DRDYNVC_STATE DRDYNVC_STATE;
#define CREATE_REQUEST_PDU 0x01
#define DATA_FIRST_PDU 0x02
@ -32,12 +109,19 @@
#define CLOSE_REQUEST_PDU 0x04
#define CAPABILITY_REQUEST_PDU 0x05
typedef struct drdynvc_plugin drdynvcPlugin;
struct drdynvc_plugin
{
rdpSvcPlugin plugin;
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
wLog* log;
HANDLE thread;
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;
wMessageQueue* queue;
DRDYNVC_STATE state;
DrdynvcClientContext* context;
int version;
@ -51,6 +135,5 @@ struct drdynvc_plugin
};
int drdynvc_write_data(drdynvcPlugin* plugin, UINT32 ChannelId, BYTE* data, UINT32 data_size);
int drdynvc_push_event(drdynvcPlugin* plugin, wMessage* event);
#endif

View File

@ -1,485 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Dynamic Virtual Channel Manager
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/stream.h>
#include <freerdp/addin.h>
#include "drdynvc_types.h"
#include "dvcman.h"
static int dvcman_get_configuration(IWTSListener* pListener, void** ppPropertyBag)
{
*ppPropertyBag = NULL;
return 1;
}
static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr,
const char* pszChannelName, UINT32 ulFlags,
IWTSListenerCallback* pListenerCallback, IWTSListener** ppListener)
{
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
DVCMAN_LISTENER* listener;
if (dvcman->num_listeners < MAX_PLUGINS)
{
DEBUG_DVC("%d.%s.", dvcman->num_listeners, pszChannelName);
listener = (DVCMAN_LISTENER*) malloc(sizeof(DVCMAN_LISTENER));
ZeroMemory(listener, sizeof(DVCMAN_LISTENER));
listener->iface.GetConfiguration = dvcman_get_configuration;
listener->iface.pInterface = NULL;
listener->dvcman = dvcman;
listener->channel_name = _strdup(pszChannelName);
listener->flags = ulFlags;
listener->listener_callback = pListenerCallback;
if (ppListener)
*ppListener = (IWTSListener*) listener;
dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*) listener;
return 0;
}
else
{
DEBUG_WARN("Maximum DVC listener number reached.");
return 1;
}
}
static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* pEvent)
{
int status;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
status = drdynvc_push_event(dvcman->drdynvc, pEvent);
if (status == 0)
{
DEBUG_DVC("event_type %d pushed.", GetMessageType(pEvent->id));
}
else
{
DEBUG_WARN("event_type %d push failed.", GetMessageType(pEvent->id));
}
return status;
}
static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name, IWTSPlugin* pPlugin)
{
DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman;
if (dvcman->num_plugins < MAX_PLUGINS)
{
DEBUG_DVC("num_plugins %d", dvcman->num_plugins);
dvcman->plugin_names[dvcman->num_plugins] = name;
dvcman->plugins[dvcman->num_plugins++] = pPlugin;
return 0;
}
else
{
DEBUG_WARN("Maximum DVC plugin number reached.");
return 1;
}
}
IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name)
{
int i;
DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman;
for (i = 0; i < dvcman->num_plugins; i++)
{
if (dvcman->plugin_names[i] == name ||
strcmp(dvcman->plugin_names[i], name) == 0)
{
return dvcman->plugins[i];
}
}
return NULL;
}
ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args;
}
UINT32 dvcman_get_channel_id(IWTSVirtualChannel * channel)
{
return ((DVCMAN_CHANNEL*) channel)->channel_id;
}
IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId)
{
int index;
BOOL found = FALSE;
DVCMAN_CHANNEL* channel;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
ArrayList_Lock(dvcman->channels);
index = 0;
channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++);
while (channel)
{
if (channel->channel_id == ChannelId)
{
found = TRUE;
break;
}
channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++);
}
ArrayList_Unlock(dvcman->channels);
return (found) ? ((IWTSVirtualChannel*) channel) : NULL;
}
void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName)
{
int i;
BOOL found = FALSE;
void* pInterface = NULL;
DVCMAN_LISTENER* listener;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
for (i = 0; i < dvcman->num_listeners; i++)
{
listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
if (strcmp(listener->channel_name, ChannelName) == 0)
{
pInterface = listener->iface.pInterface;
found = TRUE;
break;
}
}
return (found) ? pInterface : NULL;
}
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
{
DVCMAN* dvcman;
dvcman = (DVCMAN*) malloc(sizeof(DVCMAN));
ZeroMemory(dvcman, sizeof(DVCMAN));
dvcman->iface.CreateListener = dvcman_create_listener;
dvcman->iface.PushEvent = dvcman_push_event;
dvcman->iface.FindChannelById = dvcman_find_channel_by_id;
dvcman->iface.GetChannelId = dvcman_get_channel_id;
dvcman->drdynvc = plugin;
dvcman->channels = ArrayList_New(TRUE);
return (IWTSVirtualChannelManager*) dvcman;
}
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args)
{
DVCMAN_ENTRY_POINTS entryPoints;
PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
fprintf(stderr, "Loading Dynamic Virtual Channel %s\n", args->argv[0]);
pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(args->argv[0],
NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC);
if (pDVCPluginEntry)
{
entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
entryPoints.iface.GetPlugin = dvcman_get_plugin;
entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
entryPoints.dvcman = (DVCMAN*) pChannelMgr;
entryPoints.args = args;
pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints);
}
return 0;
}
static void dvcman_channel_free(DVCMAN_CHANNEL* channel)
{
if (channel->channel_callback)
channel->channel_callback->OnClose(channel->channel_callback);
free(channel);
}
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
{
int i;
int count;
IWTSPlugin* pPlugin;
DVCMAN_LISTENER* listener;
DVCMAN_CHANNEL* channel;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
ArrayList_Lock(dvcman->channels);
count = ArrayList_Count(dvcman->channels);
for (i = 0; i < count; i++)
{
channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, i);
dvcman_channel_free(channel);
}
ArrayList_Unlock(dvcman->channels);
ArrayList_Free(dvcman->channels);
for (i = 0; i < dvcman->num_listeners; i++)
{
listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
free(listener->channel_name);
free(listener);
}
for (i = 0; i < dvcman->num_plugins; i++)
{
pPlugin = dvcman->plugins[i];
if (pPlugin->Terminated)
pPlugin->Terminated(pPlugin);
}
free(dvcman);
}
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr)
{
int i;
IWTSPlugin* pPlugin;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
for (i = 0; i < dvcman->num_plugins; i++)
{
pPlugin = dvcman->plugins[i];
if (pPlugin->Initialize)
pPlugin->Initialize(pPlugin, pChannelMgr);
}
return 0;
}
static int dvcman_write_channel(IWTSVirtualChannel* pChannel, UINT32 cbSize, BYTE* pBuffer, void* pReserved)
{
int status;
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
WaitForSingleObject(channel->dvc_chan_mutex, INFINITE);
status = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize);
ReleaseMutex(channel->dvc_chan_mutex);
return status;
}
static int dvcman_close_channel_iface(IWTSVirtualChannel* pChannel)
{
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
DVCMAN* dvcman = channel->dvcman;
DEBUG_DVC("id=%d", channel->channel_id);
ArrayList_Remove(dvcman->channels, channel);
dvcman_channel_free(channel);
return 1;
}
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName)
{
int i;
int bAccept;
DVCMAN_LISTENER* listener;
DVCMAN_CHANNEL* channel;
DrdynvcClientContext* context;
IWTSVirtualChannelCallback* pCallback;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
channel = (DVCMAN_CHANNEL*) malloc(sizeof(DVCMAN_CHANNEL));
ZeroMemory(channel, sizeof(DVCMAN_CHANNEL));
channel->dvcman = dvcman;
channel->channel_id = ChannelId;
channel->channel_name = _strdup(ChannelName);
for (i = 0; i < dvcman->num_listeners; i++)
{
listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
if (strcmp(listener->channel_name, ChannelName) == 0)
{
channel->iface.Write = dvcman_write_channel;
channel->iface.Close = dvcman_close_channel_iface;
channel->dvc_chan_mutex = CreateMutex(NULL, FALSE, NULL);
bAccept = 1;
pCallback = NULL;
if (listener->listener_callback->OnNewChannelConnection(listener->listener_callback,
(IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1)
{
DEBUG_DVC("listener %s created new channel %d",
listener->channel_name, channel->channel_id);
channel->status = 0;
channel->channel_callback = pCallback;
channel->pInterface = listener->iface.pInterface;
ArrayList_Add(dvcman->channels, channel);
context = dvcman->drdynvc->context;
IFCALL(context->OnChannelConnected, context, ChannelName, listener->iface.pInterface);
return 0;
}
else
{
DEBUG_WARN("channel rejected by plugin");
free(channel);
return 1;
}
}
}
free(channel);
return 1;
}
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId)
{
DVCMAN_CHANNEL* channel;
IWTSVirtualChannel* ichannel;
DrdynvcClientContext* context;
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
if (!channel)
{
DEBUG_WARN("ChannelId %d not found!", ChannelId);
return 1;
}
if (channel->dvc_data)
{
Stream_Free(channel->dvc_data, TRUE);
channel->dvc_data = NULL;
}
if (channel->status == 0)
{
context = dvcman->drdynvc->context;
IFCALL(context->OnChannelDisconnected, context, channel->channel_name, channel->pInterface);
free(channel->channel_name);
DEBUG_DVC("dvcman_close_channel: channel %d closed", ChannelId);
ichannel = (IWTSVirtualChannel*) channel;
ichannel->Close(ichannel);
}
return 0;
}
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length)
{
DVCMAN_CHANNEL* channel;
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
if (!channel)
{
DEBUG_WARN("ChannelId %d not found!", ChannelId);
return 1;
}
if (channel->dvc_data)
Stream_Free(channel->dvc_data, TRUE);
channel->dvc_data = Stream_New(NULL, length);
return 0;
}
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size)
{
int error = 0;
DVCMAN_CHANNEL* channel;
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
if (!channel)
{
DEBUG_WARN("ChannelId %d not found!", ChannelId);
return 1;
}
if (channel->dvc_data)
{
/* Fragmented data */
if (Stream_GetPosition(channel->dvc_data) + data_size > (UINT32) Stream_Capacity(channel->dvc_data))
{
DEBUG_WARN("data exceeding declared length!");
Stream_Free(channel->dvc_data, TRUE);
channel->dvc_data = NULL;
return 1;
}
Stream_Write(channel->dvc_data, data, data_size);
if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data))
{
error = channel->channel_callback->OnDataReceived(channel->channel_callback,
Stream_Capacity(channel->dvc_data), Stream_Buffer(channel->dvc_data));
Stream_Free(channel->dvc_data, TRUE);
channel->dvc_data = NULL;
}
}
else
{
error = channel->channel_callback->OnDataReceived(channel->channel_callback, data_size, data);
}
return error;
}

View File

@ -1,97 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Dynamic Virtual Channel Manager
*
* 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 __DVCMAN_H
#define __DVCMAN_H
#include <freerdp/dvc.h>
#include <freerdp/addin.h>
#include <winpr/collections.h>
#include "drdynvc_main.h"
#define MAX_PLUGINS 32
struct _DVCMAN
{
IWTSVirtualChannelManager iface;
drdynvcPlugin* drdynvc;
const char* plugin_names[MAX_PLUGINS];
IWTSPlugin* plugins[MAX_PLUGINS];
int num_plugins;
IWTSListener* listeners[MAX_PLUGINS];
int num_listeners;
wArrayList* channels;
};
typedef struct _DVCMAN DVCMAN;
struct _DVCMAN_LISTENER
{
IWTSListener iface;
DVCMAN* dvcman;
char* channel_name;
UINT32 flags;
IWTSListenerCallback* listener_callback;
};
typedef struct _DVCMAN_LISTENER DVCMAN_LISTENER;
struct _DVCMAN_ENTRY_POINTS
{
IDRDYNVC_ENTRY_POINTS iface;
DVCMAN* dvcman;
ADDIN_ARGV* args;
};
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
struct _DVCMAN_CHANNEL
{
IWTSVirtualChannel iface;
int status;
DVCMAN* dvcman;
void* pInterface;
UINT32 channel_id;
char* channel_name;
IWTSVirtualChannelCallback* channel_callback;
wStream* dvc_data;
HANDLE dvc_chan_mutex;
};
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin);
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args);
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName);
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId);
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length);
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size);
void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName);
#endif

View File

@ -23,14 +23,9 @@ set(${MODULE_PREFIX}_SRCS
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})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -67,15 +67,14 @@ static void* drdynvc_server_thread(void* arg)
break;
}
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned);
if (BytesReturned < 1)
continue;
Stream_EnsureRemainingCapacity(s, BytesReturned);
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);
break;
}
}

View File

@ -31,19 +31,9 @@ endif()
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-file winpr-synch winpr-thread winpr-interlocked)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} winpr freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -49,7 +49,14 @@
#endif
#ifdef HAVE_FCNTL_H
#define __USE_GNU /* for O_PATH */
#include <fcntl.h>
#undef __USE_GNU
#endif
#ifdef _WIN32
#pragma comment(lib, "Shlwapi.lib")
#include <Shlwapi.h>
#endif
#include "drive_file.h"
@ -187,6 +194,11 @@ static BOOL drive_file_init(DRIVE_FILE* file, UINT32 DesiredAccess, UINT32 Creat
if (STAT(file->fullpath, &st) == 0)
{
file->is_dir = (S_ISDIR(st.st_mode) ? TRUE : FALSE);
if (!file->is_dir && !S_ISREG(st.st_mode))
{
file->err = EPERM;
return TRUE;
}
#ifndef WIN32
if (st.st_size > (unsigned long) 0x07FFFFFFF)
largeFile = TRUE;
@ -301,6 +313,25 @@ DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id,
return NULL;
}
#if defined(__linux__) && defined(O_PATH)
if (file->fd < 0 && file->err == EACCES)
{
/**
* We have no access permissions for the file or directory but if the
* peer is only interested in reading the object's attributes we can try
* to obtain a file descriptor who's only purpose is to perform
* operations that act purely at the file descriptor level.
* See open(2)
**/
{
if ((file->fd = OPEN(file->fullpath, O_PATH)) >= 0)
{
file->err = 0;
}
}
}
#endif
return file;
}
@ -425,6 +456,29 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
return TRUE;
}
int dir_empty(const char *path)
{
#ifdef _WIN32
return PathIsDirectoryEmptyA(path);
#else
struct dirent *dp;
int empty = 1;
DIR *dir = opendir(path);
if (dir == NULL) //Not a directory or doesn't exist
return 1;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue; /* Skip . and .. */
empty = 0;
break;
}
closedir(dir);
return empty;
#endif
}
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
{
char* s = NULL;
@ -433,7 +487,11 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
int status;
char* fullpath;
struct STAT st;
#if defined(__linux__) && !defined(ANDROID)
struct timespec tv[2];
#else
struct timeval tv[2];
#endif
UINT64 LastWriteTime;
UINT32 FileAttributes;
UINT32 FileNameLength;
@ -454,14 +512,20 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
return FALSE;
tv[0].tv_sec = st.st_atime;
tv[0].tv_usec = 0;
tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
tv[1].tv_usec = 0;
#ifndef WIN32
/* TODO on win32 */
#ifdef ANDROID
tv[0].tv_usec = 0;
tv[1].tv_usec = 0;
utimes(file->fullpath, tv);
#elif defined (__linux__)
tv[0].tv_nsec = 0;
tv[1].tv_nsec = 0;
futimens(file->fd, tv);
#else
tv[0].tv_usec = 0;
tv[1].tv_usec = 0;
futimes(file->fd, tv);
#endif
@ -492,6 +556,9 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
case FileDispositionInformation:
/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
if (file->is_dir && !dir_empty(file->fullpath))
break;
if (Length)
Stream_Read_UINT8(input, file->delete_pending);
else

View File

@ -117,6 +117,7 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input);
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
const char* path, wStream* output);
int dir_empty(const char *path);
extern UINT sys_code_page;

View File

@ -346,6 +346,9 @@ static void drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
}
if (file && file->is_dir && !dir_empty(file->fullpath))
irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;
Stream_Write_UINT32(irp->output, Length);
irp->Complete(irp);
@ -617,6 +620,9 @@ static void drive_free(DEVICE* device)
CloseHandle(drive->thread);
ListDictionary_Free(drive->files);
MessageQueue_Free(drive->IrpQueue);
Stream_Free(drive->device.data, TRUE);
free(drive);
}

View File

@ -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()

View File

@ -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 "echo" TYPE "dynamic"
DESCRIPTION "Echo Virtual Channel Extension"

View File

@ -25,14 +25,9 @@ include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -26,12 +26,11 @@
#include <string.h>
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <winpr/cmdline.h>
#include <freerdp/addin.h>
#include <winpr/stream.h>
#include "echo_main.h"
typedef struct _ECHO_LISTENER_CALLBACK ECHO_LISTENER_CALLBACK;
@ -61,47 +60,23 @@ struct _ECHO_PLUGIN
ECHO_LISTENER_CALLBACK* listener_callback;
};
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
{
int error;
int status;
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
#ifdef WITH_DEBUG_DVC
int i = 0;
char* debug_buffer;
char* p;
if (cbSize > 0)
{
debug_buffer = (char*) malloc(3 * cbSize);
ZeroMemory(debug_buffer, 3 * cbSize);
p = debug_buffer;
for (i = 0; i < (int) (cbSize - 1); i++)
{
sprintf(p, "%02x ", pBuffer[i]);
p += 3;
}
sprintf(p, "%02x", pBuffer[i]);
DEBUG_DVC("ECHO %d: %s", cbSize, debug_buffer);
free(debug_buffer);
}
#endif
BYTE* pBuffer = Stream_Pointer(data);
UINT32 cbSize = Stream_GetRemainingLength(data);
/* echo back what we have received. ECHO does not have any message IDs. */
error = callback->channel->Write(callback->channel, cbSize, pBuffer, NULL);
status = callback->channel->Write(callback->channel, cbSize, pBuffer, NULL);
return error;
return status;
}
static int echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
DEBUG_DVC("");
free(callback);
return 0;
@ -114,10 +89,10 @@ static int echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallbac
ECHO_CHANNEL_CALLBACK* callback;
ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*) pListenerCallback;
DEBUG_DVC("");
callback = (ECHO_CHANNEL_CALLBACK*) calloc(1, sizeof(ECHO_CHANNEL_CALLBACK));
callback = (ECHO_CHANNEL_CALLBACK*) malloc(sizeof(ECHO_CHANNEL_CALLBACK));
ZeroMemory(callback, sizeof(ECHO_CHANNEL_CALLBACK));
if (!callback)
return -1;
callback->iface.OnDataReceived = echo_on_data_received;
callback->iface.OnClose = echo_on_close;
@ -134,10 +109,10 @@ static int echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager
{
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
DEBUG_DVC("");
echo->listener_callback = (ECHO_LISTENER_CALLBACK*) calloc(1, sizeof(ECHO_LISTENER_CALLBACK));
echo->listener_callback = (ECHO_LISTENER_CALLBACK*) malloc(sizeof(ECHO_LISTENER_CALLBACK));
ZeroMemory(echo->listener_callback, sizeof(ECHO_LISTENER_CALLBACK));
if (!echo->listener_callback)
return -1;
echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection;
echo->listener_callback->plugin = pPlugin;
@ -151,9 +126,10 @@ static int echo_plugin_terminated(IWTSPlugin* pPlugin)
{
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
DEBUG_DVC("");
free(echo);
if (echo)
{
free(echo);
}
return 0;
}
@ -164,23 +140,25 @@ static int echo_plugin_terminated(IWTSPlugin* pPlugin)
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
int error = 0;
int status = 0;
ECHO_PLUGIN* echo;
echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo");
if (echo == NULL)
if (!echo)
{
echo = (ECHO_PLUGIN*) malloc(sizeof(ECHO_PLUGIN));
ZeroMemory(echo, sizeof(ECHO_PLUGIN));
echo = (ECHO_PLUGIN*) calloc(1, sizeof(ECHO_PLUGIN));
if (!echo)
return -1;
echo->iface.Initialize = echo_plugin_initialize;
echo->iface.Connected = NULL;
echo->iface.Disconnected = NULL;
echo->iface.Terminated = echo_plugin_terminated;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo);
status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo);
}
return error;
return status;
}

View File

@ -27,12 +27,13 @@
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/utils/debug.h>
#include <freerdp/channels/log.h>
#define DVC_TAG CHANNELS_TAG("echo.client")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
#define DEBUG_DVC(fmt, ...) WLog_DBG(DVC_TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#define DEBUG_DVC(fmt, ...) do { } while (0)
#endif
#endif /* __ECHO_MAIN_H */

View File

@ -0,0 +1,31 @@
# 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("echo")
set(${MODULE_PREFIX}_SRCS
echo_main.c)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

@ -0,0 +1,234 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Echo Virtual Channel Extension
*
* Copyright 2014 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/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include <freerdp/server/echo.h>
typedef struct _echo_server
{
echo_server_context context;
BOOL opened;
HANDLE stopEvent;
HANDLE thread;
void* echo_channel;
DWORD SessionId;
} echo_server;
static BOOL echo_server_open_channel(echo_server* echo)
{
DWORD Error;
HANDLE hEvent;
DWORD StartTick;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION,
WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned) == FALSE)
{
return FALSE;
}
echo->SessionId = (DWORD) *pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(echo->context.vcm);
StartTick = GetTickCount();
while (echo->echo_channel == NULL)
{
WaitForSingleObject(hEvent, 1000);
echo->echo_channel = WTSVirtualChannelOpenEx(echo->SessionId,
"ECHO", WTS_CHANNEL_OPTION_DYNAMIC);
if (echo->echo_channel)
break;
Error = GetLastError();
if (Error == ERROR_NOT_FOUND)
break;
if (GetTickCount() - StartTick > 5000)
break;
}
return echo->echo_channel ? TRUE : FALSE;
}
static void* echo_server_thread_func(void* arg)
{
wStream* s;
void* buffer;
DWORD nCount;
HANDLE events[8];
BOOL ready = FALSE;
HANDLE ChannelEvent;
DWORD BytesReturned = 0;
echo_server* echo = (echo_server*) arg;
if (echo_server_open_channel(echo) == FALSE)
{
IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED);
return NULL;
}
buffer = NULL;
BytesReturned = 0;
ChannelEvent = NULL;
if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
nCount = 0;
events[nCount++] = echo->stopEvent;
events[nCount++] = ChannelEvent;
/* Wait for the client to confirm that the Graphics Pipeline dynamic channel is ready */
while (1)
{
if (WaitForMultipleObjects(nCount, events, FALSE, 100) == WAIT_OBJECT_0)
{
IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_CLOSED);
break;
}
if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE)
{
IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_ERROR);
break;
}
ready = *((BOOL*) buffer);
WTSFreeMemory(buffer);
if (ready)
{
IFCALL(echo->context.OpenResult, &echo->context, ECHO_SERVER_OPEN_RESULT_OK);
break;
}
}
s = Stream_New(NULL, 4096);
while (ready)
{
if (WaitForMultipleObjects(nCount, events, FALSE, INFINITE) == WAIT_OBJECT_0)
break;
Stream_SetPosition(s, 0);
WTSVirtualChannelRead(echo->echo_channel, 0, NULL, 0, &BytesReturned);
if (BytesReturned < 1)
continue;
Stream_EnsureRemainingCapacity(s, BytesReturned);
if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR) Stream_Buffer(s),
(ULONG) Stream_Capacity(s), &BytesReturned) == FALSE)
{
break;
}
IFCALL(echo->context.Response, &echo->context, (BYTE *) Stream_Buffer(s), BytesReturned);
}
Stream_Free(s, TRUE);
WTSVirtualChannelClose(echo->echo_channel);
echo->echo_channel = NULL;
return NULL;
}
static void echo_server_open(echo_server_context* context)
{
echo_server* echo = (echo_server*) context;
if (echo->thread == NULL)
{
echo->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
echo->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) echo_server_thread_func, (void*) echo, 0, NULL);
}
}
static void echo_server_close(echo_server_context* context)
{
echo_server* echo = (echo_server*) context;
if (echo->thread)
{
SetEvent(echo->stopEvent);
WaitForSingleObject(echo->thread, INFINITE);
CloseHandle(echo->thread);
CloseHandle(echo->stopEvent);
echo->thread = NULL;
echo->stopEvent = NULL;
}
}
static BOOL echo_server_request(echo_server_context* context, const BYTE* buffer, UINT32 length)
{
echo_server* echo = (echo_server*) context;
return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR) buffer, length, NULL);
}
echo_server_context* echo_server_context_new(HANDLE vcm)
{
echo_server* echo;
echo = (echo_server*) calloc(1, sizeof(echo_server));
echo->context.vcm = vcm;
echo->context.Open = echo_server_open;
echo->context.Close = echo_server_close;
echo->context.Request = echo_server_request;
return (echo_server_context*) echo;
}
void echo_server_context_free(echo_server_context* context)
{
echo_server* echo = (echo_server*) context;
echo_server_close(context);
free(echo);
}

View File

@ -15,9 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel("sample")
define_channel("encomsp")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -0,0 +1,13 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT ON)
define_channel_options(NAME "encomsp" TYPE "static"
DESCRIPTION "Multiparty Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPEMC]"
DEFAULT ${OPTION_DEFAULT})
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})

View File

@ -15,21 +15,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_client("sample")
define_channel_client("encomsp")
include_directories(..)
set(${MODULE_PREFIX}_SRCS
sample_main.c
sample_main.h)
encomsp_main.c
encomsp_main.h)
add_channel_client_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)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")

View File

@ -0,0 +1,957 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Multiparty Virtual Channel
*
* Copyright 2014 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 <freerdp/channels/log.h>
#include <freerdp/client/encomsp.h>
#include "encomsp_main.h"
static int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
{
if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE)
return -1;
Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
return 1;
}
static int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
{
Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */
Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */
return 1;
}
static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str)
{
ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING));
if (Stream_GetRemainingLength(s) < 2)
return -1;
Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */
if (str->cchString > 1024)
return -1;
if (Stream_GetRemainingLength(s) < (size_t) (str->cchString * 2))
return -1;
Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */
return 1;
}
EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp)
{
EncomspClientContext* pInterface;
pInterface = (EncomspClientContext*) encomsp->channelEntryPoints.pInterface;
return pInterface;
}
int encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s)
{
UINT32 status = 0;
if (!encomsp)
return -1;
#if 0
WLog_INFO(TAG, "EncomspWrite (%d)", Stream_Length(s));
winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
#endif
status = encomsp->channelEntryPoints.pVirtualChannelWrite(encomsp->OpenHandle,
Stream_Buffer(s), (UINT32) Stream_Length(s), s);
if (status != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "encomsp_virtual_channel_write: VirtualChannelWrite failed %d", status);
return -1;
}
return 1;
}
static int encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_FILTER_UPDATED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 1)
return -1;
Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->FilterUpdated)
{
return context->FilterUpdated(context, &pdu);
}
return 1;
}
static int encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_APPLICATION_CREATED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 6)
return -1;
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0)
return -1;
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ApplicationCreated)
{
return context->ApplicationCreated(context, &pdu);
}
return 1;
}
static int encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_APPLICATION_REMOVED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ApplicationRemoved)
{
return context->ApplicationRemoved(context, &pdu);
}
return 1;
}
static int encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_WINDOW_CREATED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 10)
return -1;
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0)
return -1;
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->WindowCreated)
{
return context->WindowCreated(context, &pdu);
}
return 1;
}
static int encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_WINDOW_REMOVED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->WindowRemoved)
{
return context->WindowRemoved(context, &pdu);
}
return 1;
}
static int encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_SHOW_WINDOW_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ShowWindow)
{
return context->ShowWindow(context, &pdu);
}
return 1;
}
static int encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_PARTICIPANT_CREATED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 10)
return -1;
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
if (encomsp_read_unicode_string(s, &(pdu.FriendlyName)) < 0)
return -1;
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ParticipantCreated)
{
return context->ParticipantCreated(context, &pdu);
}
return 1;
}
static int encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_PARTICIPANT_REMOVED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 12)
return -1;
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */
Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ParticipantRemoved)
{
return context->ParticipantRemoved(context, &pdu);
}
return 1;
}
static int encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 6)
return -1;
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ChangeParticipantControlLevel)
{
return context->ChangeParticipantControlLevel(context, &pdu);
}
return 1;
}
static int encomsp_send_change_participant_control_level_pdu(EncomspClientContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu)
{
wStream* s;
encomspPlugin* encomsp;
encomsp = (encomspPlugin*) context->handle;
pdu->Type = ODTYPE_PARTICIPANT_CTRL_CHANGED;
pdu->Length = ENCOMSP_ORDER_HEADER_SIZE + 6;
s = Stream_New(NULL, pdu->Length);
encomsp_write_header(s, (ENCOMSP_ORDER_HEADER*) pdu);
Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */
Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */
Stream_SealLength(s);
encomsp_virtual_channel_write(encomsp, s);
return 1;
}
static int encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->GraphicsStreamPaused)
{
return context->GraphicsStreamPaused(context, &pdu);
}
return 1;
}
static int encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
EncomspClientContext* context;
ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU pdu;
context = encomsp_get_client_interface(encomsp);
if (!context)
return -1;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->GraphicsStreamResumed)
{
return context->GraphicsStreamResumed(context, &pdu);
}
return 1;
}
static int encomsp_process_receive(encomspPlugin* encomsp, wStream* s)
{
int status = 1;
ENCOMSP_ORDER_HEADER header;
while (Stream_GetRemainingLength(s) > 0)
{
if (encomsp_read_header(s, &header) < 0)
return -1;
//WLog_DBG(TAG, "EncomspReceive: Type: %d Length: %d", header.Type, header.Length);
switch (header.Type)
{
case ODTYPE_FILTER_STATE_UPDATED:
status = encomsp_recv_filter_updated_pdu(encomsp, s, &header);
break;
case ODTYPE_APP_REMOVED:
status = encomsp_recv_application_removed_pdu(encomsp, s, &header);
break;
case ODTYPE_APP_CREATED:
status = encomsp_recv_application_created_pdu(encomsp, s, &header);
break;
case ODTYPE_WND_REMOVED:
status = encomsp_recv_window_removed_pdu(encomsp, s, &header);
break;
case ODTYPE_WND_CREATED:
status = encomsp_recv_window_created_pdu(encomsp, s, &header);
break;
case ODTYPE_WND_SHOW:
status = encomsp_recv_show_window_pdu(encomsp, s, &header);
break;
case ODTYPE_PARTICIPANT_REMOVED:
status = encomsp_recv_participant_removed_pdu(encomsp, s, &header);
break;
case ODTYPE_PARTICIPANT_CREATED:
status = encomsp_recv_participant_created_pdu(encomsp, s, &header);
break;
case ODTYPE_PARTICIPANT_CTRL_CHANGED:
status = encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header);
break;
case ODTYPE_GRAPHICS_STREAM_PAUSED:
status = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header);
break;
case ODTYPE_GRAPHICS_STREAM_RESUMED:
status = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header);
break;
default:
status = -1;
break;
}
if (status < 0)
return -1;
}
return status;
}
static void encomsp_process_connect(encomspPlugin* encomsp)
{
}
/****************************************************************************************/
static wListDictionary* g_InitHandles;
static wListDictionary* g_OpenHandles;
void encomsp_add_init_handle_data(void* pInitHandle, void* pUserData)
{
if (!g_InitHandles)
g_InitHandles = ListDictionary_New(TRUE);
ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
}
void* encomsp_get_init_handle_data(void* pInitHandle)
{
void* pUserData = NULL;
pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
return pUserData;
}
void encomsp_remove_init_handle_data(void* pInitHandle)
{
ListDictionary_Remove(g_InitHandles, pInitHandle);
}
void encomsp_add_open_handle_data(DWORD openHandle, void* pUserData)
{
void* pOpenHandle = (void*) (size_t) openHandle;
if (!g_OpenHandles)
g_OpenHandles = ListDictionary_New(TRUE);
ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
}
void* encomsp_get_open_handle_data(DWORD openHandle)
{
void* pUserData = NULL;
void* pOpenHandle = (void*) (size_t) openHandle;
pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
return pUserData;
}
void encomsp_remove_open_handle_data(DWORD openHandle)
{
void* pOpenHandle = (void*) (size_t) openHandle;
ListDictionary_Remove(g_OpenHandles, pOpenHandle);
}
int encomsp_send(encomspPlugin* encomsp, wStream* s)
{
UINT32 status = 0;
encomspPlugin* plugin = (encomspPlugin*) encomsp;
if (!plugin)
{
status = CHANNEL_RC_BAD_INIT_HANDLE;
}
else
{
status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle,
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
}
if (status != CHANNEL_RC_OK)
{
Stream_Free(s, TRUE);
WLog_ERR(TAG, "encomsp_send: VirtualChannelWrite failed %d", status);
}
return status;
}
static void encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp,
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
wStream* data_in;
if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
{
return;
}
if (dataFlags & CHANNEL_FLAG_FIRST)
{
if (encomsp->data_in)
Stream_Free(encomsp->data_in, TRUE);
encomsp->data_in = Stream_New(NULL, totalLength);
}
data_in = encomsp->data_in;
Stream_EnsureRemainingCapacity(data_in, (int) dataLength);
Stream_Write(data_in, pData, dataLength);
if (dataFlags & CHANNEL_FLAG_LAST)
{
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
{
WLog_ERR(TAG, "encomsp_plugin_process_received: read error");
}
encomsp->data_in = NULL;
Stream_SealLength(data_in);
Stream_SetPosition(data_in, 0);
MessageQueue_Post(encomsp->queue, NULL, 0, (void*) data_in, NULL);
}
}
static VOID VCAPITYPE encomsp_virtual_channel_open_event(DWORD openHandle, UINT event,
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
encomspPlugin* encomsp;
encomsp = (encomspPlugin*) encomsp_get_open_handle_data(openHandle);
if (!encomsp)
{
WLog_ERR(TAG, "encomsp_virtual_channel_open_event: error no match");
return;
}
switch (event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength, totalLength, dataFlags);
break;
case CHANNEL_EVENT_WRITE_COMPLETE:
Stream_Free((wStream*) pData, TRUE);
break;
}
}
static void* encomsp_virtual_channel_client_thread(void* arg)
{
wStream* data;
wMessage message;
encomspPlugin* encomsp = (encomspPlugin*) arg;
encomsp_process_connect(encomsp);
while (1)
{
if (!MessageQueue_Wait(encomsp->queue))
break;
if (MessageQueue_Peek(encomsp->queue, &message, TRUE))
{
if (message.id == WMQ_QUIT)
break;
if (message.id == 0)
{
data = (wStream*) message.wParam;
encomsp_process_receive(encomsp, data);
}
}
}
ExitThread(0);
return NULL;
}
static void encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, LPVOID pData, UINT32 dataLength)
{
UINT32 status;
status = encomsp->channelEntryPoints.pVirtualChannelOpen(encomsp->InitHandle,
&encomsp->OpenHandle, encomsp->channelDef.name, encomsp_virtual_channel_open_event);
encomsp_add_open_handle_data(encomsp->OpenHandle, encomsp);
if (status != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "encomsp_virtual_channel_event_connected: open failed: status: %d", status);
return;
}
encomsp->queue = MessageQueue_New(NULL);
encomsp->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) encomsp_virtual_channel_client_thread, (void*) encomsp, 0, NULL);
}
static void encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp)
{
if (encomsp->queue)
{
MessageQueue_PostQuit(encomsp->queue, 0);
WaitForSingleObject(encomsp->thread, INFINITE);
MessageQueue_Free(encomsp->queue);
encomsp->queue = NULL;
CloseHandle(encomsp->thread);
encomsp->thread = NULL;
}
encomsp->channelEntryPoints.pVirtualChannelClose(encomsp->OpenHandle);
if (encomsp->data_in)
{
Stream_Free(encomsp->data_in, TRUE);
encomsp->data_in = NULL;
}
encomsp_remove_open_handle_data(encomsp->OpenHandle);
encomsp_remove_init_handle_data(encomsp->InitHandle);
free(encomsp->context);
free(encomsp);
}
static VOID VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
{
encomspPlugin* encomsp;
encomsp = (encomspPlugin*) encomsp_get_init_handle_data(pInitHandle);
if (!encomsp)
{
WLog_ERR(TAG, "encomsp_virtual_channel_init_event: error no match");
return;
}
switch (event)
{
case CHANNEL_EVENT_CONNECTED:
encomsp_virtual_channel_event_connected(encomsp, pData, dataLength);
break;
case CHANNEL_EVENT_DISCONNECTED:
break;
case CHANNEL_EVENT_TERMINATED:
encomsp_virtual_channel_event_terminated(encomsp);
break;
}
}
/* encomsp is always built-in */
#define VirtualChannelEntry encomsp_VirtualChannelEntry
BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
encomspPlugin* encomsp;
EncomspClientContext* context;
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
encomsp = (encomspPlugin*) calloc(1, sizeof(encomspPlugin));
encomsp->channelDef.options =
CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL;
strcpy(encomsp->channelDef.name, "encomsp");
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
{
context = (EncomspClientContext*) calloc(1, sizeof(EncomspClientContext));
context->handle = (void*) encomsp;
context->FilterUpdated = NULL;
context->ApplicationCreated = NULL;
context->ApplicationRemoved = NULL;
context->WindowCreated = NULL;
context->WindowRemoved = NULL;
context->ShowWindow = NULL;
context->ParticipantCreated = NULL;
context->ParticipantRemoved = NULL;
context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu;
context->GraphicsStreamPaused = NULL;
context->GraphicsStreamResumed = NULL;
*(pEntryPointsEx->ppInterface) = (void*) context;
encomsp->context = context;
}
CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
encomsp->channelEntryPoints.pVirtualChannelInit(&encomsp->InitHandle,
&encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, encomsp_virtual_channel_init_event);
encomsp->channelEntryPoints.pInterface = *(encomsp->channelEntryPoints.ppInterface);
encomsp->channelEntryPoints.ppInterface = &(encomsp->channelEntryPoints.pInterface);
encomsp_add_init_handle_data(encomsp->InitHandle, (void*) encomsp);
return 1;
}

View File

@ -0,0 +1,53 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Multiparty Virtual Channel
*
* Copyright 2014 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_ENCOMSP_CLIENT_MAIN_H
#define FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <freerdp/api.h>
#include <freerdp/channels/log.h>
#include <freerdp/svc.h>
#include <freerdp/addin.h>
#include <freerdp/client/encomsp.h>
#define TAG CHANNELS_TAG("encomsp.client")
struct encomsp_plugin
{
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
EncomspClientContext* context;
HANDLE thread;
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;
wMessageQueue* queue;
};
typedef struct encomsp_plugin encomspPlugin;
#endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */

View File

@ -1,5 +1,5 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP X11 cmake build script
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
@ -15,22 +15,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "xfreerdp-server-cli")
set(MODULE_PREFIX "FREERDP_SERVER_X11")
define_channel_server("encomsp")
include_directories(..)
set(${MODULE_PREFIX}_SRCS
xfreerdp.c)
encomsp_main.c
encomsp_main.h)
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "xfreerdp-server" RUNTIME_OUTPUT_DIRECTORY "..")
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} xfreerdp-server)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/X11")
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

@ -0,0 +1,273 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Multiparty Virtual Channel
*
* Copyright 2014 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 <freerdp/channels/log.h>
#include "encomsp_main.h"
#define TAG CHANNELS_TAG("encomsp.server")
static int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
{
if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE)
return -1;
Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
return 1;
}
#if 0
static int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
{
Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */
Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */
return 1;
}
static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str)
{
ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING));
if (Stream_GetRemainingLength(s) < 2)
return -1;
Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */
if (str->cchString > 1024)
return -1;
if (Stream_GetRemainingLength(s) < (str->cchString * 2))
return -1;
Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */
return 1;
}
#endif
static int encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context, wStream* s, ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 6)
return -1;
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
end = (int) Stream_GetPosition(s);
if ((beg + header->Length) < end)
return -1;
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end))
return -1;
Stream_SetPosition(s, (beg + header->Length));
}
if (context->ChangeParticipantControlLevel)
{
return context->ChangeParticipantControlLevel(context, &pdu);
}
return 1;
}
static int encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s)
{
int status = 1;
ENCOMSP_ORDER_HEADER header;
while (Stream_GetRemainingLength(s) > 0)
{
if (encomsp_read_header(s, &header) < 0)
return -1;
WLog_INFO(TAG, "EncomspReceive: Type: %d Length: %d", header.Type, header.Length);
switch (header.Type)
{
case ODTYPE_PARTICIPANT_CTRL_CHANGED:
status = encomsp_recv_change_participant_control_level_pdu(context, s, &header);
break;
default:
status = -1;
break;
}
if (status < 0)
return -1;
}
return status;
}
static void* encomsp_server_thread(void* arg)
{
wStream* s;
DWORD status;
DWORD nCount;
void* buffer;
HANDLE events[8];
HANDLE ChannelEvent;
DWORD BytesReturned;
ENCOMSP_ORDER_HEADER* header;
EncomspServerContext* context;
context = (EncomspServerContext*) 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;
}
WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned);
if (BytesReturned < 1)
continue;
Stream_EnsureRemainingCapacity(s, BytesReturned);
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
{
break;
}
if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
{
header = (ENCOMSP_ORDER_HEADER*) Stream_Buffer(s);
if (header->Length >= Stream_GetPosition(s))
{
Stream_SealLength(s);
Stream_SetPosition(s, 0);
encomsp_server_receive_pdu(context, s);
Stream_SetPosition(s, 0);
}
}
}
Stream_Free(s, TRUE);
return NULL;
}
static int encomsp_server_start(EncomspServerContext* context)
{
context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "encomsp");
if (!context->priv->ChannelHandle)
return -1;
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
context->priv->Thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) encomsp_server_thread, (void*) context, 0, NULL);
return 0;
}
static int encomsp_server_stop(EncomspServerContext* context)
{
SetEvent(context->priv->StopEvent);
WaitForSingleObject(context->priv->Thread, INFINITE);
CloseHandle(context->priv->Thread);
return 0;
}
EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
{
EncomspServerContext* context;
context = (EncomspServerContext*) calloc(1, sizeof(EncomspServerContext));
if (context)
{
context->vcm = vcm;
context->Start = encomsp_server_start;
context->Stop = encomsp_server_stop;
context->priv = (EncomspServerPrivate*) calloc(1, sizeof(EncomspServerPrivate));
if (context->priv)
{
}
}
return context;
}
void encomsp_server_context_free(EncomspServerContext* context)
{
if (context)
{
if (context->priv)
{
free(context->priv);
}
free(context);
}
}

View File

@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Multiparty Virtual Channel
*
* Copyright 2014 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_ENCOMSP_MAIN_H
#define FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <freerdp/server/encomsp.h>
struct _encomsp_server_private
{
HANDLE Thread;
HANDLE StopEvent;
void* ChannelHandle;
};
#endif /* FREERDP_CHANNEL_SERVER_ENCOMSP_MAIN_H */

View File

@ -22,19 +22,9 @@ set(${MODULE_PREFIX}_SRCS
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-interlocked)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} freerdp winpr)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -47,13 +47,12 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <winpr/interlocked.h>
#include <freerdp/types.h>
#include <freerdp/constants.h>
#include <winpr/stream.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/channels/rdpdr.h>
struct _PARALLEL_DEVICE
@ -93,16 +92,14 @@ static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
{
irp->IoStatus = STATUS_ACCESS_DENIED;
parallel->id = 0;
DEBUG_WARN("failed to create %s: %s", parallel->path, strerror(errno));
}
else
{
/* all read and write operations should be non-blocking */
if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
DEBUG_WARN("%s fcntl %s", path, strerror(errno));
{
DEBUG_SVC("%s(%d) created", parallel->path, parallel->file);
}
}
Stream_Write_UINT32(irp->output, parallel->id);
@ -116,9 +113,13 @@ static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
static void parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
{
if (close(parallel->file) < 0)
DEBUG_SVC("failed to close %s(%d)", parallel->path, parallel->id);
{
}
else
DEBUG_SVC("%s(%d) closed", parallel->path, parallel->id);
{
}
Stream_Zero(irp->output, 5); /* Padding(5) */
@ -145,12 +146,10 @@ static void parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
free(buffer);
buffer = NULL;
Length = 0;
DEBUG_WARN("read %s(%d) failed", parallel->path, parallel->id);
}
else
{
DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, parallel->id);
}
Stream_Write_UINT32(irp->output, Length);
@ -177,8 +176,6 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
Stream_Read_UINT64(irp->input, Offset);
Stream_Seek(irp->input, 20); /* Padding */
DEBUG_SVC("Length %u Offset %llu", Length, Offset);
len = Length;
while (len > 0)
@ -189,8 +186,6 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
DEBUG_WARN("write %s(%d) failed.", parallel->path, parallel->id);
break;
}
@ -206,15 +201,12 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
static void parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
{
DEBUG_SVC("in");
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
irp->Complete(irp);
}
static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
{
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
switch (irp->MajorFunction)
{
case IRP_MJ_CREATE:
@ -238,7 +230,6 @@ static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
break;
default:
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED;
irp->Complete(irp);
break;
@ -281,8 +272,6 @@ static void parallel_free(DEVICE* device)
{
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
DEBUG_SVC("freeing device");
MessageQueue_PostQuit(parallel->queue, 0);
WaitForSingleObject(parallel->thread, INFINITE);
CloseHandle(parallel->thread);

View File

@ -38,17 +38,9 @@ endif()
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-synch winpr-thread winpr-interlocked)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
if(WITH_CUPS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES})

View File

@ -31,7 +31,6 @@
#include <winpr/crt.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/channels/rdpdr.h>
#include "printer_main.h"
@ -87,15 +86,12 @@ static void printer_cups_write_printjob(rdpPrintJob* printjob, BYTE* data, int s
fp = fopen((const char*) cups_printjob->printjob_object, "a+b");
if (fp == NULL)
{
DEBUG_WARN("failed to open file %s", (char*) cups_printjob->printjob_object);
if (!fp)
return;
}
if (fwrite(data, 1, size, fp) < size)
{
DEBUG_WARN("failed to write file %s", (char*) cups_printjob->printjob_object);
}
fclose(fp);
@ -121,7 +117,7 @@ static void printer_cups_close_printjob(rdpPrintJob* printjob)
if (cupsPrintFile(printjob->printer->name, (const char*) cups_printjob->printjob_object, buf, 0, NULL) == 0)
{
DEBUG_WARN("cupsPrintFile: %s", cupsLastErrorString());
}
unlink(cups_printjob->printjob_object);
@ -167,20 +163,19 @@ static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id)
cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
if (cups_printjob->printjob_object == NULL)
if (!cups_printjob->printjob_object)
{
DEBUG_WARN("httpConnectEncrypt: %s", cupsLastErrorString());
free(cups_printjob);
return NULL;
}
printer_cups_get_printjob_name(buf, sizeof(buf));
cups_printjob->printjob_id = cupsCreateJob((http_t*) cups_printjob->printjob_object,
printer->name, buf, 0, NULL);
if (cups_printjob->printjob_id == 0)
if (!cups_printjob->printjob_id)
{
DEBUG_WARN("cupsCreateJob: %s", cupsLastErrorString());
httpClose((http_t*) cups_printjob->printjob_object);
free(cups_printjob);
return NULL;
@ -281,19 +276,15 @@ rdpPrinterDriver* printer_cups_get_driver(void)
{
if (cups_driver == NULL)
{
cups_driver = (rdpCupsPrinterDriver*) malloc(sizeof(rdpCupsPrinterDriver));
ZeroMemory(cups_driver, sizeof(rdpCupsPrinterDriver));
cups_driver = (rdpCupsPrinterDriver*) calloc(1, sizeof(rdpCupsPrinterDriver));
if (!cups_driver)
return NULL;
cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
cups_driver->driver.GetPrinter = printer_cups_get_printer;
cups_driver->id_sequence = 1;
#ifdef _CUPS_API_1_4
DEBUG_SVC("using CUPS API 1.4");
#else
DEBUG_SVC("using CUPS API 1.2");
#endif
}
return (rdpPrinterDriver*) cups_driver;

View File

@ -28,11 +28,10 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/interlocked.h>
#include <winpr/stream.h>
#include <freerdp/channels/rdpdr.h>
#include <freerdp/utils/svc_plugin.h>
#ifdef WITH_CUPS
#include "printer_cups.h"
@ -69,15 +68,11 @@ static void printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
if (printjob)
{
Stream_Write_UINT32(irp->output, printjob->id); /* FileId */
DEBUG_SVC("printjob id: %d", printjob->id);
}
else
{
Stream_Write_UINT32(irp->output, 0); /* FileId */
irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
DEBUG_WARN("error creating print job.");
}
irp->Complete(irp);
@ -87,20 +82,16 @@ static void printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
{
rdpPrintJob* printjob = NULL;
if (printer_dev->printer != NULL)
if (printer_dev->printer)
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
if (!printjob)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
DEBUG_WARN("printjob id %d not found.", irp->FileId);
}
else
{
printjob->Close(printjob);
DEBUG_SVC("printjob id %d closed.", irp->FileId);
}
Stream_Zero(irp->output, 4); /* Padding(4) */
@ -125,14 +116,10 @@ static void printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
DEBUG_WARN("printjob id %d not found.", irp->FileId);
}
else
{
printjob->Write(printjob, Stream_Pointer(irp->input), Length);
DEBUG_SVC("printjob id %d written %d bytes.", irp->FileId, Length);
}
Stream_Write_UINT32(irp->output, Length);
@ -168,7 +155,6 @@ static void printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
break;
default:
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED;
irp->Complete(irp);
break;
@ -267,8 +253,6 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri
CachedFieldsLen = 0;
CachedPrinterConfigData = NULL;
DEBUG_SVC("Printer %s registered", printer->name);
Flags = 0;
if (printer->is_default)
@ -332,9 +316,8 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
driver = printer_win_get_driver();
#endif
if (driver == NULL)
if (!driver)
{
DEBUG_WARN("no driver");
return 1;
}
@ -347,10 +330,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
printer = driver->GetPrinter(driver, name);
if (!printer)
{
DEBUG_WARN("printer %s not found.", name);
return 1;
}
if (driver_name && driver_name[0])
printer->driver = driver_name;

View File

@ -30,8 +30,6 @@
#include <string.h>
#include <winspool.h>
#include <freerdp/utils/svc_plugin.h>
#include "printer_main.h"
#include "printer_win.h"
@ -69,45 +67,44 @@ static void printer_win_get_printjob_name(char* buf, int size)
time_t tt;
struct tm* t;
DEBUG_WINPR("");
tt = time(NULL);
t = localtime(&tt);
snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
DEBUG_WINPR("buf: %s", buf);
}
static void printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
LPVOID pBuf = data;
DWORD cbBuf = size;
DWORD pcWritten;
if( ! WritePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten ) )
DEBUG_WINPR("WritePrinter failed");
;
if(!WritePrinter(((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten))
{
}
}
static void printer_win_close_printjob(rdpPrintJob* printjob)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
DEBUG_WINPR("");
if (!EndPagePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
{
if ( ! EndPagePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
DEBUG_WINPR("EndPagePrinter failed");;
if ( ! ClosePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
DEBUG_WINPR("ClosePrinter failed");;
}
((rdpWinPrinter*)printjob->printer)->printjob = NULL;
free(win_printjob) ;
if (!ClosePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
{
}
((rdpWinPrinter*) printjob->printer)->printjob = NULL;
free(win_printjob);
}
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
@ -115,13 +112,10 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
rdpWinPrintJob* win_printjob;
DEBUG_WINPR("");
if (win_printer->printjob != NULL)
return NULL;
win_printjob = (rdpWinPrintJob*) malloc(sizeof(rdpWinPrintJob));
ZeroMemory(win_printjob, sizeof(rdpWinPrintJob));
win_printjob = (rdpWinPrintJob*) calloc(1, sizeof(rdpWinPrintJob));
win_printjob->printjob.id = id;
win_printjob->printjob.printer = printer;
@ -132,10 +126,14 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) &(win_printjob->di));
if (!win_printjob->handle)
DEBUG_WINPR("StartDocPrinter failed");
{
}
if (!StartPagePrinter(win_printer->hPrinter))
DEBUG_WINPR("ClosePrinter failed");
{
}
win_printjob->printjob.Write = printer_win_write_printjob;
win_printjob->printjob.Close = printer_win_close_printjob;
@ -149,9 +147,7 @@ static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
DEBUG_WINPR("");
if (win_printer->printjob == NULL)
if (!win_printer->printjob)
return NULL;
if (win_printer->printjob->printjob.id != id)
@ -164,8 +160,6 @@ static void printer_win_free_printer(rdpPrinter* printer)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
DEBUG_WINPR("");
if (win_printer->printjob)
win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob);
@ -180,10 +174,8 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons
DWORD needed;
PRINTER_INFO_2 *prninfo=NULL;
size_t charsConverted;
DEBUG_WINPR("");
win_printer = (rdpWinPrinter*) malloc(sizeof(rdpWinPrinter));
ZeroMemory(win_printer, sizeof(rdpWinPrinter));
win_printer = (rdpWinPrinter*) calloc(1, sizeof(rdpWinPrinter));
win_printer->printer.id = win_driver->id_sequence++;
win_printer->printer.name = _strdup(name);
@ -195,7 +187,6 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons
swprintf(wname, 256, L"%hs", name);
OpenPrinter(wname, &(win_printer->hPrinter), NULL);
DEBUG_WINPR("handle: 0x%08X", win_printer->hPrinter);
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
@ -216,8 +207,6 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
size_t charsConverted;
PRINTER_INFO_2* prninfo = NULL;
DWORD needed, returned;
DEBUG_WINPR("");
/* find required size for the buffer */
EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
@ -227,19 +216,16 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
/* call again */
if ( !EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned) )
if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned))
{
DEBUG_WINPR("EnumPrinters failed");
} ; /* ERROR... */
DEBUG_WINPR("printers found: %d", returned);
}
printers = (rdpPrinter**) malloc(sizeof(rdpPrinter*) * (returned + 1));
ZeroMemory(printers, sizeof(rdpPrinter*) * (returned + 1));
printers = (rdpPrinter**) calloc((returned + 1), sizeof(rdpPrinter*));
num_printers = 0;
for (i = 0; i < (int)returned; i++)
for (i = 0; i < (int) returned; i++)
{
wcstombs_s(&charsConverted, pname, 1000, prninfo[i].pPrinterName, _TRUNCATE);
printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
@ -254,8 +240,6 @@ static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char*
{
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
rdpPrinter *myPrinter = NULL;
DEBUG_WINPR("printer %s", name);
myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? TRUE : FALSE);
@ -266,12 +250,9 @@ static rdpWinPrinterDriver* win_driver = NULL;
rdpPrinterDriver* printer_win_get_driver(void)
{
DEBUG_WINPR("");
if (win_driver == NULL)
if (!win_driver)
{
win_driver = (rdpWinPrinterDriver*) malloc(sizeof(rdpWinPrinterDriver));
ZeroMemory(win_driver, sizeof(rdpWinPrinterDriver));
win_driver = (rdpWinPrinterDriver*) calloc(1, sizeof(rdpWinPrinterDriver));
win_driver->driver.EnumPrinters = printer_win_enum_printers;
win_driver->driver.GetPrinter = printer_win_get_printer;

View File

@ -20,17 +20,20 @@
#ifndef __PRINTER_WIN_H
#define __PRINTER_WIN_H
#include <freerdp/channels/log.h>
rdpPrinterDriver* printer_win_get_driver(void);
#define PRINTER_TAG CHANNELS_TAG("printer.client")
#ifdef WITH_DEBUG_WINPR
#define DEBUG_WINPR(fmt, ...) DEBUG_CLASS(WINPR, fmt, ## __VA_ARGS__)
#define DEBUG_WINPR(fmt, ...) WLog_DBG(PRINTER_TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_WINPR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#define DEBUG_WINPR(fmt, ...) do { } while (0)
#endif
#endif
#ifdef WIN32
#define snprintf _snprintf
#endif
#endif

View File

@ -27,14 +27,9 @@ set(${MODULE_PREFIX}_SRCS
add_channel_client_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})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -23,238 +23,52 @@
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <freerdp/types.h>
#include <freerdp/constants.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/utils/rail.h>
#include <freerdp/rail.h>
#include "rail_orders.h"
#include "rail_main.h"
RailClientContext* rail_get_client_interface(void* railObject)
RailClientContext* rail_get_client_interface(railPlugin* rail)
{
RailClientContext* pInterface;
rdpSvcPlugin* plugin = (rdpSvcPlugin*) railObject;
pInterface = (RailClientContext*) plugin->channel_entry_points.pInterface;
pInterface = (RailClientContext*) rail->channelEntryPoints.pInterface;
return pInterface;
}
void rail_send_channel_data(void* railObject, void* data, size_t length)
int rail_send(railPlugin* rail, wStream* s)
{
UINT32 status = 0;
if (!rail)
{
status = CHANNEL_RC_BAD_INIT_HANDLE;
}
else
{
status = rail->channelEntryPoints.pVirtualChannelWrite(rail->OpenHandle,
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
}
if (status != CHANNEL_RC_OK)
{
Stream_Free(s, TRUE);
WLog_ERR(TAG, "rail_send: VirtualChannelWrite failed %d", status);
}
return status;
}
void rail_send_channel_data(railPlugin* rail, void* data, size_t length)
{
wStream* s = NULL;
railPlugin* plugin = (railPlugin*) railObject;
s = Stream_New(NULL, length);
Stream_Write(s, data, length);
svc_plugin_send((rdpSvcPlugin*) plugin, s);
}
static void on_free_rail_channel_event(wMessage* event)
{
rail_free_cloned_order(GetMessageType(event->id), event->wParam);
}
void rail_send_channel_event(void* railObject, UINT16 eventType, void* param)
{
void* payload = NULL;
wMessage* out_event = NULL;
railPlugin* plugin = (railPlugin*) railObject;
payload = rail_clone_order(eventType, param);
if (payload)
{
out_event = freerdp_event_new(RailChannel_Class, eventType,
on_free_rail_channel_event, payload);
svc_plugin_send_event((rdpSvcPlugin*) plugin, out_event);
}
}
static void rail_process_connect(rdpSvcPlugin* plugin)
{
railPlugin* rail = (railPlugin*) plugin;
rail->rail_order = rail_order_new();
rail->rail_order->settings = (rdpSettings*) plugin->channel_entry_points.pExtendedData;
rail->rail_order->plugin = rail;
WLog_Print(rail->log, WLOG_DEBUG, "Connect");
}
static void rail_process_terminate(rdpSvcPlugin* plugin)
{
railPlugin* rail = (railPlugin*) plugin;
WLog_Print(rail->log, WLOG_DEBUG, "Terminate");
}
static void rail_process_receive(rdpSvcPlugin* plugin, wStream* s)
{
railPlugin* rail = (railPlugin*) plugin;
rail_order_recv(rail, s);
Stream_Free(s, TRUE);
}
static void rail_process_addin_args(rdpRailOrder* railOrder, rdpSettings* settings)
{
char* exeOrFile;
exeOrFile = settings->RemoteApplicationProgram;
if (strlen(exeOrFile) >= 2)
{
if (strncmp(exeOrFile, "||", 2) != 0)
railOrder->exec.flags |= RAIL_EXEC_FLAG_FILE;
}
rail_string_to_unicode_string(settings->RemoteApplicationProgram, &railOrder->exec.exeOrFile);
rail_string_to_unicode_string(settings->ShellWorkingDirectory, &railOrder->exec.workingDir);
rail_string_to_unicode_string(settings->RemoteApplicationCmdLine, &railOrder->exec.arguments);
rail_send_client_exec_order((railPlugin*) railOrder->plugin, &railOrder->exec);
}
static void rail_recv_set_sysparams_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_SYSPARAM_ORDER* sysparam;
/* Send System Parameters */
sysparam = (RAIL_SYSPARAM_ORDER*) event->wParam;
memmove(&railOrder->sysparam, sysparam, sizeof(RAIL_SYSPARAM_ORDER));
rail_send_client_sysparams_order((railPlugin*) railOrder->plugin, &railOrder->sysparam);
/* execute */
railOrder->exec.flags = RAIL_EXEC_FLAG_EXPAND_ARGUMENTS;
rail_process_addin_args(railOrder, railOrder->settings);
}
static void rail_recv_exec_remote_app_event(rdpRailOrder* railOrder, wMessage* event)
{
/**
* TODO: replace event system by an API to allow the execution
* of multiple remote apps over the same connection. RAIL is
* always built-in, so clients can safely link to it.
*/
//rail_process_addin_args((railPlugin*) railOrder->plugin, data);
}
static void rail_recv_activate_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_ACTIVATE_ORDER* activate = (RAIL_ACTIVATE_ORDER*) event->wParam;
CopyMemory(&railOrder->activate, activate, sizeof(RAIL_ACTIVATE_ORDER));
rail_send_client_activate_order((railPlugin*) railOrder->plugin, &railOrder->activate);
}
static void rail_recv_sysmenu_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_SYSMENU_ORDER* sysmenu = (RAIL_SYSMENU_ORDER*) event->wParam;
CopyMemory(&railOrder->sysmenu, sysmenu, sizeof(RAIL_SYSMENU_ORDER));
rail_send_client_sysmenu_order((railPlugin*) railOrder->plugin, &railOrder->sysmenu);
}
static void rail_recv_syscommand_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_SYSCOMMAND_ORDER* syscommand = (RAIL_SYSCOMMAND_ORDER*) event->wParam;
CopyMemory(&railOrder->syscommand, syscommand, sizeof(RAIL_SYSCOMMAND_ORDER));
rail_send_client_syscommand_order((railPlugin*) railOrder->plugin, &railOrder->syscommand);
}
static void rail_recv_notify_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_NOTIFY_EVENT_ORDER* notify = (RAIL_NOTIFY_EVENT_ORDER*) event->wParam;
CopyMemory(&railOrder->notify_event, notify, sizeof(RAIL_NOTIFY_EVENT_ORDER));
rail_send_client_notify_event_order((railPlugin*) railOrder->plugin, &railOrder->notify_event);
}
static void rail_recv_window_move_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_WINDOW_MOVE_ORDER* window_move = (RAIL_WINDOW_MOVE_ORDER*) event->wParam;
CopyMemory(&railOrder->window_move, window_move, sizeof(RAIL_WINDOW_MOVE_ORDER));
rail_send_client_window_move_order((railPlugin*) railOrder->plugin, &railOrder->window_move);
}
static void rail_recv_app_req_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_GET_APPID_REQ_ORDER* get_appid_req = (RAIL_GET_APPID_REQ_ORDER*) event->wParam;
CopyMemory(&railOrder->get_appid_req, get_appid_req, sizeof(RAIL_GET_APPID_REQ_ORDER));
rail_send_client_get_appid_req_order((railPlugin*) railOrder->plugin, &railOrder->get_appid_req);
}
static void rail_recv_langbarinfo_event(rdpRailOrder* railOrder, wMessage* event)
{
RAIL_LANGBAR_INFO_ORDER* langbar_info = (RAIL_LANGBAR_INFO_ORDER*) event->wParam;
CopyMemory(&railOrder->langbar_info, langbar_info, sizeof(RAIL_LANGBAR_INFO_ORDER));
rail_send_client_langbar_info_order((railPlugin*) railOrder->plugin, &railOrder->langbar_info);
}
static void rail_process_event(rdpSvcPlugin* plugin, wMessage* event)
{
railPlugin* rail = NULL;
rail = (railPlugin*) plugin;
switch (GetMessageType(event->id))
{
case RailChannel_ClientSystemParam:
rail_recv_set_sysparams_event(rail->rail_order, event);
break;
case RailChannel_ClientExecute:
rail_recv_exec_remote_app_event(rail->rail_order, event);
break;
case RailChannel_ClientActivate:
rail_recv_activate_event(rail->rail_order, event);
break;
case RailChannel_ClientSystemMenu:
rail_recv_sysmenu_event(rail->rail_order, event);
break;
case RailChannel_ClientSystemCommand:
rail_recv_syscommand_event(rail->rail_order, event);
break;
case RailChannel_ClientNotifyEvent:
rail_recv_notify_event(rail->rail_order, event);
break;
case RailChannel_ClientWindowMove:
rail_recv_window_move_event(rail->rail_order, event);
break;
case RailChannel_ClientGetAppIdRequest:
rail_recv_app_req_event(rail->rail_order, event);
break;
case RailChannel_ClientLanguageBarInfo:
rail_recv_langbarinfo_event(rail->rail_order, event);
break;
default:
break;
}
freerdp_event_free(event);
rail_send(rail, s);
}
/**
@ -263,9 +77,8 @@ static void rail_process_event(rdpSvcPlugin* plugin, wMessage* event)
int rail_client_execute(RailClientContext* context, RAIL_EXEC_ORDER* exec)
{
railPlugin* rail = (railPlugin*) context->handle;
char* exeOrFile;
railPlugin* rail = (railPlugin*) context->handle;
exeOrFile = exec->RemoteApplicationProgram;
@ -498,6 +311,223 @@ int rail_server_get_appid_response(RailClientContext* context, RAIL_GET_APPID_RE
return 0; /* stub - should be registered by client */
}
/****************************************************************************************/
static wListDictionary* g_InitHandles;
static wListDictionary* g_OpenHandles;
void rail_add_init_handle_data(void* pInitHandle, void* pUserData)
{
if (!g_InitHandles)
g_InitHandles = ListDictionary_New(TRUE);
ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
}
void* rail_get_init_handle_data(void* pInitHandle)
{
void* pUserData = NULL;
pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
return pUserData;
}
void rail_remove_init_handle_data(void* pInitHandle)
{
ListDictionary_Remove(g_InitHandles, pInitHandle);
}
void rail_add_open_handle_data(DWORD openHandle, void* pUserData)
{
void* pOpenHandle = (void*) (size_t) openHandle;
if (!g_OpenHandles)
g_OpenHandles = ListDictionary_New(TRUE);
ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
}
void* rail_get_open_handle_data(DWORD openHandle)
{
void* pUserData = NULL;
void* pOpenHandle = (void*) (size_t) openHandle;
pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
return pUserData;
}
void rail_remove_open_handle_data(DWORD openHandle)
{
void* pOpenHandle = (void*) (size_t) openHandle;
ListDictionary_Remove(g_OpenHandles, pOpenHandle);
}
static void rail_virtual_channel_event_data_received(railPlugin* rail,
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
wStream* data_in;
if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
{
return;
}
if (dataFlags & CHANNEL_FLAG_FIRST)
{
if (rail->data_in)
Stream_Free(rail->data_in, TRUE);
rail->data_in = Stream_New(NULL, totalLength);
}
data_in = rail->data_in;
Stream_EnsureRemainingCapacity(data_in, (int) dataLength);
Stream_Write(data_in, pData, dataLength);
if (dataFlags & CHANNEL_FLAG_LAST)
{
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
{
WLog_ERR(TAG, "rail_plugin_process_received: read error");
}
rail->data_in = NULL;
Stream_SealLength(data_in);
Stream_SetPosition(data_in, 0);
MessageQueue_Post(rail->queue, NULL, 0, (void*) data_in, NULL);
}
}
static VOID VCAPITYPE rail_virtual_channel_open_event(DWORD openHandle, UINT event,
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
railPlugin* rail;
rail = (railPlugin*) rail_get_open_handle_data(openHandle);
if (!rail)
{
WLog_ERR(TAG, "rail_virtual_channel_open_event: error no match");
return;
}
switch (event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
rail_virtual_channel_event_data_received(rail, pData, dataLength, totalLength, dataFlags);
break;
case CHANNEL_EVENT_WRITE_COMPLETE:
Stream_Free((wStream*) pData, TRUE);
break;
}
}
static void* rail_virtual_channel_client_thread(void* arg)
{
wStream* data;
wMessage message;
railPlugin* rail = (railPlugin*) arg;
while (1)
{
if (!MessageQueue_Wait(rail->queue))
break;
if (MessageQueue_Peek(rail->queue, &message, TRUE))
{
if (message.id == WMQ_QUIT)
break;
if (message.id == 0)
{
data = (wStream*) message.wParam;
rail_order_recv(rail, data);
}
}
}
ExitThread(0);
return NULL;
}
static void rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength)
{
UINT32 status;
status = rail->channelEntryPoints.pVirtualChannelOpen(rail->InitHandle,
&rail->OpenHandle, rail->channelDef.name, rail_virtual_channel_open_event);
rail_add_open_handle_data(rail->OpenHandle, rail);
if (status != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "rail_virtual_channel_event_connected: open failed: status: %d", status);
return;
}
rail->queue = MessageQueue_New(NULL);
rail->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rail_virtual_channel_client_thread, (void*) rail, 0, NULL);
}
static void rail_virtual_channel_event_terminated(railPlugin* rail)
{
if (rail->queue)
{
MessageQueue_PostQuit(rail->queue, 0);
WaitForSingleObject(rail->thread, INFINITE);
MessageQueue_Free(rail->queue);
rail->queue = NULL;
CloseHandle(rail->thread);
rail->thread = NULL;
}
rail->channelEntryPoints.pVirtualChannelClose(rail->OpenHandle);
if (rail->data_in)
{
Stream_Free(rail->data_in, TRUE);
rail->data_in = NULL;
}
rail_remove_open_handle_data(rail->OpenHandle);
rail_remove_init_handle_data(rail->InitHandle);
free(rail->context);
free(rail);
}
static VOID VCAPITYPE rail_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
{
railPlugin* rail;
rail = (railPlugin*) rail_get_init_handle_data(pInitHandle);
if (!rail)
{
WLog_ERR(TAG, "rail_virtual_channel_init_event: error no match");
return;
}
switch (event)
{
case CHANNEL_EVENT_CONNECTED:
rail_virtual_channel_event_connected(rail, pData, dataLength);
break;
case CHANNEL_EVENT_DISCONNECTED:
break;
case CHANNEL_EVENT_TERMINATED:
rail_virtual_channel_event_terminated(rail);
break;
}
}
/* rail is always built-in */
#define VirtualChannelEntry rail_VirtualChannelEntry
@ -507,30 +537,25 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
RailClientContext* context;
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
rail = (railPlugin*) malloc(sizeof(railPlugin));
ZeroMemory(rail, sizeof(railPlugin));
rail = (railPlugin*) calloc(1, sizeof(railPlugin));
rail->plugin.channel_def.options =
rail->channelDef.options =
CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL;
strcpy(rail->plugin.channel_def.name, "rail");
rail->plugin.connect_callback = rail_process_connect;
rail->plugin.receive_callback = rail_process_receive;
rail->plugin.event_callback = rail_process_event;
rail->plugin.terminate_callback = rail_process_terminate;
strcpy(rail->channelDef.name, "rail");
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
{
context = (RailClientContext*) malloc(sizeof(RailClientContext));
context = (RailClientContext*) calloc(1, sizeof(RailClientContext));
context->handle = (void*) rail;
context->custom = NULL;
context->ClientExecute = rail_client_execute;
context->ClientActivate = rail_client_activate;
@ -554,6 +579,7 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
context->ServerGetAppIdResponse = rail_server_get_appid_response;
*(pEntryPointsEx->ppInterface) = (void*) context;
rail->context = context;
}
WLog_Init();
@ -561,7 +587,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntry");
svc_plugin_init((rdpSvcPlugin*) rail, pEntryPoints);
CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
rail->channelEntryPoints.pVirtualChannelInit(&rail->InitHandle,
&rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rail_virtual_channel_init_event);
rail->channelEntryPoints.pInterface = *(rail->channelEntryPoints.ppInterface);
rail->channelEntryPoints.ppInterface = &(rail->channelEntryPoints.pInterface);
rail_add_init_handle_data(rail->InitHandle, (void*) rail);
return 1;
}

View File

@ -23,9 +23,9 @@
#define FREERDP_CHANNEL_CLIENT_RAIL_MAIN_H
#include <freerdp/rail.h>
#include <freerdp/svc.h>
#include <freerdp/addin.h>
#include <freerdp/settings.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/client/rail.h>
#include <winpr/crt.h>
@ -36,16 +36,21 @@
struct rail_plugin
{
rdpSvcPlugin plugin;
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
RailClientContext* context;
wLog* log;
rdpRailOrder* rail_order;
HANDLE thread;
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;
wMessageQueue* queue;
};
typedef struct rail_plugin railPlugin;
RailClientContext* rail_get_client_interface(void* railObject);
void rail_send_channel_event(void* rail_object, UINT16 event_type, void* param);
void rail_send_channel_data(void* rail_object, void* data, size_t length);
RailClientContext* rail_get_client_interface(railPlugin* rail);
void rail_send_channel_data(railPlugin* rail, void* data, size_t length);
#endif /* FREERDP_CHANNEL_CLIENT_RAIL_MAIN_H */

View File

@ -22,15 +22,48 @@
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <winpr/crt.h>
#include <freerdp/utils/rail.h>
#include <freerdp/channels/log.h>
#include "rail_orders.h"
static BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
{
if (Stream_GetRemainingLength(s) < 2)
return FALSE;
Stream_Read_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
if (Stream_GetRemainingLength(s) < unicode_string->length)
return FALSE;
if (!unicode_string->string)
unicode_string->string = (BYTE*) malloc(unicode_string->length);
else
unicode_string->string = (BYTE*) realloc(unicode_string->string, unicode_string->length);
Stream_Read(s, unicode_string->string, unicode_string->length);
return TRUE;
}
static void rail_write_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
{
Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length);
Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
}
static void rail_write_unicode_string_value(wStream* s, RAIL_UNICODE_STRING* unicode_string)
{
if (unicode_string->length > 0)
{
Stream_EnsureRemainingCapacity(s, unicode_string->length);
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
}
}
void rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
{
UINT16 orderLength;
@ -275,8 +308,6 @@ void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarI
BOOL rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake, wStream* s)
{
RAIL_SYSPARAM_ORDER sysparam;
RAIL_CLIENT_STATUS_ORDER clientStatus;
RailClientContext* context = rail_get_client_interface(rail);
if (!rail_read_handshake_order(s, handshake))
@ -288,44 +319,6 @@ BOOL rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake
return TRUE;
}
handshake->buildNumber = 0x00001DB0;
rail_send_handshake_order(rail, handshake);
ZeroMemory(&clientStatus, sizeof(RAIL_CLIENT_STATUS_ORDER));
clientStatus.flags = RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE;
rail_send_client_status_order(rail, &clientStatus);
/* sysparam update */
ZeroMemory(&sysparam, sizeof(RAIL_SYSPARAM_ORDER));
sysparam.params = 0;
sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST;
sysparam.highContrast.colorScheme.string = NULL;
sysparam.highContrast.colorScheme.length = 0;
sysparam.highContrast.flags = 0x7E;
sysparam.params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
sysparam.mouseButtonSwap = FALSE;
sysparam.params |= SPI_MASK_SET_KEYBOARD_PREF;
sysparam.keyboardPref = FALSE;
sysparam.params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
sysparam.dragFullWindows = FALSE;
sysparam.params |= SPI_MASK_SET_KEYBOARD_CUES;
sysparam.keyboardCues = FALSE;
sysparam.params |= SPI_MASK_SET_WORK_AREA;
sysparam.workArea.left = 0;
sysparam.workArea.top = 0;
sysparam.workArea.right = 1024;
sysparam.workArea.bottom = 768;
rail_send_channel_event(rail, RailChannel_GetSystemParam, &sysparam);
return TRUE;
}
@ -357,10 +350,6 @@ BOOL rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER* execR
{
IFCALL(context->ServerExecuteResult, context, execResult);
}
else
{
rail_send_channel_event(rail, RailChannel_ServerExecuteResult, execResult);
}
return TRUE;
}
@ -376,10 +365,6 @@ BOOL rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysp
{
IFCALL(context->ServerSystemParam, context, sysparam);
}
else
{
rail_send_channel_event(rail, RailChannel_ServerSystemParam, sysparam);
}
return TRUE;
}
@ -395,10 +380,6 @@ BOOL rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ORDER*
{
IFCALL(context->ServerMinMaxInfo, context, minMaxInfo);
}
else
{
rail_send_channel_event(rail, RailChannel_ServerMinMaxInfo, minMaxInfo);
}
return TRUE;
}
@ -414,10 +395,6 @@ BOOL rail_recv_server_localmovesize_order(railPlugin* rail, RAIL_LOCALMOVESIZE_O
{
IFCALL(context->ServerLocalMoveSize, context, localMoveSize);
}
else
{
rail_send_channel_event(rail, RailChannel_ServerLocalMoveSize, localMoveSize);
}
return TRUE;
}
@ -433,10 +410,6 @@ BOOL rail_recv_server_get_appid_resp_order(railPlugin* rail, RAIL_GET_APPID_RESP
{
IFCALL(context->ServerGetAppIdResponse, context, getAppIdResp);
}
else
{
rail_send_channel_event(rail, RailChannel_ServerGetAppIdResponse, getAppIdResp);
}
return TRUE;
}
@ -452,10 +425,6 @@ BOOL rail_recv_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* lan
{
IFCALL(context->ServerLanguageBarInfo, context, langBarInfo);
}
else
{
rail_send_channel_event(rail, RailChannel_ServerLanguageBarInfo, langBarInfo);
}
return TRUE;
}
@ -522,7 +491,7 @@ BOOL rail_order_recv(railPlugin* rail, wStream* s)
}
default:
fprintf(stderr, "Unknown RAIL PDU order reveived.");
WLog_ERR(TAG, "Unknown RAIL PDU order reveived.");
break;
}
@ -712,25 +681,3 @@ void rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORD
rail_send_pdu(rail, s, RDP_RAIL_ORDER_LANGBARINFO);
Stream_Free(s, TRUE);
}
rdpRailOrder* rail_order_new()
{
rdpRailOrder* railOrder;
railOrder = (rdpRailOrder*) malloc(sizeof(rdpRailOrder));
if (railOrder)
{
ZeroMemory(railOrder, sizeof(rdpRailOrder));
}
return railOrder;
}
void rail_order_free(rdpRailOrder* railOrder)
{
if (railOrder)
{
free(railOrder);
}
}

View File

@ -21,8 +21,12 @@
#ifndef __RAIL_ORDERS_H
#define __RAIL_ORDERS_H
#include <freerdp/channels/log.h>
#include "rail_main.h"
#define TAG CHANNELS_TAG("rail.client")
BOOL rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* exec_result);
BOOL rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam);
BOOL rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo);
@ -42,7 +46,6 @@ void rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER*
void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbar_info);
BOOL rail_order_recv(railPlugin* rail, wStream* s);
void rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType);
void rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake);
@ -59,7 +62,4 @@ void rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER
void rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_ORDER* getAppIdReq);
void rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo);
rdpRailOrder* rail_order_new(void);
void rail_order_free(rdpRailOrder* railOrder);
#endif /* __RAIL_ORDERS_H */

View File

@ -29,41 +29,18 @@ extern const char* const RAIL_ORDER_TYPE_STRINGS[];
#define RAIL_PDU_HEADER_LENGTH 4
/* Fixed length of PDUs, excluding variable lengths */
#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
struct rdp_rail_order
{
rdpSettings* settings;
void* plugin;
RAIL_HANDSHAKE_ORDER handshake;
RAIL_CLIENT_STATUS_ORDER client_status;
RAIL_EXEC_ORDER exec;
RAIL_EXEC_RESULT_ORDER exec_result;
RAIL_SYSPARAM_ORDER sysparam;
RAIL_ACTIVATE_ORDER activate;
RAIL_SYSMENU_ORDER sysmenu;
RAIL_SYSCOMMAND_ORDER syscommand;
RAIL_NOTIFY_EVENT_ORDER notify_event;
RAIL_MINMAXINFO_ORDER minmaxinfo;
RAIL_LOCALMOVESIZE_ORDER localmovesize;
RAIL_WINDOW_MOVE_ORDER window_move;
RAIL_LANGBAR_INFO_ORDER langbar_info;
RAIL_GET_APPID_REQ_ORDER get_appid_req;
RAIL_GET_APPID_RESP_ORDER get_appid_resp;
};
typedef struct rdp_rail_order rdpRailOrder;
#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_string);
BOOL rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake);

View File

@ -29,19 +29,9 @@ set(${MODULE_PREFIX}_SRCS
add_channel_client_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)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-synch winpr-thread winpr-interlocked)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} winpr freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -32,6 +32,7 @@
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/client/channels.h>
#include <freerdp/channels/log.h>
#include "rdpdr_main.h"
@ -122,7 +123,7 @@ BOOL devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device)
if (!ServiceName)
return FALSE;
fprintf(stderr, "Loading device service %s (static)\n", ServiceName);
WLog_INFO(TAG, "Loading device service %s (static)", ServiceName);
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0);
if (!entry)

View File

@ -75,6 +75,10 @@ IRP* irp_new(DEVMAN* devman, wStream* s)
return NULL;
irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
if (!irp)
return NULL;
ZeroMemory(irp, sizeof(IRP));
irp->input = s;

View File

@ -31,6 +31,7 @@
#include <freerdp/types.h>
#include <freerdp/constants.h>
#include <freerdp/channels/log.h>
#include <freerdp/channels/rdpdr.h>
#ifdef _WIN32
@ -451,7 +452,7 @@ static void* drive_hotplug_thread_func(void* arg)
if (mfd < 0)
{
fprintf(stderr, "ERROR: Unable to open /proc/mounts.");
WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts.");
return NULL;
}
@ -460,6 +461,8 @@ static void* drive_hotplug_thread_func(void* arg)
tv.tv_sec = 1;
tv.tv_usec = 0;
handle_hotplug(rdpdr);
while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
{
if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0)
@ -503,8 +506,10 @@ static void rdpdr_process_connect(rdpdrPlugin* rdpdr)
rdpdr->devman = devman_new(rdpdr);
settings = (rdpSettings*) rdpdr->channelEntryPoints.pExtendedData;
strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1);
if (settings->ClientHostname)
strncpy(rdpdr->computerName, settings->ClientHostname, sizeof(rdpdr->computerName) - 1);
else
strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1);
for (index = 0; index < settings->DeviceCount; index++)
{
@ -536,8 +541,8 @@ static void rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
s = Stream_New(NULL, 12);
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM);
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */
Stream_Write_UINT16(s, rdpdr->versionMajor);
Stream_Write_UINT16(s, rdpdr->versionMinor);
@ -559,8 +564,8 @@ static void rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
s = Stream_New(NULL, 16 + computerNameLenW + 2);
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME);
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); /* PacketId (2 bytes) */
Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */
@ -611,8 +616,8 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
s = Stream_New(NULL, 256);
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE);
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */
count_pos = (int) Stream_GetPosition(s);
count = 0;
@ -659,9 +664,8 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
Stream_Write(s, Stream_Buffer(device->data), data_len);
count++;
fprintf(stderr, "registered device #%d: %s (type=%d id=%d)\n",
count, device->name, device->type, device->id);
WLog_INFO(TAG, "registered device #%d: %s (type=%d id=%d)",
count, device->name, device->type, device->id);
}
}
@ -714,16 +718,16 @@ static void rdpdr_process_init(rdpdrPlugin* rdpdr)
static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 component;
UINT16 packetID;
UINT32 deviceID;
UINT16 packetId;
UINT32 deviceId;
UINT32 status;
Stream_Read_UINT16(s, component);
Stream_Read_UINT16(s, packetID);
Stream_Read_UINT16(s, component); /* Component (2 bytes) */
Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
if (component == RDPDR_CTYP_CORE)
{
switch (packetID)
switch (packetId)
{
case PAKID_CORE_SERVER_ANNOUNCE:
rdpdr_process_server_announce_request(rdpdr, s);
@ -748,7 +752,7 @@ static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
case PAKID_CORE_DEVICE_REPLY:
/* connect to a specific resource */
Stream_Read_UINT32(s, deviceID);
Stream_Read_UINT32(s, deviceId);
Stream_Read_UINT32(s, status);
break;
@ -758,17 +762,19 @@ static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
break;
default:
WLog_ERR(TAG, "rdpdr_process_receive: RDPDR_CTYP_CORE unknown PacketId: 0x%04X", packetId);
break;
}
}
else if (component == RDPDR_CTYP_PRN)
{
WLog_ERR(TAG, "rdpdr_process_receive: RDPDR_CTYP_PRN unknown PacketId: 0x%04X", packetId);
}
else
{
WLog_ERR(TAG, "rdpdr_process_receive: unknown message: Component: 0x%04X PacketId: 0x%04X",
component, packetId);
}
Stream_Free(s, TRUE);
@ -843,7 +849,7 @@ int rdpdr_send(rdpdrPlugin* rdpdr, wStream* s)
if (status != CHANNEL_RC_OK)
{
Stream_Free(s, TRUE);
fprintf(stderr, "rdpdr_send: VirtualChannelWrite failed %d\n", status);
WLog_ERR(TAG, "rdpdr_send: VirtualChannelWrite failed %d", status);
}
return status;
@ -867,7 +873,7 @@ static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr,
if (dataFlags & CHANNEL_FLAG_FIRST)
{
if (rdpdr->data_in != NULL)
if (rdpdr->data_in)
Stream_Free(rdpdr->data_in, TRUE);
rdpdr->data_in = Stream_New(NULL, totalLength);
@ -881,14 +887,14 @@ static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr,
{
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
{
fprintf(stderr, "svc_plugin_process_received: read error\n");
WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received: read error\n");
}
rdpdr->data_in = NULL;
Stream_SealLength(data_in);
Stream_SetPosition(data_in, 0);
MessageQueue_Post(rdpdr->MsgPipe->In, NULL, 0, (void*) data_in, NULL);
MessageQueue_Post(rdpdr->queue, NULL, 0, (void*) data_in, NULL);
}
}
@ -901,7 +907,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev
if (!rdpdr)
{
fprintf(stderr, "rdpdr_virtual_channel_open_event: error no match\n");
WLog_ERR(TAG, "rdpdr_virtual_channel_open_event: error no match\n");
return;
}
@ -914,9 +920,6 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev
case CHANNEL_EVENT_WRITE_COMPLETE:
Stream_Free((wStream*) pData, TRUE);
break;
case CHANNEL_EVENT_USER:
break;
}
}
@ -930,10 +933,10 @@ static void* rdpdr_virtual_channel_client_thread(void* arg)
while (1)
{
if (!MessageQueue_Wait(rdpdr->MsgPipe->In))
if (!MessageQueue_Wait(rdpdr->queue))
break;
if (MessageQueue_Peek(rdpdr->MsgPipe->In, &message, TRUE))
if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
{
if (message.id == WMQ_QUIT)
break;
@ -961,11 +964,11 @@ static void rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa
if (status != CHANNEL_RC_OK)
{
fprintf(stderr, "rdpdr_virtual_channel_event_connected: open failed: status: %d\n", status);
WLog_ERR(TAG, "rdpdr_virtual_channel_event_connected: open failed: status: %d\n", status);
return;
}
rdpdr->MsgPipe = MessagePipe_New();
rdpdr->queue = MessageQueue_New(NULL);
rdpdr->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, NULL);
@ -973,11 +976,17 @@ static void rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa
static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
{
MessagePipe_PostQuit(rdpdr->MsgPipe, 0);
WaitForSingleObject(rdpdr->thread, INFINITE);
if (rdpdr->queue)
{
MessageQueue_PostQuit(rdpdr->queue, 0);
WaitForSingleObject(rdpdr->thread, INFINITE);
MessagePipe_Free(rdpdr->MsgPipe);
CloseHandle(rdpdr->thread);
MessageQueue_Free(rdpdr->queue);
rdpdr->queue = NULL;
CloseHandle(rdpdr->thread);
rdpdr->thread = NULL;
}
drive_hotplug_thread_terminate(rdpdr);
@ -997,6 +1006,8 @@ static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
rdpdr_remove_open_handle_data(rdpdr->OpenHandle);
rdpdr_remove_init_handle_data(rdpdr->InitHandle);
free(rdpdr);
}
static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
@ -1007,7 +1018,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT
if (!rdpdr)
{
fprintf(stderr, "rdpdr_virtual_channel_init_event: error no match\n");
WLog_ERR(TAG, "rdpdr_virtual_channel_init_event: error no match");
return;
}

View File

@ -32,6 +32,9 @@
#include <freerdp/addin.h>
#include <freerdp/channels/rdpdr.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("rdpdr.client")
typedef struct rdpdr_plugin rdpdrPlugin;
@ -44,7 +47,7 @@ struct rdpdr_plugin
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;
wMessagePipe* MsgPipe;
wMessageQueue* queue;
DEVMAN* devman;

View File

@ -23,14 +23,9 @@ set(${MODULE_PREFIX}_SRCS
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})
target_link_libraries(${MODULE_NAME} freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -25,8 +25,11 @@
#include <winpr/print.h>
#include <winpr/stream.h>
#include <freerdp/channels/log.h>
#include "rdpdr_main.h"
#define TAG "rdpdr.server"
static UINT32 g_ClientId = 0;
static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
@ -34,27 +37,19 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
wStream* s;
BOOL status;
RDPDR_HEADER header;
printf("RdpdrServerSendAnnounceRequest\n");
ULONG written;
WLog_DBG(TAG, "RdpdrServerSendAnnounceRequest");
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);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
Stream_Free(s, TRUE);
return 0;
}
@ -63,16 +58,12 @@ static int rdpdr_server_receive_announce_response(RdpdrServerContext* context, w
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);
WLog_DBG(TAG, "Client Announce Response: VersionMajor: 0x%04X VersionMinor: 0x%04X ClientId: 0x%04X",
VersionMajor, VersionMinor, ClientId);
context->priv->ClientId = ClientId;
return 0;
}
@ -80,7 +71,6 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context,
{
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) */
@ -99,7 +89,7 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context,
if (UnicodeFlag)
{
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
-1, &(context->priv->ClientComputerName), 0, NULL, NULL);
-1, &(context->priv->ClientComputerName), 0, NULL, NULL);
}
else
{
@ -107,9 +97,7 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context,
}
Stream_Seek(s, ComputerNameLen);
printf("ClientComputerName: %s\n", context->priv->ClientComputerName);
WLog_DBG(TAG, "ClientComputerName: %s", context->priv->ClientComputerName);
return 0;
}
@ -137,7 +125,6 @@ static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context,
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) */
@ -148,9 +135,7 @@ static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context,
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;
}
@ -161,11 +146,9 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
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 */
@ -183,7 +166,6 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
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 */
@ -193,12 +175,9 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
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) */
@ -209,7 +188,6 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
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;
}
@ -221,14 +199,11 @@ static int rdpdr_server_read_printer_capability_set(RdpdrServerContext* context,
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;
}
@ -240,14 +215,11 @@ static int rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wS
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;
}
@ -259,14 +231,11 @@ static int rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, w
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;
}
@ -278,14 +247,11 @@ static int rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* contex
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;
}
@ -295,34 +261,24 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
BOOL status;
RDPDR_HEADER header;
UINT16 numCapabilities;
printf("RdpdrServerSendCoreCapabilityRequest\n");
ULONG written;
WLog_DBG(TAG, "RdpdrServerSendCoreCapabilityRequest");
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);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
Stream_Free(s, TRUE);
return 0;
}
@ -331,7 +287,6 @@ static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* con
int i;
UINT16 numCapabilities;
RDPDR_CAPABILITY_HEADER capabilityHeader;
Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
Stream_Seek_UINT16(s); /* Padding (2 bytes) */
@ -362,7 +317,7 @@ static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* con
break;
default:
printf("Unknown capabilityType %d\n", capabilityHeader.CapabilityType);
WLog_DBG(TAG, "Unknown capabilityType %d", capabilityHeader.CapabilityType);
Stream_Seek(s, capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH);
break;
}
@ -376,27 +331,19 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
wStream* s;
BOOL status;
RDPDR_HEADER header;
printf("RdpdrServerSendClientIdConfirm\n");
ULONG written;
WLog_DBG(TAG, "RdpdrServerSendClientIdConfirm");
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);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
Stream_Free(s, TRUE);
return 0;
}
@ -408,12 +355,9 @@ static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext*
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);
WLog_DBG(TAG, "DeviceCount: %d", DeviceCount);
for (i = 0; i < DeviceCount; i++)
{
@ -421,9 +365,8 @@ static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext*
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);
WLog_DBG(TAG, "Device %d Name: %s Id: 0x%04X DataLength: %d",
i, PreferredDosName, DeviceId, DeviceDataLength);
switch (DeviceId)
{
@ -457,32 +400,24 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
wStream* s;
BOOL status;
RDPDR_HEADER header;
printf("%s\n", __FUNCTION__);
ULONG written;
WLog_DBG(TAG, "%s");
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);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
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));
WLog_DBG(TAG, "RdpdrServerReceivePdu: Component: 0x%04X PacketId: 0x%04X",
header->Component, header->PacketId);
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s));
if (header->Component == RDPDR_CTYP_CORE)
{
@ -503,6 +438,7 @@ static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDP
if (context->priv->UserLoggedOnPdu)
rdpdr_server_send_user_logged_on(context);
break;
case PAKID_CORE_DEVICELIST_ANNOUNCE:
@ -541,7 +477,7 @@ static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDP
}
else
{
printf("Unknown RDPDR_HEADER.Component: 0x%04X\n", header->Component);
WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: 0x%04X", header->Component);
return -1;
}
@ -560,13 +496,10 @@ static void* rdpdr_server_thread(void* arg)
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)
@ -580,13 +513,11 @@ static void* rdpdr_server_thread(void* arg)
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)
@ -594,37 +525,34 @@ static void* rdpdr_server_thread(void* arg)
break;
}
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Pointer(s),
Stream_Capacity(s) - Stream_GetPosition(s), &BytesReturned))
WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned);
if (BytesReturned < 1)
continue;
Stream_EnsureRemainingCapacity(s, BytesReturned);
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);
break;
}
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;
}
@ -636,48 +564,38 @@ static int rdpdr_server_start(RdpdrServerContext* context)
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);
(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(HANDLE 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;
}
}

View File

@ -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()

View File

@ -20,26 +20,15 @@ define_channel_client("rdpei")
set(${MODULE_PREFIX}_SRCS
rdpei_main.c
rdpei_main.h
rdpei_common.c
rdpei_common.h)
../rdpei_common.c
../rdpei_common.h)
include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-sysinfo)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} winpr freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -88,6 +88,8 @@ struct _RDPEI_PLUGIN
IWTSListener* listener;
RDPEI_LISTENER_CALLBACK* listener_callback;
RdpeiClientContext* context;
int version;
UINT16 maxTouchContacts;
UINT64 currentFrameTime;
@ -201,8 +203,8 @@ int rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, UINT16 eventId,
status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL);
#ifdef WITH_DEBUG_RDPEI
fprintf(stderr, "rdpei_send_pdu: eventId: %d (%s) length: %d status: %d\n",
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status);
WLog_DBG(TAG, "rdpei_send_pdu: eventId: %d (%s) length: %d status: %d",
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status);
#endif
return status;
@ -239,17 +241,22 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback)
void rdpei_print_contact_flags(UINT32 contactFlags)
{
if (contactFlags & CONTACT_FLAG_DOWN)
printf(" CONTACT_FLAG_DOWN");
WLog_DBG(TAG, " CONTACT_FLAG_DOWN");
if (contactFlags & CONTACT_FLAG_UPDATE)
printf(" CONTACT_FLAG_UPDATE");
WLog_DBG(TAG, " CONTACT_FLAG_UPDATE");
if (contactFlags & CONTACT_FLAG_UP)
printf(" CONTACT_FLAG_UP");
WLog_DBG(TAG, " CONTACT_FLAG_UP");
if (contactFlags & CONTACT_FLAG_INRANGE)
printf(" CONTACT_FLAG_INRANGE");
WLog_DBG(TAG, " CONTACT_FLAG_INRANGE");
if (contactFlags & CONTACT_FLAG_INCONTACT)
printf(" CONTACT_FLAG_INCONTACT");
WLog_DBG(TAG, " CONTACT_FLAG_INCONTACT");
if (contactFlags & CONTACT_FLAG_CANCELED)
printf(" CONTACT_FLAG_CANCELED");
WLog_DBG(TAG, " CONTACT_FLAG_CANCELED");
}
int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
@ -259,8 +266,8 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
RDPINPUT_CONTACT_DATA* contact;
#ifdef WITH_DEBUG_RDPEI
printf("contactCount: %d\n", frame->contactCount);
printf("frameOffset: 0x%08X\n", (UINT32) frame->frameOffset);
WLog_DBG(TAG, "contactCount: %d", frame->contactCount);
WLog_DBG(TAG, "frameOffset: 0x%08X", (UINT32) frame->frameOffset);
#endif
rdpei_write_2byte_unsigned(s, frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */
@ -284,13 +291,12 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
contact->contactRectBottom = contact->y + rectSize;
#ifdef WITH_DEBUG_RDPEI
printf("contact[%d].contactId: %d\n", index, contact->contactId);
printf("contact[%d].fieldsPresent: %d\n", index, contact->fieldsPresent);
printf("contact[%d].x: %d\n", index, contact->x);
printf("contact[%d].y: %d\n", index, contact->y);
printf("contact[%d].contactFlags: 0x%04X", index, contact->contactFlags);
WLog_DBG(TAG, "contact[%d].contactId: %d", index, contact->contactId);
WLog_DBG(TAG, "contact[%d].fieldsPresent: %d", index, contact->fieldsPresent);
WLog_DBG(TAG, "contact[%d].x: %d", index, contact->x);
WLog_DBG(TAG, "contact[%d].y: %d", index, contact->y);
WLog_DBG(TAG, "contact[%d].contactFlags: 0x%04X", index, contact->contactFlags);
rdpei_print_contact_flags(contact->contactFlags);
printf("\n");
#endif
Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */
@ -371,7 +377,7 @@ int rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
#if 0
if (protocolVersion != RDPINPUT_PROTOCOL_V10)
{
fprintf(stderr, "Unknown [MS-RDPEI] protocolVersion: 0x%08X\n", protocolVersion);
WLog_ERR(TAG, "Unknown [MS-RDPEI] protocolVersion: 0x%08X", protocolVersion);
return -1;
}
#endif
@ -408,8 +414,8 @@ int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */
#ifdef WITH_DEBUG_RDPEI
fprintf(stderr, "rdpei_recv_pdu: eventId: %d (%s) length: %d\n",
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength);
WLog_DBG(TAG, "rdpei_recv_pdu: eventId: %d (%s) length: %d",
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength);
#endif
switch (eventId)
@ -434,17 +440,12 @@ int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
return 0;
}
static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
{
wStream* s;
int status = 0;
RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback;
s = Stream_New(pBuffer, cbSize);
status = rdpei_recv_pdu(callback, s);
Stream_Free(s, FALSE);
status = rdpei_recv_pdu(callback, data);
return status;
}
@ -535,6 +536,8 @@ static int rdpei_plugin_terminated(IWTSPlugin* pPlugin)
if (rdpei->listener_callback)
free(rdpei->listener_callback);
free(rdpei->context);
free(rdpei);
return 0;
@ -744,7 +747,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
rdpei = (RDPEI_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "rdpei");
if (rdpei == NULL)
if (!rdpei)
{
size_t size;
@ -779,6 +782,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
rdpei->iface.pInterface = (void*) context;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", (IWTSPlugin*) rdpei);
rdpei->context = context;
}
return error;

View File

@ -27,30 +27,12 @@
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/utils/debug.h>
#include <freerdp/channels/log.h>
#include <freerdp/channels/rdpei.h>
#include <freerdp/client/rdpei.h>
#define RDPINPUT_HEADER_LENGTH 6
/* Protocol Version */
#define RDPINPUT_PROTOCOL_V10 0x00010000
#define RDPINPUT_PROTOCOL_V101 0x00010001
/* Client Ready Flags */
#define READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001
#define READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002
/* Input Event Ids */
#define EVENTID_SC_READY 0x0001
#define EVENTID_CS_READY 0x0002
#define EVENTID_TOUCH 0x0003
#define EVENTID_SUSPEND_TOUCH 0x0004
#define EVENTID_RESUME_TOUCH 0x0005
#define EVENTID_DISMISS_HOVERING_CONTACT 0x0006
#define TAG CHANNELS_TAG("rdpei.client")
#define RDPINPUT_CONTACT_STATE_INITIAL 0x0000
#define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001
@ -100,9 +82,9 @@ struct _RDPINPUT_CONTACT_POINT
typedef struct _RDPINPUT_CONTACT_POINT RDPINPUT_CONTACT_POINT;
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
#define DEBUG_DVC(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
#else
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#define DEBUG_DVC(fmt, ...) do { } while (0)
#endif
#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_MAIN_H */

View File

@ -3,6 +3,7 @@
* Input Virtual Channel Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -587,3 +588,23 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value)
return TRUE;
}
void touch_event_reset(RDPINPUT_TOUCH_EVENT *event)
{
int i;
for (i = 0; i < event->frameCount; i++)
touch_frame_reset(&event->frames[i]);
free(event->frames);
event->frames = NULL;
event->frameCount = 0;
}
void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame)
{
free(frame->contacts);
frame->contacts = NULL;
frame->contactCount = 0;
}

View File

@ -3,6 +3,7 @@
* Input Virtual Channel Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +18,22 @@
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H
#define FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H
#ifndef FREERDP_CHANNEL_RDPEI_COMMON_H
#define FREERDP_CHANNEL_RDPEI_COMMON_H
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <freerdp/channels/rdpei.h>
/** @brief input event ids */
enum {
EVENTID_SC_READY = 0x0001,
EVENTID_CS_READY = 0x0002,
EVENTID_TOUCH = 0x0003,
EVENTID_SUSPEND_TOUCH = 0x0004,
EVENTID_RESUME_TOUCH = 0x0005,
EVENTID_DISMISS_HOVERING_CONTACT = 0x0006
};
BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value);
BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value);
@ -34,5 +46,8 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value);
BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value);
BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value);
#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H */
void touch_event_reset(RDPINPUT_TOUCH_EVENT *event);
void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame);
#endif /* FREERDP_CHANNEL_RDPEI_COMMON_H */

View File

@ -0,0 +1,38 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2014 Thincast Technologies Gmbh.
# Copyright 2014 David FORT <contact@hardening-consulting.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("rdpei")
set(${MODULE_PREFIX}_SRCS
rdpei_main.c
rdpei_main.h
../rdpei_common.c
../rdpei_common.h
)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

@ -0,0 +1,464 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Extended Input channel server-side implementation
*
* Copyright 2014 Thincast Technologies Gmbh.
* Copyright 2014 David FORT <contact@hardening-consulting.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 "rdpei_main.h"
#include "../rdpei_common.h"
#include <freerdp/channels/rdpei.h>
#include <freerdp/server/rdpei.h>
/** @brief */
enum RdpEiState {
STATE_INITIAL,
STATE_WAITING_CLIENT_READY,
STATE_WAITING_FRAME,
STATE_SUSPENDED,
};
struct _rdpei_server_private
{
HANDLE channelHandle;
HANDLE eventHandle;
UINT32 expectedBytes;
BOOL waitingHeaders;
wStream *inputStream;
wStream *outputStream;
UINT16 currentMsgType;
RDPINPUT_TOUCH_EVENT touchEvent;
enum RdpEiState automataState;
};
RdpeiServerContext* rdpei_server_context_new(HANDLE vcm)
{
RdpeiServerContext *ret = calloc(1, sizeof(*ret));
RdpeiServerPrivate *priv;
if (!ret)
return NULL;
ret->priv = priv = calloc(1, sizeof(*ret->priv));
if (!priv)
goto out_free;
priv->inputStream = Stream_New(NULL, 256);
if (!priv->inputStream)
goto out_free_priv;
priv->outputStream = Stream_New(NULL, 200);
if (!priv->inputStream)
goto out_free_input_stream;
ret->vcm = vcm;
rdpei_server_context_reset(ret);
return ret;
out_free_input_stream:
Stream_Free(priv->inputStream, TRUE);
out_free_priv:
free(ret->priv);
out_free:
free(ret);
return NULL;
}
int rdpei_server_init(RdpeiServerContext *context)
{
void *buffer = NULL;
DWORD bytesReturned;
RdpeiServerPrivate *priv = context->priv;
priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
if (!priv->channelHandle)
{
fprintf(stderr, "%s: unable to open channel\n", __FUNCTION__);
return -1;
}
if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE)))
{
fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n",
__FUNCTION__, bytesReturned);
if (buffer)
WTSFreeMemory(buffer);
goto out_close;
}
CopyMemory(&priv->eventHandle, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
return 0;
out_close:
WTSVirtualChannelClose(priv->channelHandle);
return -1;
}
void rdpei_server_context_reset(RdpeiServerContext *context)
{
RdpeiServerPrivate *priv = context->priv;
priv->channelHandle = INVALID_HANDLE_VALUE;
priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
priv->waitingHeaders = TRUE;
priv->automataState = STATE_INITIAL;
Stream_SetPosition(priv->inputStream, 0);
}
void rdpei_server_context_free(RdpeiServerContext* context)
{
RdpeiServerPrivate *priv = context->priv;
if (priv->channelHandle != INVALID_HANDLE_VALUE)
WTSVirtualChannelClose(priv->channelHandle);
Stream_Free(priv->inputStream, TRUE);
free(priv);
free(context);
}
HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context)
{
return context->priv->eventHandle;
}
static int read_cs_ready_message(RdpeiServerContext *context, wStream *s)
{
if (Stream_GetRemainingLength(s) < 10)
return -1;
Stream_Read_UINT32(s, context->protocolFlags);
Stream_Read_UINT32(s, context->clientVersion);
Stream_Read_UINT16(s, context->maxTouchPoints);
switch (context->clientVersion)
{
case RDPINPUT_PROTOCOL_V10:
case RDPINPUT_PROTOCOL_V101:
break;
default:
fprintf(stderr, "%s: unhandled RPDEI protocol version 0x%x\n", __FUNCTION__, context->clientVersion);
break;
}
if (context->onClientReady)
context->onClientReady(context);
return 0;
}
static int read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDPINPUT_CONTACT_DATA *contactData)
{
if (Stream_GetRemainingLength(s) < 1)
return -1;
Stream_Read_UINT8(s, contactData->contactId);
if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
!rdpei_read_4byte_signed(s, &contactData->x) ||
!rdpei_read_4byte_signed(s, &contactData->y) ||
!rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
return -1;
if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
{
if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) ||
!rdpei_read_2byte_signed(s, &contactData->contactRectTop) ||
!rdpei_read_2byte_signed(s, &contactData->contactRectRight) ||
!rdpei_read_2byte_signed(s, &contactData->contactRectBottom))
return -1;
}
if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) &&
!rdpei_read_4byte_unsigned(s, &contactData->orientation))
return -1;
if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) &&
!rdpei_read_4byte_unsigned(s, &contactData->pressure))
return -1;
return 0;
}
static int read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_TOUCH_FRAME *frame)
{
int i;
RDPINPUT_CONTACT_DATA *contact;
if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) || !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
return -1;
frame->contacts = contact = calloc(frame->contactCount, sizeof(RDPINPUT_CONTACT_DATA));
if (!frame->contacts)
return -1;
for (i = 0; i < frame->contactCount; i++, contact++)
{
if (read_touch_contact_data(context, s, contact) < 0)
{
frame->contactCount = i;
goto out_cleanup;
}
}
return 0;
out_cleanup:
touch_frame_reset(frame);
return -1;
}
static int read_touch_event(RdpeiServerContext *context, wStream *s)
{
UINT32 frameCount;
int i, ret;
RDPINPUT_TOUCH_EVENT *event = &context->priv->touchEvent;
RDPINPUT_TOUCH_FRAME *frame;
ret = -1;
if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) || !rdpei_read_2byte_unsigned(s, &frameCount))
return -1;
event->frameCount = frameCount;
event->frames = frame = calloc(event->frameCount, sizeof(RDPINPUT_TOUCH_FRAME));
if (!event->frames)
return -1;
for (i = 0; i < frameCount; i++, frame++)
{
if (read_touch_frame(context, s, frame) < 0)
{
event->frameCount = i;
goto out_cleanup;
}
}
if (context->onTouchEvent)
context->onTouchEvent(context, event);
ret = 0;
out_cleanup:
touch_event_reset(event);
return ret;
}
static int read_dismiss_hovering_contact(RdpeiServerContext *context, wStream *s) {
BYTE contactId;
if (Stream_GetRemainingLength(s) < 1)
return -1;
Stream_Read_UINT8(s, contactId);
if (context->onTouchReleased)
context->onTouchReleased(context, contactId);
return 0;
}
int rdpei_server_handle_messages(RdpeiServerContext *context) {
DWORD bytesReturned;
RdpeiServerPrivate *priv = context->priv;
wStream *s = priv->inputStream;
if (!WTSVirtualChannelRead(priv->channelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned))
{
if (GetLastError() == ERROR_NO_DATA)
return -1;
fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__);
return 0;
}
priv->expectedBytes -= bytesReturned;
Stream_Seek(s, bytesReturned);
if (priv->expectedBytes)
return 1;
Stream_SealLength(s);
Stream_SetPosition(s, 0);
if (priv->waitingHeaders)
{
UINT32 pduLen;
/* header case */
Stream_Read_UINT16(s, priv->currentMsgType);
Stream_Read_UINT16(s, pduLen);
if (pduLen < RDPINPUT_HEADER_LENGTH)
{
fprintf(stderr, "%s: invalid pduLength %d\n", __FUNCTION__, pduLen);
return -1;
}
priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH;
priv->waitingHeaders = FALSE;
Stream_SetPosition(s, 0);
if (priv->expectedBytes)
{
Stream_EnsureCapacity(s, priv->expectedBytes);
return 1;
}
}
/* when here we have the header + the body */
switch (priv->currentMsgType)
{
case EVENTID_CS_READY:
if (priv->automataState != STATE_WAITING_CLIENT_READY)
{
fprintf(stderr, "%s: not expecting a CS_READY packet in this state(%d)\n", __FUNCTION__, (int)priv->automataState);
return 0;
}
if (read_cs_ready_message(context, s) < 0)
return 0;
break;
case EVENTID_TOUCH:
if (read_touch_event(context, s) < 0)
{
fprintf(stderr, "%s: error in touch event packet\n", __FUNCTION__);
return 0;
}
break;
case EVENTID_DISMISS_HOVERING_CONTACT:
if (read_dismiss_hovering_contact(context, s) < 0)
{
fprintf(stderr, "%s: error reading read_dismiss_hovering_contact\n", __FUNCTION__);
return 0;
}
break;
default:
fprintf(stderr, "%s: unexpected message type 0x%x\n", __FUNCTION__, priv->currentMsgType);
}
Stream_SetPosition(s, 0);
priv->waitingHeaders = TRUE;
priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
return 1;
}
int rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version)
{
ULONG written;
RdpeiServerPrivate *priv = context->priv;
if (priv->automataState != STATE_INITIAL)
{
fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState);
return -1;
}
Stream_SetPosition(priv->outputStream, 0);
Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4);
Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4);
Stream_Write_UINT32(priv->outputStream, version);
if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream),
Stream_GetPosition(priv->outputStream), &written))
{
fprintf(stderr, "%s: error writing ready message\n", __FUNCTION__);
return -1;
}
priv->automataState = STATE_WAITING_CLIENT_READY;
return 0;
}
int rdpei_server_suspend(RdpeiServerContext *context)
{
ULONG written;
RdpeiServerPrivate *priv = context->priv;
switch (priv->automataState)
{
case STATE_SUSPENDED:
fprintf(stderr, "%s: already suspended\n", __FUNCTION__);
return 0;
case STATE_WAITING_FRAME:
break;
default:
fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState);
return -1;
}
Stream_SetPosition(priv->outputStream, 0);
Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH);
Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH);
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream),
Stream_GetPosition(priv->outputStream), &written))
{
fprintf(stderr, "%s: error writing suspendTouch message\n", __FUNCTION__);
return -1;
}
priv->automataState = STATE_SUSPENDED;
return 0;
}
int rdpei_server_resume(RdpeiServerContext *context)
{
ULONG written;
RdpeiServerPrivate *priv = context->priv;
switch (priv->automataState)
{
case STATE_WAITING_FRAME:
fprintf(stderr, "%s: not suspended\n", __FUNCTION__);
return 0;
case STATE_SUSPENDED:
break;
default:
fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState);
return -1;
}
Stream_SetPosition(priv->outputStream, 0);
Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH);
Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH);
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream),
Stream_GetPosition(priv->outputStream), &written))
{
fprintf(stderr, "%s: error writing resumeTouch message\n", __FUNCTION__);
return -1;
}
priv->automataState = STATE_WAITING_FRAME;
return 0;
}

View File

@ -1,8 +1,8 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* X11 Server Cursor
* Extended Input channel server-side implementation
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +17,13 @@
* limitations under the License.
*/
#ifndef XFREERDP_SERVER_CURSOR_H
#define XFREERDP_SERVER_CURSOR_H
#ifndef __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_
#define __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_
#include "xfreerdp.h"
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
int xf_cursor_init(xfInfo* xfi);
#endif /* XFREERDP_SERVER_CURSOR_H */
#endif /* FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ */

View File

@ -20,6 +20,8 @@ define_channel_client("rdpgfx")
set(${MODULE_PREFIX}_SRCS
rdpgfx_main.c
rdpgfx_main.h
rdpgfx_codec.c
rdpgfx_codec.h
rdpgfx_common.c
rdpgfx_common.h)
@ -27,19 +29,9 @@ include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-sysinfo)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} winpr freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -0,0 +1,200 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Graphics Pipeline Extension
*
* Copyright 2014 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/stream.h>
#include <freerdp/log.h>
#include "rdpgfx_common.h"
#include "rdpgfx_codec.h"
#define TAG CHANNELS_TAG("rdpgfx.client")
int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
return 1;
}
int rdpgfx_decode_remotefx(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
return 1;
}
int rdpgfx_decode_clear(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
return 1;
}
int rdpgfx_decode_planar(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
return 1;
}
int rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta)
{
UINT32 index;
RDPGFX_RECT16* regionRect;
RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
meta->regionRects = NULL;
meta->quantQualityVals = NULL;
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8))
return -1;
meta->regionRects = (RDPGFX_RECT16*) malloc(meta->numRegionRects * sizeof(RDPGFX_RECT16));
if (!meta->regionRects)
return -1;
meta->quantQualityVals = (RDPGFX_H264_QUANT_QUALITY*) malloc(meta->numRegionRects * sizeof(RDPGFX_H264_QUANT_QUALITY));
if (!meta->quantQualityVals)
return -1;
WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %d", (int) meta->numRegionRects);
for (index = 0; index < meta->numRegionRects; index++)
{
regionRect = &(meta->regionRects[index]);
rdpgfx_read_rect16(s, regionRect);
WLog_DBG(TAG, "regionRects[%d]: left: %d top: %d right: %d bottom: %d",
index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom);
}
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 2))
return -1;
for (index = 0; index < meta->numRegionRects; index++)
{
quantQualityVal = &(meta->quantQualityVals[index]);
Stream_Read_UINT8(s, quantQualityVal->qpVal); /* qpVal (1 byte) */
Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */
quantQualityVal->qp = quantQualityVal->qpVal & 0x3F;
quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1;
quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1;
WLog_DBG(TAG, "quantQualityVals[%d]: qp: %d r: %d p: %d qualityVal: %d",
index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p, quantQualityVal->qualityVal);
}
return 1;
}
int rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
int status;
wStream* s;
RDPGFX_H264_BITMAP_STREAM h264;
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
s = Stream_New(cmd->data, cmd->length);
if (!s)
return -1;
status = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta));
if (status < 0)
{
if (h264.meta.regionRects)
free(h264.meta.regionRects);
if (h264.meta.quantQualityVals)
free(h264.meta.quantQualityVals);
return -1;
}
h264.data = Stream_Pointer(s);
h264.length = (UINT32) Stream_GetRemainingLength(s);
Stream_Free(s, FALSE);
cmd->extra = (void*) &h264;
if (context && context->SurfaceCommand)
{
context->SurfaceCommand(context, cmd);
}
free(h264.meta.regionRects);
free(h264.meta.quantQualityVals);
return 1;
}
int rdpgfx_decode_alpha(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
return 1;
}
int rdpgfx_decode_progressive(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
return 1;
}
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
{
int status;
switch (cmd->codecId)
{
case RDPGFX_CODECID_UNCOMPRESSED:
status = rdpgfx_decode_uncompressed(gfx, cmd);
break;
case RDPGFX_CODECID_CAVIDEO:
status = rdpgfx_decode_remotefx(gfx, cmd);
break;
case RDPGFX_CODECID_CLEARCODEC:
status = rdpgfx_decode_clear(gfx, cmd);
break;
case RDPGFX_CODECID_PLANAR:
status = rdpgfx_decode_planar(gfx, cmd);
break;
case RDPGFX_CODECID_H264:
status = rdpgfx_decode_h264(gfx, cmd);
break;
case RDPGFX_CODECID_ALPHA:
status = rdpgfx_decode_alpha(gfx, cmd);
break;
case RDPGFX_CODECID_CAPROGRESSIVE:
status = rdpgfx_decode_progressive(gfx, cmd);
break;
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
break;
}
return 1;
}

View File

@ -1,8 +1,8 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* X11 Server Graphical Updates
* Graphics Pipeline Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 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.
@ -17,12 +17,16 @@
* limitations under the License.
*/
#ifndef __XF_UPDATE_H
#define __XF_UPDATE_H
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H
#define FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H
#include "xfreerdp.h"
#include <winpr/crt.h>
#include <winpr/stream.h>
void* xf_update_thread(void* param);
#include <freerdp/channels/rdpgfx.h>
#endif /* __XF_UPDATE_H */
#include "rdpgfx_main.h"
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd);
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H */

View File

@ -26,12 +26,95 @@
#include "rdpgfx_common.h"
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* point16)
const char* RDPGFX_CMDID_STRINGS[] =
{
Stream_Read_UINT16(s, point16->x); /* x (2 bytes) */
Stream_Read_UINT16(s, point16->y); /* y (2 bytes) */
"RDPGFX_CMDID_UNUSED_0000",
"RDPGFX_CMDID_WIRETOSURFACE_1",
"RDPGFX_CMDID_WIRETOSURFACE_2",
"RDPGFX_CMDID_DELETEENCODINGCONTEXT",
"RDPGFX_CMDID_SOLIDFILL",
"RDPGFX_CMDID_SURFACETOSURFACE",
"RDPGFX_CMDID_SURFACETOCACHE",
"RDPGFX_CMDID_CACHETOSURFACE",
"RDPGFX_CMDID_EVICTCACHEENTRY",
"RDPGFX_CMDID_CREATESURFACE",
"RDPGFX_CMDID_DELETESURFACE",
"RDPGFX_CMDID_STARTFRAME",
"RDPGFX_CMDID_ENDFRAME",
"RDPGFX_CMDID_FRAMEACKNOWLEDGE",
"RDPGFX_CMDID_RESETGRAPHICS",
"RDPGFX_CMDID_MAPSURFACETOOUTPUT",
"RDPGFX_CMDID_CACHEIMPORTOFFER",
"RDPGFX_CMDID_CACHEIMPORTREPLY",
"RDPGFX_CMDID_CAPSADVERTISE",
"RDPGFX_CMDID_CAPSCONFIRM",
"RDPGFX_CMDID_UNUSED_0014",
"RDPGFX_CMDID_MAPSURFACETOWINDOW"
};
return 0;
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId)
{
if (cmdId <= RDPGFX_CMDID_MAPSURFACETOWINDOW)
return RDPGFX_CMDID_STRINGS[cmdId];
else
return "RDPGFX_CMDID_UNKNOWN";
}
const char* rdpgfx_get_codec_id_string(UINT16 codecId)
{
switch (codecId)
{
case RDPGFX_CODECID_UNCOMPRESSED:
return "RDPGFX_CODECID_UNCOMPRESSED";
case RDPGFX_CODECID_CAVIDEO:
return "RDPGFX_CODECID_CAVIDEO";
case RDPGFX_CODECID_CLEARCODEC:
return "RDPGFX_CODECID_CLEARCODEC";
case RDPGFX_CODECID_PLANAR:
return "RDPGFX_CODECID_PLANAR";
case RDPGFX_CODECID_H264:
return "RDPGFX_CODECID_H264";
case RDPGFX_CODECID_ALPHA:
return "RDPGFX_CODECID_ALPHA";
case RDPGFX_CODECID_CAPROGRESSIVE:
return "RDPGFX_CODECID_CAPROGRESSIVE";
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
return "RDPGFX_CODECID_CAPROGRESSIVE_V2";
}
return "RDPGFX_CODECID_UNKNOWN";
}
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
{
if (Stream_GetRemainingLength(s) < 8)
return -1;
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
return 1;
}
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
{
Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */
Stream_Write_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
return 1;
}
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16)
{
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT16(s, pt16->x); /* x (2 bytes) */
Stream_Read_UINT16(s, pt16->y); /* y (2 bytes) */
return 1;
}
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
@ -39,17 +122,20 @@ int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
Stream_Write_UINT16(s, point16->x); /* x (2 bytes) */
Stream_Write_UINT16(s, point16->y); /* y (2 bytes) */
return 0;
return 1;
}
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16)
{
if (Stream_GetRemainingLength(s) < 8)
return -1;
Stream_Read_UINT16(s, rect16->left); /* left (2 bytes) */
Stream_Read_UINT16(s, rect16->top); /* top (2 bytes) */
Stream_Read_UINT16(s, rect16->right); /* right (2 bytes) */
Stream_Read_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
return 0;
return 1;
}
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
@ -59,17 +145,20 @@ int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
Stream_Write_UINT16(s, rect16->right); /* right (2 bytes) */
Stream_Write_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
return 0;
return 1;
}
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32)
{
if (Stream_GetRemainingLength(s) < 4)
return -1;
Stream_Read_UINT8(s, color32->B); /* B (1 byte) */
Stream_Read_UINT8(s, color32->G); /* G (1 byte) */
Stream_Read_UINT8(s, color32->R); /* R (1 byte) */
Stream_Read_UINT8(s, color32->XA); /* XA (1 byte) */
return 0;
return 1;
}
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
@ -79,23 +168,5 @@ int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
Stream_Write_UINT8(s, color32->R); /* R (1 byte) */
Stream_Write_UINT8(s, color32->XA); /* XA (1 byte) */
return 0;
}
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
{
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
Stream_Read_UINT16(s, header->pduLength); /* pduLength (4 bytes) */
return 0;
}
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
{
Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */
Stream_Write_UINT16(s, header->pduLength); /* pduLength (4 bytes) */
return 0;
return 1;
}

View File

@ -25,14 +25,20 @@
#include <freerdp/channels/rdpgfx.h>
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* point16);
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId);
const char* rdpgfx_get_codec_id_string(UINT16 codecId);
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header);
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header);
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16);
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_COMMON_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* FreeRDP: A Remote Desktop Protocol Implementation
* Graphics Pipeline Extension
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2013-2014 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.
@ -20,17 +20,65 @@
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
#define FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <winpr/wlog.h>
#include <winpr/collections.h>
#include <freerdp/client/rdpgfx.h>
#include <freerdp/channels/log.h>
#include <freerdp/codec/zgfx.h>
#define TAG CHANNELS_TAG("rdpgfx.client")
struct _RDPGFX_CHANNEL_CALLBACK
{
IWTSVirtualChannelCallback iface;
IWTSPlugin* plugin;
IWTSVirtualChannelManager* channel_mgr;
IWTSVirtualChannel* channel;
};
typedef struct _RDPGFX_CHANNEL_CALLBACK RDPGFX_CHANNEL_CALLBACK;
struct _RDPGFX_LISTENER_CALLBACK
{
IWTSListenerCallback iface;
IWTSPlugin* plugin;
IWTSVirtualChannelManager* channel_mgr;
RDPGFX_CHANNEL_CALLBACK* channel_callback;
};
typedef struct _RDPGFX_LISTENER_CALLBACK RDPGFX_LISTENER_CALLBACK;
struct _RDPGFX_PLUGIN
{
IWTSPlugin iface;
IWTSListener* listener;
RDPGFX_LISTENER_CALLBACK* listener_callback;
wLog* log;
rdpSettings* settings;
BOOL ThinClient;
BOOL SmallCache;
BOOL Progressive;
BOOL ProgressiveV2;
BOOL H264;
ZGFX_CONTEXT* zgfx;
UINT32 UnacknowledgedFrames;
UINT32 TotalDecodedFrames;
wHashTable* SurfaceTable;
UINT16 MaxCacheSlot;
void* CacheSlots[25600];
};
typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN;
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */

View File

@ -23,19 +23,9 @@ set(${MODULE_PREFIX}_SRCS
add_channel_client_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-codec freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-sysinfo winpr-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
target_link_libraries(${MODULE_NAME} winpr freerdp)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -25,17 +25,9 @@ include_directories(${ALSA_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})

View File

@ -35,7 +35,7 @@
#include <freerdp/types.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/utils/debug.h>
#include <freerdp/channels/log.h>
#include "rdpsnd_main.h"
@ -68,7 +68,7 @@ struct rdpsnd_alsa_plugin
#define SND_PCM_CHECK(_func, _status) \
if (_status < 0) \
{ \
fprintf(stderr, "%s: %d\n", _func, _status); \
WLog_ERR(TAG, "%s: %d\n", _func, _status); \
return -1; \
}
@ -106,8 +106,8 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa)
if (alsa->buffer_size > buffer_size_max)
{
fprintf(stderr, "Warning: requested sound buffer size %d, got %d instead\n",
(int) alsa->buffer_size, (int) buffer_size_max);
WLog_ERR(TAG, "Warning: requested sound buffer size %d, got %d instead\n",
(int) alsa->buffer_size, (int) buffer_size_max);
alsa->buffer_size = buffer_size_max;
}
@ -262,7 +262,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
DEBUG_WARN("snd_mixer_open failed");
WLog_ERR(TAG, "snd_mixer_open failed");
return;
}
@ -270,7 +270,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
DEBUG_WARN("snd_mixer_attach failed");
WLog_ERR(TAG, "snd_mixer_attach failed");
snd_mixer_close(alsa->mixer_handle);
return;
}
@ -279,7 +279,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
DEBUG_WARN("snd_mixer_selem_register failed");
WLog_ERR(TAG, "snd_mixer_selem_register failed");
snd_mixer_close(alsa->mixer_handle);
return;
}
@ -288,7 +288,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
DEBUG_WARN("snd_mixer_load failed");
WLog_ERR(TAG, "snd_mixer_load failed");
snd_mixer_close(alsa->mixer_handle);
return;
}
@ -310,7 +310,7 @@ static void rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, i
if (status < 0)
{
DEBUG_WARN("snd_pcm_open failed");
WLog_ERR(TAG, "snd_pcm_open failed");
}
else
{
@ -579,7 +579,7 @@ static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
}
else if (status < 0)
{
fprintf(stderr, "status: %d\n", status);
WLog_ERR(TAG, "status: %d\n", status);
snd_pcm_close(alsa->pcm_handle);
alsa->pcm_handle = NULL;
rdpsnd_alsa_open((rdpsndDevicePlugin*) alsa, NULL, alsa->latency);
@ -599,8 +599,7 @@ static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
wave->wLocalTimeB += wave->wPlaybackDelay;
wave->wLatency = (UINT16) (wave->wLocalTimeB - wave->wLocalTimeA);
wave->wTimeStampB = wave->wTimeStampA + wave->wLatency;
//fprintf(stderr, "wTimeStampA: %d wTimeStampB: %d wLatency: %d\n", wave->wTimeStampA, wave->wTimeStampB, wave->wLatency);
//WLog_ERR(TAG, "wTimeStampA: %d wTimeStampB: %d wLatency: %d\n", wave->wTimeStampA, wave->wTimeStampB, wave->wLatency);
}
static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] =

View File

@ -31,18 +31,15 @@ include_directories(..)
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
${AUDIO_TOOL}
${CORE_AUDIO}
${CORE_FOUNDATION})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp}
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -37,7 +37,7 @@
#define reportResult(result,operation) (_reportResult((result),(operation),__FILE__,__LINE__))
static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
if ( result != ERR_SUCCESS ) {
printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
WLog_DBG(TAG, "%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
return false;
}
return true;
@ -108,7 +108,7 @@ bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
if ( virtualAddress != bufferAddress+buffer->length ) {
// If the memory is not contiguous, clean up both allocated buffers and try again
if ( retries-- == 0 ) {
printf("Couldn't map buffer memory to end of buffer\n");
WLog_DBG(TAG, "Couldn't map buffer memory to end of buffer");
return false;
}

View File

@ -20,12 +20,11 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/wtypes.h>
#include <freerdp/types.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/utils/svc_plugin.h>
#import <AudioToolbox/AudioToolbox.h>
@ -37,66 +36,66 @@
typedef struct rdpsnd_ios_plugin
{
rdpsndDevicePlugin device;
AudioComponentInstance audio_unit;
TPCircularBuffer buffer;
BOOL is_opened;
BOOL is_playing;
rdpsndDevicePlugin device;
AudioComponentInstance audio_unit;
TPCircularBuffer buffer;
BOOL is_opened;
BOOL is_playing;
} rdpsndIOSPlugin;
#define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr)
static OSStatus rdpsnd_ios_render_cb(
void *inRefCon,
AudioUnitRenderActionFlags __unused *ioActionFlags,
const AudioTimeStamp __unused *inTimeStamp,
UInt32 inBusNumber,
UInt32 __unused inNumberFrames,
AudioBufferList *ioData
void *inRefCon,
AudioUnitRenderActionFlags __unused *ioActionFlags,
const AudioTimeStamp __unused *inTimeStamp,
UInt32 inBusNumber,
UInt32 __unused inNumberFrames,
AudioBufferList *ioData
)
{
unsigned int i;
if (inBusNumber != 0)
{
return noErr;
}
rdpsndIOSPlugin *p = THIS(inRefCon);
for (i = 0; i < ioData->mNumberBuffers; i++)
{
AudioBuffer* target_buffer = &ioData->mBuffers[i];
int32_t available_bytes = 0;
const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
if (buffer != NULL && available_bytes > 0)
{
const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
memcpy(target_buffer->mData, buffer, bytes_to_copy);
target_buffer->mDataByteSize = bytes_to_copy;
TPCircularBufferConsume(&p->buffer, bytes_to_copy);
}
else
{
target_buffer->mDataByteSize = 0;
AudioOutputUnitStop(p->audio_unit);
p->is_playing = 0;
}
}
return noErr;
unsigned int i;
if (inBusNumber != 0)
{
return noErr;
}
rdpsndIOSPlugin *p = THIS(inRefCon);
for (i = 0; i < ioData->mNumberBuffers; i++)
{
AudioBuffer* target_buffer = &ioData->mBuffers[i];
int32_t available_bytes = 0;
const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
if (buffer != NULL && available_bytes > 0)
{
const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
memcpy(target_buffer->mData, buffer, bytes_to_copy);
target_buffer->mDataByteSize = bytes_to_copy;
TPCircularBufferConsume(&p->buffer, bytes_to_copy);
}
else
{
target_buffer->mDataByteSize = 0;
AudioOutputUnitStop(p->audio_unit);
p->is_playing = 0;
}
}
return noErr;
}
static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* format)
{
if (format->wFormatTag == WAVE_FORMAT_PCM)
{
return 1;
}
return 0;
if (format->wFormatTag == WAVE_FORMAT_PCM)
{
return 1;
}
return 0;
}
static void rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency)
@ -109,170 +108,170 @@ static void rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __
static void rdpsnd_ios_start(rdpsndDevicePlugin* device)
{
rdpsndIOSPlugin *p = THIS(device);
rdpsndIOSPlugin *p = THIS(device);
/* If this device is not playing... */
if (!p->is_playing)
{
/* Start the device. */
int32_t available_bytes = 0;
TPCircularBufferTail(&p->buffer, &available_bytes);
if (available_bytes > 0)
{
p->is_playing = 1;
AudioOutputUnitStart(p->audio_unit);
}
}
/* If this device is not playing... */
if (!p->is_playing)
{
/* Start the device. */
int32_t available_bytes = 0;
TPCircularBufferTail(&p->buffer, &available_bytes);
if (available_bytes > 0)
{
p->is_playing = 1;
AudioOutputUnitStart(p->audio_unit);
}
}
}
static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device)
{
rdpsndIOSPlugin *p = THIS(device);
rdpsndIOSPlugin *p = THIS(device);
/* If the device is playing... */
if (p->is_playing)
{
/* Stop the device. */
AudioOutputUnitStop(p->audio_unit);
p->is_playing = 0;
/* If the device is playing... */
if (p->is_playing)
{
/* Stop the device. */
AudioOutputUnitStop(p->audio_unit);
p->is_playing = 0;
/* Free all buffers. */
TPCircularBufferClear(&p->buffer);
}
/* Free all buffers. */
TPCircularBufferClear(&p->buffer);
}
}
static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size)
{
rdpsndIOSPlugin *p = THIS(device);
const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
if (!ok)
{
return;
}
rdpsnd_ios_start(device);
rdpsndIOSPlugin *p = THIS(device);
const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
if (!ok)
{
return;
}
rdpsnd_ios_start(device);
}
static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency)
{
rdpsndIOSPlugin *p = THIS(device);
if (p->is_opened)
{
return;
}
rdpsndIOSPlugin *p = THIS(device);
/* Find the output audio unit. */
AudioComponentDescription desc;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
if (audioComponent == NULL) return;
if (p->is_opened)
{
return;
}
/* Open the audio unit. */
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
if (status != 0) return;
/* Find the output audio unit. */
AudioComponentDescription desc;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
/* Set the format for the AudioUnit. */
AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = format->nSamplesPerSec;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */
audioFormat.mChannelsPerFrame = format->nChannels;
audioFormat.mBitsPerChannel = format->wBitsPerSample;
audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
status = AudioUnitSetProperty(
p->audio_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&audioFormat,
sizeof(audioFormat));
if (status != 0)
{
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
/* Set up the AudioUnit callback. */
AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = rdpsnd_ios_render_cb;
callbackStruct.inputProcRefCon = p;
status = AudioUnitSetProperty(
p->audio_unit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callbackStruct,
sizeof(callbackStruct));
if (status != 0)
{
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
if (audioComponent == NULL) return;
/* Initialize the AudioUnit. */
status = AudioUnitInitialize(p->audio_unit);
if (status != 0)
{
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
/* Allocate the circular buffer. */
const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
if (!ok)
{
AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
/* Open the audio unit. */
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
if (status != 0) return;
p->is_opened = 1;
/* Set the format for the AudioUnit. */
AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = format->nSamplesPerSec;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */
audioFormat.mChannelsPerFrame = format->nChannels;
audioFormat.mBitsPerChannel = format->wBitsPerSample;
audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
status = AudioUnitSetProperty(
p->audio_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&audioFormat,
sizeof(audioFormat));
if (status != 0)
{
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
/* Set up the AudioUnit callback. */
AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = rdpsnd_ios_render_cb;
callbackStruct.inputProcRefCon = p;
status = AudioUnitSetProperty(
p->audio_unit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callbackStruct,
sizeof(callbackStruct));
if (status != 0)
{
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
/* Initialize the AudioUnit. */
status = AudioUnitInitialize(p->audio_unit);
if (status != 0)
{
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
/* Allocate the circular buffer. */
const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
if (!ok)
{
AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
return;
}
p->is_opened = 1;
}
static void rdpsnd_ios_close(rdpsndDevicePlugin* device)
{
rdpsndIOSPlugin *p = THIS(device);
rdpsndIOSPlugin *p = THIS(device);
/* Make sure the device is stopped. */
rdpsnd_ios_stop(device);
/* Make sure the device is stopped. */
rdpsnd_ios_stop(device);
/* If the device is open... */
if (p->is_opened)
{
/* Close the device. */
AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
p->is_opened = 0;
/* Destroy the circular buffer. */
TPCircularBufferCleanup(&p->buffer);
}
/* If the device is open... */
if (p->is_opened)
{
/* Close the device. */
AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL;
p->is_opened = 0;
/* Destroy the circular buffer. */
TPCircularBufferCleanup(&p->buffer);
}
}
static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
{
rdpsndIOSPlugin *p = THIS(device);
rdpsndIOSPlugin *p = THIS(device);
/* Ensure the device is closed. */
rdpsnd_ios_close(device);
/* Ensure the device is closed. */
rdpsnd_ios_close(device);
/* Free memory associated with the device. */
free(p);
/* Free memory associated with the device. */
free(p);
}
#ifdef STATIC_CHANNELS
@ -281,19 +280,21 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
{
rdpsndIOSPlugin *p = (rdpsndIOSPlugin*)malloc(sizeof(rdpsndIOSPlugin));
memset(p, 0, sizeof(rdpsndIOSPlugin));
p->device.Open = rdpsnd_ios_open;
p->device.FormatSupported = rdpsnd_ios_format_supported;
p->device.SetFormat = rdpsnd_ios_set_format;
p->device.SetVolume = rdpsnd_ios_set_volume;
p->device.Play = rdpsnd_ios_play;
p->device.Start = rdpsnd_ios_start;
p->device.Close = rdpsnd_ios_close;
p->device.Free = rdpsnd_ios_free;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
return 0;
}
rdpsndIOSPlugin* p = (rdpsndIOSPlugin*) calloc(1, sizeof(rdpsndIOSPlugin));
if (!p)
return -1;
p->device.Open = rdpsnd_ios_open;
p->device.FormatSupported = rdpsnd_ios_format_supported;
p->device.SetFormat = rdpsnd_ios_set_format;
p->device.SetVolume = rdpsnd_ios_set_volume;
p->device.Play = rdpsnd_ios_play;
p->device.Start = rdpsnd_ios_start;
p->device.Close = rdpsnd_ios_close;
p->device.Free = rdpsnd_ios_free;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
return 0;
}

View File

@ -31,18 +31,15 @@ include_directories(${MACAUDIO_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
${AUDIO_TOOL}
${CORE_AUDIO}
${CORE_FOUNDATION})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -29,7 +29,6 @@
#include <freerdp/types.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/utils/svc_plugin.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AudioToolbox/AudioQueue.h>
@ -122,7 +121,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
if (status != 0)
{
fprintf(stderr, "AudioQueueNewOutput failure\n");
WLog_ERR(TAG, "AudioQueueNewOutput failure\n");
return;
}
@ -136,7 +135,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
if (status != 0)
{
printf("AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n");
WLog_DBG(TAG, "AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n");
}
for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++)
@ -145,7 +144,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
if (status != 0)
{
fprintf(stderr, "AudioQueueAllocateBuffer failed\n");
WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n");
}
}
@ -220,7 +219,7 @@ static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value)
if (status != 0)
{
fprintf(stderr, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume);
WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume);
}
}
@ -239,7 +238,7 @@ static void rdpsnd_mac_start(rdpsndDevicePlugin* device)
if (status != 0)
{
fprintf(stderr, "AudioQueueStart failed\n");
WLog_ERR(TAG, "AudioQueueStart failed\n");
}
mac->isPlaying = TRUE;
@ -282,23 +281,21 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
{
rdpsndMacPlugin* mac;
mac = (rdpsndMacPlugin*) malloc(sizeof(rdpsndMacPlugin));
mac = (rdpsndMacPlugin*) calloc(1, sizeof(rdpsndMacPlugin));
if (mac)
{
ZeroMemory(mac, sizeof(rdpsndMacPlugin));
if (!mac)
return -1;
mac->device.Open = rdpsnd_mac_open;
mac->device.FormatSupported = rdpsnd_mac_format_supported;
mac->device.SetFormat = rdpsnd_mac_set_format;
mac->device.SetVolume = rdpsnd_mac_set_volume;
mac->device.Play = rdpsnd_mac_play;
mac->device.Start = rdpsnd_mac_start;
mac->device.Close = rdpsnd_mac_close;
mac->device.Free = rdpsnd_mac_free;
mac->device.Open = rdpsnd_mac_open;
mac->device.FormatSupported = rdpsnd_mac_format_supported;
mac->device.SetFormat = rdpsnd_mac_set_format;
mac->device.SetVolume = rdpsnd_mac_set_volume;
mac->device.Play = rdpsnd_mac_play;
mac->device.Start = rdpsnd_mac_start;
mac->device.Close = rdpsnd_mac_close;
mac->device.Free = rdpsnd_mac_free;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
}
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
return 0;
}

View File

@ -26,15 +26,9 @@ include_directories(${OPENSLES_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils
${OPENSLES_LIBRARIES})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES})
set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

Some files were not shown because too many files have changed in this diff Show More