Merge branch 'master' of https://github.com/awakecoding/FreeRDP into awakecoding-staging
This commit is contained in:
commit
5fa6fa7013
6
.gitignore
vendored
Executable file → Normal file
6
.gitignore
vendored
Executable file → Normal file
@ -92,6 +92,7 @@ RelWithDebInfo
|
|||||||
|
|
||||||
# Binaries
|
# Binaries
|
||||||
*.a
|
*.a
|
||||||
|
*.o
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
*.dylib
|
*.dylib
|
||||||
@ -105,6 +106,7 @@ client/DirectFB/dfreerdp
|
|||||||
server/Sample/sfreerdp-server
|
server/Sample/sfreerdp-server
|
||||||
server/X11/xfreerdp-server
|
server/X11/xfreerdp-server
|
||||||
xcode
|
xcode
|
||||||
|
libfreerdp/codec/test/TestOpenH264ASM
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
*~
|
*~
|
||||||
@ -113,6 +115,7 @@ Release
|
|||||||
Win32
|
Win32
|
||||||
build*/
|
build*/
|
||||||
*.orig
|
*.orig
|
||||||
|
*.msrcIncident
|
||||||
|
|
||||||
default.log
|
default.log
|
||||||
*Amplifier XE*
|
*Amplifier XE*
|
||||||
@ -122,3 +125,6 @@ default.log
|
|||||||
*.txt.user
|
*.txt.user
|
||||||
|
|
||||||
*.autosave
|
*.autosave
|
||||||
|
|
||||||
|
# etags
|
||||||
|
TAGS
|
||||||
|
71
CMakeLists.txt
Executable file → Normal file
71
CMakeLists.txt
Executable file → Normal file
@ -59,6 +59,7 @@ include(GNUInstallDirsWrapper)
|
|||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
# Soname versioning
|
# Soname versioning
|
||||||
|
set(WITH_LIBRARY_VERSIONING "ON")
|
||||||
set(FREERDP_VERSION_MAJOR "1")
|
set(FREERDP_VERSION_MAJOR "1")
|
||||||
set(FREERDP_VERSION_MINOR "2")
|
set(FREERDP_VERSION_MINOR "2")
|
||||||
set(FREERDP_VERSION_REVISION "0")
|
set(FREERDP_VERSION_REVISION "0")
|
||||||
@ -232,9 +233,23 @@ endif()
|
|||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUNICODE -D_UNICODE")
|
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} -D_CRT_SECURE_NO_WARNINGS")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN")
|
||||||
|
|
||||||
|
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()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
@ -248,6 +263,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINPR_EXPORTS -DFREERDP_EXPORTS")
|
|||||||
if(NOT IOS)
|
if(NOT IOS)
|
||||||
check_include_files(fcntl.h HAVE_FCNTL_H)
|
check_include_files(fcntl.h HAVE_FCNTL_H)
|
||||||
check_include_files(unistd.h HAVE_UNISTD_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(stdint.h HAVE_STDINT_H)
|
||||||
check_include_files(inttypes.h HAVE_INTTYPES_H)
|
check_include_files(inttypes.h HAVE_INTTYPES_H)
|
||||||
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
|
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
|
||||||
@ -301,6 +317,8 @@ endif(APPLE)
|
|||||||
|
|
||||||
# Android
|
# Android
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
|
set(WITH_LIBRARY_VERSIONING "OFF")
|
||||||
|
|
||||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
add_definitions(-DNDK_DEBUG=1)
|
add_definitions(-DNDK_DEBUG=1)
|
||||||
|
|
||||||
@ -369,9 +387,12 @@ if(UNIX OR CYGWIN)
|
|||||||
check_include_files(sys/eventfd.h HAVE_AIO_H)
|
check_include_files(sys/eventfd.h HAVE_AIO_H)
|
||||||
check_include_files(sys/eventfd.h HAVE_EVENTFD_H)
|
check_include_files(sys/eventfd.h HAVE_EVENTFD_H)
|
||||||
check_include_files(sys/timerfd.h HAVE_TIMERFD_H)
|
check_include_files(sys/timerfd.h HAVE_TIMERFD_H)
|
||||||
|
check_include_files(poll.h HAVE_POLL_H)
|
||||||
set(X11_FEATURE_TYPE "RECOMMENDED")
|
set(X11_FEATURE_TYPE "RECOMMENDED")
|
||||||
|
set(WAYLAND_FEATURE_TYPE "RECOMMENDED")
|
||||||
else()
|
else()
|
||||||
set(X11_FEATURE_TYPE "DISABLED")
|
set(X11_FEATURE_TYPE "DISABLED")
|
||||||
|
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_PCSC_WINPR)
|
if(WITH_PCSC_WINPR)
|
||||||
@ -381,6 +402,9 @@ endif()
|
|||||||
set(X11_FEATURE_PURPOSE "X11")
|
set(X11_FEATURE_PURPOSE "X11")
|
||||||
set(X11_FEATURE_DESCRIPTION "X11 client and server")
|
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_TYPE "OPTIONAL")
|
||||||
set(DIRECTFB_FEATURE_PURPOSE "DirectFB")
|
set(DIRECTFB_FEATURE_PURPOSE "DirectFB")
|
||||||
set(DIRECTFB_FEATURE_DESCRIPTION "DirectFB client")
|
set(DIRECTFB_FEATURE_DESCRIPTION "DirectFB client")
|
||||||
@ -433,12 +457,17 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
|
|||||||
set(JPEG_FEATURE_PURPOSE "codec")
|
set(JPEG_FEATURE_PURPOSE "codec")
|
||||||
set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
|
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_TYPE "OPTIONAL")
|
||||||
set(GSM_FEATURE_PURPOSE "codec")
|
set(GSM_FEATURE_PURPOSE "codec")
|
||||||
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
|
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(X11_FEATURE_TYPE "DISABLED")
|
set(X11_FEATURE_TYPE "DISABLED")
|
||||||
|
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||||
set(ZLIB_FEATURE_TYPE "DISABLED")
|
set(ZLIB_FEATURE_TYPE "DISABLED")
|
||||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||||
@ -456,6 +485,7 @@ if(APPLE)
|
|||||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||||
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
|
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
|
||||||
set(X11_FEATURE_TYPE "OPTIONAL")
|
set(X11_FEATURE_TYPE "OPTIONAL")
|
||||||
|
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||||
if(IOS)
|
if(IOS)
|
||||||
set(X11_FEATURE_TYPE "DISABLED")
|
set(X11_FEATURE_TYPE "DISABLED")
|
||||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||||
@ -470,6 +500,7 @@ endif()
|
|||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
set(X11_FEATURE_TYPE "DISABLED")
|
set(X11_FEATURE_TYPE "DISABLED")
|
||||||
|
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||||
@ -483,6 +514,7 @@ endif()
|
|||||||
|
|
||||||
|
|
||||||
find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION})
|
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})
|
find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION})
|
||||||
if (${WITH_DIRECTFB})
|
if (${WITH_DIRECTFB})
|
||||||
message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details")
|
message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details")
|
||||||
@ -504,6 +536,7 @@ find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEAT
|
|||||||
find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_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(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})
|
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
|
||||||
|
|
||||||
if(TARGET_ARCH MATCHES "x86|x64")
|
if(TARGET_ARCH MATCHES "x86|x64")
|
||||||
@ -608,6 +641,12 @@ if (IOS)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# RdTk
|
||||||
|
include_directories("${CMAKE_SOURCE_DIR}/rdtk/include")
|
||||||
|
include_directories("${CMAKE_BINARY_DIR}/rdtk/include")
|
||||||
|
|
||||||
|
add_subdirectory(rdtk)
|
||||||
|
|
||||||
if(WITH_CLIENT)
|
if(WITH_CLIENT)
|
||||||
add_subdirectory(client)
|
add_subdirectory(client)
|
||||||
endif()
|
endif()
|
||||||
@ -625,7 +664,9 @@ if(${CMAKE_VERSION} VERSION_GREATER "2.8.10")
|
|||||||
set(FREERDP_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP")
|
set(FREERDP_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP")
|
||||||
|
|
||||||
set(FREERDP_INCLUDE_DIR "include")
|
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
|
configure_package_config_file(FreeRDPConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfig.cmake
|
||||||
INSTALL_DESTINATION ${FREERDP_CMAKE_INSTALL_DIR}
|
INSTALL_DESTINATION ${FREERDP_CMAKE_INSTALL_DIR}
|
||||||
@ -657,27 +698,11 @@ endif()
|
|||||||
|
|
||||||
include(${CMAKE_CPACK_INCLUDE_FILE})
|
include(${CMAKE_CPACK_INCLUDE_FILE})
|
||||||
|
|
||||||
if(MONOLITHIC_BUILD)
|
set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client")
|
||||||
set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client")
|
set(WINPR_PC_LIBS "-lwinpr")
|
||||||
set(WINPR_PC_LIBS "-lwinpr")
|
if (WITH_SERVER)
|
||||||
if (WITH_SERVER)
|
set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server")
|
||||||
set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server")
|
endif()
|
||||||
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)
|
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
|
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)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/winpr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc @ONLY)
|
||||||
|
@ -27,12 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -27,12 +27,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp ${ALSA_LIBRARIES})
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -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)
|
if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_pcm_hw_params_malloc (%s)",
|
WLog_ERR(TAG, "snd_pcm_hw_params_malloc (%s)",
|
||||||
snd_strerror(error));
|
snd_strerror(error));
|
||||||
return FALSE;
|
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)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ static void* audin_alsa_thread_func(void* arg)
|
|||||||
}
|
}
|
||||||
else if (error < 0)
|
else if (error < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_pcm_readi (%s)", snd_strerror(error));
|
WLog_ERR(TAG, "snd_pcm_readi (%s)", snd_strerror(error));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w
|
|||||||
DEBUG_DVC("NumFormats %d", NumFormats);
|
DEBUG_DVC("NumFormats %d", NumFormats);
|
||||||
if ((NumFormats < 1) || (NumFormats > 1000))
|
if ((NumFormats < 1) || (NumFormats > 1000))
|
||||||
{
|
{
|
||||||
DEBUG_WARN("bad NumFormats %d", NumFormats);
|
WLog_ERR(TAG, "bad NumFormats %d", NumFormats);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */
|
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */
|
||||||
@ -262,8 +262,8 @@ static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStr
|
|||||||
|
|
||||||
if (initialFormat >= (UINT32) callback->formats_count)
|
if (initialFormat >= (UINT32) callback->formats_count)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("invalid format index %d (total %d)",
|
WLog_ERR(TAG, "invalid format index %d (total %d)",
|
||||||
initialFormat, callback->formats_count);
|
initialFormat, callback->formats_count);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,8 +293,8 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
|
|||||||
|
|
||||||
if (NewFormat >= (UINT32) callback->formats_count)
|
if (NewFormat >= (UINT32) callback->formats_count)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("invalid format index %d (total %d)",
|
WLog_ERR(TAG, "invalid format index %d (total %d)",
|
||||||
NewFormat, callback->formats_count);
|
NewFormat, callback->formats_count);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("unknown MessageId=0x%x", MessageId);
|
WLog_ERR(TAG, "unknown MessageId=0x%x", MessageId);
|
||||||
error = 1;
|
error = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -429,7 +429,7 @@ static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi
|
|||||||
|
|
||||||
if (audin->device)
|
if (audin->device)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("existing device, abort.");
|
WLog_ERR(TAG, "existing device, abort.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +454,7 @@ static BOOL audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI
|
|||||||
|
|
||||||
if (entry(&entryPoints) != 0)
|
if (entry(&entryPoints) != 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("%s entry returns error.", name);
|
WLog_ERR(TAG, "%s entry returns error.", name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,7 +613,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||||||
|
|
||||||
if (audin->device == NULL)
|
if (audin->device == NULL)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("no sound device.");
|
WLog_ERR(TAG, "no sound device.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -27,13 +27,15 @@
|
|||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/client/audin.h>
|
#include <freerdp/client/audin.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("audin.client")
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_DVC
|
#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
|
#else
|
||||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
#define DEBUG_DVC(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* FREERDP_AUDIN_CLIENT_MAIN_H */
|
#endif /* FREERDP_AUDIN_CLIENT_MAIN_H */
|
||||||
|
@ -28,14 +28,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES})
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils
|
|
||||||
${OPENSLES_LIBRARIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES})
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ static void* audin_opensles_thread_func(void* arg)
|
|||||||
int rc = android_RecIn(opensles->stream, buffer.s, raw_size);
|
int rc = android_RecIn(opensles->stream, buffer.s, raw_size);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("android_RecIn %d", rc);
|
WLog_ERR(TAG, "android_RecIn %d", rc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,9 +250,9 @@ static void audin_opensles_set_format(IAudinDevice* device,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("Encoding '%d' [%08X] not supported",
|
WLog_ERR(TAG, "Encoding '%d' [%08X] not supported",
|
||||||
(format->wFormatTag),
|
(format->wFormatTag),
|
||||||
format->wFormatTag);
|
format->wFormatTag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +309,7 @@ static void audin_opensles_close(IAudinDevice* device)
|
|||||||
* ignore duplicate requests. */
|
* ignore duplicate requests. */
|
||||||
if (!opensles->stopEvent)
|
if (!opensles->stopEvent)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("[ERROR] function called without matching open.");
|
WLog_ERR(TAG, "[ERROR] function called without matching open.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ int android_RecIn(OPENSL_STREAM *p,short *buffer,int size)
|
|||||||
e = Queue_Dequeue(p->queue);
|
e = Queue_Dequeue(p->queue);
|
||||||
if (!e)
|
if (!e)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("[ERROR] got e=%p from queue", e);
|
WLog_ERR(TAG, "[ERROR] got e=%p from queue", e);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,12 +27,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp ${PULSE_LIBRARY})
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY})
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -94,16 +94,16 @@ static BOOL audin_pulse_connect(IAudinDevice* device)
|
|||||||
|
|
||||||
if (pa_context_connect(pulse->context, NULL, 0, NULL))
|
if (pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||||
{
|
{
|
||||||
DEBUG_WARN("pa_context_connect failed (%d)",
|
WLog_ERR(TAG, "pa_context_connect failed (%d)",
|
||||||
pa_context_errno(pulse->context));
|
pa_context_errno(pulse->context));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||||
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||||
{
|
{
|
||||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||||
DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
|
WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)",
|
||||||
pa_context_errno(pulse->context));
|
pa_context_errno(pulse->context));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -113,8 +113,8 @@ static BOOL audin_pulse_connect(IAudinDevice* device)
|
|||||||
break;
|
break;
|
||||||
if (!PA_CONTEXT_IS_GOOD(state))
|
if (!PA_CONTEXT_IS_GOOD(state))
|
||||||
{
|
{
|
||||||
DEBUG_WARN("bad context state (%d)",
|
WLog_ERR(TAG, "bad context state (%d)",
|
||||||
pa_context_errno(pulse->context));
|
pa_context_errno(pulse->context));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
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)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,8 +415,8 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
|
|||||||
&buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0)
|
&buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0)
|
||||||
{
|
{
|
||||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||||
DEBUG_WARN("pa_stream_connect_playback failed (%d)",
|
WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)",
|
||||||
pa_context_errno(pulse->context));
|
pa_context_errno(pulse->context));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,8 +427,8 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
|
|||||||
break;
|
break;
|
||||||
if (!PA_STREAM_IS_GOOD(state))
|
if (!PA_STREAM_IS_GOOD(state))
|
||||||
{
|
{
|
||||||
DEBUG_WARN("bad stream state (%d)",
|
WLog_ERR(TAG, "bad stream state (%d)",
|
||||||
pa_context_errno(pulse->context));
|
pa_context_errno(pulse->context));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
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)
|
if (!pulse->mainloop)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("pa_threaded_mainloop_new failed");
|
WLog_ERR(TAG, "pa_threaded_mainloop_new failed");
|
||||||
audin_pulse_free((IAudinDevice*) pulse);
|
audin_pulse_free((IAudinDevice*) pulse);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -521,7 +521,7 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
|||||||
|
|
||||||
if (!pulse->context)
|
if (!pulse->context)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("pa_context_new failed");
|
WLog_ERR(TAG, "pa_context_new failed");
|
||||||
audin_pulse_free((IAudinDevice*) pulse);
|
audin_pulse_free((IAudinDevice*) pulse);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp winmm.lib)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -24,12 +24,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
#include <freerdp/codec/audio.h>
|
#include <freerdp/codec/audio.h>
|
||||||
#include <freerdp/channels/wtsvc.h>
|
#include <freerdp/channels/wtsvc.h>
|
||||||
#include <freerdp/server/audin.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_VERSION 0x01
|
||||||
#define MSG_SNDIN_FORMATS 0x02
|
#define MSG_SNDIN_FORMATS 0x02
|
||||||
#define MSG_SNDIN_OPEN 0x03
|
#define MSG_SNDIN_OPEN 0x03
|
||||||
@ -345,24 +347,16 @@ static void* audin_server_thread_func(void* arg)
|
|||||||
|
|
||||||
Stream_SetPosition(s, 0);
|
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),
|
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
|
||||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||||
{
|
{
|
||||||
if (BytesReturned == 0)
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
|
||||||
|
|
||||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
|
|
||||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BytesReturned < 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Stream_Read_UINT8(s, MessageId);
|
Stream_Read_UINT8(s, MessageId);
|
||||||
BytesReturned--;
|
BytesReturned--;
|
||||||
|
|
||||||
@ -393,7 +387,7 @@ static void* audin_server_thread_func(void* arg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,15 +96,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)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c)
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp winpr)
|
||||||
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}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE)
|
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE)
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||||
|
@ -27,15 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp winpr)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-crt)
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (num_formats * 36 != length)
|
if (num_formats * 36 != length)
|
||||||
DEBUG_WARN("dataLen %d not divided by 36!", length);
|
WLog_ERR(TAG, "dataLen %d not divided by 36!", length);
|
||||||
|
|
||||||
ascii = (flags & CB_ASCII_NAMES) ? TRUE : FALSE;
|
ascii = (flags & CB_ASCII_NAMES) ? TRUE : FALSE;
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
|
|||||||
formatList.msgFlags = msgFlags;
|
formatList.msgFlags = msgFlags;
|
||||||
formatList.dataLen = dataLen;
|
formatList.dataLen = dataLen;
|
||||||
|
|
||||||
formatList.cFormats = 0;
|
formatList.numFormats = 0;
|
||||||
|
|
||||||
while (dataLen)
|
while (dataLen)
|
||||||
{
|
{
|
||||||
@ -235,14 +235,14 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
|
|||||||
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
|
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
|
||||||
Stream_Seek(s, (formatNameLength + 1) * 2);
|
Stream_Seek(s, (formatNameLength + 1) * 2);
|
||||||
dataLen -= ((formatNameLength + 1) * 2);
|
dataLen -= ((formatNameLength + 1) * 2);
|
||||||
formatList.cFormats++;
|
formatList.numFormats++;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
dataLen = formatList.dataLen;
|
dataLen = formatList.dataLen;
|
||||||
Stream_Rewind(s, dataLen);
|
Stream_Rewind(s, dataLen);
|
||||||
|
|
||||||
formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.cFormats);
|
formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.numFormats);
|
||||||
formatList.formats = formats;
|
formatList.formats = formats;
|
||||||
|
|
||||||
while (dataLen)
|
while (dataLen)
|
||||||
@ -270,10 +270,13 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
|
|||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d",
|
||||||
|
formatList.numFormats);
|
||||||
|
|
||||||
if (context->ServerFormatList)
|
if (context->ServerFormatList)
|
||||||
context->ServerFormatList(context, &formatList);
|
context->ServerFormatList(context, &formatList);
|
||||||
|
|
||||||
for (index = 0; index < formatList.cFormats; index++)
|
for (index = 0; index < formatList.numFormats; index++)
|
||||||
free(formats[index].formatName);
|
free(formats[index].formatName);
|
||||||
|
|
||||||
free(formats);
|
free(formats);
|
||||||
@ -315,9 +318,9 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
|
|||||||
|
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case CB_FORMAT_TEXT:
|
case CF_TEXT:
|
||||||
case CB_FORMAT_DIB:
|
case CF_DIB:
|
||||||
case CB_FORMAT_UNICODETEXT:
|
case CF_UNICODETEXT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -367,6 +370,9 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
|
|||||||
|
|
||||||
cliprdr->num_format_names = 0;
|
cliprdr->num_format_names = 0;
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d",
|
||||||
|
cb_event->num_formats);
|
||||||
|
|
||||||
cliprdr_send_format_list_response(cliprdr);
|
cliprdr_send_format_list_response(cliprdr);
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
||||||
}
|
}
|
||||||
@ -376,6 +382,8 @@ void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI
|
|||||||
{
|
{
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse");
|
||||||
|
|
||||||
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */
|
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */
|
||||||
|
|
||||||
if (context->custom)
|
if (context->custom)
|
||||||
@ -406,6 +414,8 @@ void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN
|
|||||||
{
|
{
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest");
|
||||||
|
|
||||||
if (context->custom)
|
if (context->custom)
|
||||||
{
|
{
|
||||||
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
|
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
|
||||||
@ -465,6 +475,8 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
|
|||||||
{
|
{
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse");
|
||||||
|
|
||||||
if (context->custom)
|
if (context->custom)
|
||||||
{
|
{
|
||||||
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
|
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
|
||||||
|
@ -63,13 +63,11 @@ CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr)
|
|||||||
wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen)
|
wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen)
|
||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s;
|
||||||
|
|
||||||
s = Stream_New(NULL, dataLen + 8);
|
s = Stream_New(NULL, dataLen + 8);
|
||||||
Stream_Write_UINT16(s, msgType);
|
Stream_Write_UINT16(s, msgType);
|
||||||
Stream_Write_UINT16(s, msgFlags);
|
Stream_Write_UINT16(s, msgFlags);
|
||||||
/* Write actual length after the entire packet has been constructed. */
|
/* Write actual length after the entire packet has been constructed. */
|
||||||
Stream_Seek(s, 4);
|
Stream_Seek(s, 4);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,18 +75,15 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s)
|
|||||||
{
|
{
|
||||||
int pos;
|
int pos;
|
||||||
UINT32 dataLen;
|
UINT32 dataLen;
|
||||||
|
|
||||||
pos = Stream_GetPosition(s);
|
pos = Stream_GetPosition(s);
|
||||||
dataLen = pos - 8;
|
dataLen = pos - 8;
|
||||||
Stream_SetPosition(s, 4);
|
Stream_SetPosition(s, 4);
|
||||||
Stream_Write_UINT32(s, dataLen);
|
Stream_Write_UINT32(s, dataLen);
|
||||||
Stream_SetPosition(s, pos);
|
Stream_SetPosition(s, pos);
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_CLIPRDR
|
#ifdef WITH_DEBUG_CLIPRDR
|
||||||
printf("Cliprdr Sending (%d bytes)\n", dataLen + 8);
|
WLog_DBG(TAG, "Cliprdr Sending (%d bytes)", dataLen + 8);
|
||||||
winpr_HexDump(Stream_Buffer(s), dataLen + 8);
|
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
svc_plugin_send((rdpSvcPlugin*) cliprdr, s);
|
svc_plugin_send((rdpSvcPlugin*) cliprdr, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,18 +94,21 @@ static void cliprdr_process_connect(rdpSvcPlugin* plugin)
|
|||||||
|
|
||||||
void cliprdr_print_general_capability_flags(UINT32 flags)
|
void cliprdr_print_general_capability_flags(UINT32 flags)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "generalFlags (0x%08X) {\n", flags);
|
WLog_INFO(TAG, "generalFlags (0x%08X) {", flags);
|
||||||
|
|
||||||
if (flags & CB_USE_LONG_FORMAT_NAMES)
|
if (flags & CB_USE_LONG_FORMAT_NAMES)
|
||||||
fprintf(stderr, "\tCB_USE_LONG_FORMAT_NAMES\n");
|
WLog_INFO(TAG, "\tCB_USE_LONG_FORMAT_NAMES");
|
||||||
if (flags & CB_STREAM_FILECLIP_ENABLED)
|
|
||||||
fprintf(stderr, "\tCB_STREAM_FILECLIP_ENABLED\n");
|
|
||||||
if (flags & CB_FILECLIP_NO_FILE_PATHS)
|
|
||||||
fprintf(stderr, "\tCB_FILECLIP_NO_FILE_PATHS\n");
|
|
||||||
if (flags & CB_CAN_LOCK_CLIPDATA)
|
|
||||||
fprintf(stderr, "\tCB_CAN_LOCK_CLIPDATA\n");
|
|
||||||
|
|
||||||
fprintf(stderr, "}\n");
|
if (flags & CB_STREAM_FILECLIP_ENABLED)
|
||||||
|
WLog_INFO(TAG, "\tCB_STREAM_FILECLIP_ENABLED");
|
||||||
|
|
||||||
|
if (flags & CB_FILECLIP_NO_FILE_PATHS)
|
||||||
|
WLog_INFO(TAG, "\tCB_FILECLIP_NO_FILE_PATHS");
|
||||||
|
|
||||||
|
if (flags & CB_CAN_LOCK_CLIPDATA)
|
||||||
|
WLog_INFO(TAG, "\tCB_CAN_LOCK_CLIPDATA");
|
||||||
|
|
||||||
|
WLog_INFO(TAG, "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s)
|
static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s)
|
||||||
@ -118,14 +116,10 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
|
|||||||
UINT32 version;
|
UINT32 version;
|
||||||
UINT32 generalFlags;
|
UINT32 generalFlags;
|
||||||
CliprdrClientContext* context;
|
CliprdrClientContext* context;
|
||||||
|
|
||||||
context = cliprdr_get_client_interface(cliprdr);
|
context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, version); /* version (4 bytes) */
|
Stream_Read_UINT32(s, version); /* version (4 bytes) */
|
||||||
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
|
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Version: %d", version);
|
DEBUG_CLIPRDR("Version: %d", version);
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_CLIPRDR
|
#ifdef WITH_DEBUG_CLIPRDR
|
||||||
cliprdr_print_general_capability_flags(generalFlags);
|
cliprdr_print_general_capability_flags(generalFlags);
|
||||||
#endif
|
#endif
|
||||||
@ -148,13 +142,10 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
|
|||||||
{
|
{
|
||||||
CLIPRDR_CAPABILITIES capabilities;
|
CLIPRDR_CAPABILITIES capabilities;
|
||||||
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
|
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
|
||||||
|
|
||||||
capabilities.cCapabilitiesSets = 1;
|
capabilities.cCapabilitiesSets = 1;
|
||||||
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet);
|
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet);
|
||||||
|
|
||||||
generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
|
generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
|
||||||
generalCapabilitySet.capabilitySetLength = 12;
|
generalCapabilitySet.capabilitySetLength = 12;
|
||||||
|
|
||||||
generalCapabilitySet.version = version;
|
generalCapabilitySet.version = version;
|
||||||
generalCapabilitySet.generalFlags = generalFlags;
|
generalCapabilitySet.generalFlags = generalFlags;
|
||||||
|
|
||||||
@ -164,10 +155,8 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
RDP_CB_CLIP_CAPS* caps_event;
|
RDP_CB_CLIP_CAPS* caps_event;
|
||||||
|
|
||||||
caps_event = (RDP_CB_CLIP_CAPS*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_ClipCaps, NULL, NULL);
|
caps_event = (RDP_CB_CLIP_CAPS*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_ClipCaps, NULL, NULL);
|
||||||
caps_event->capabilities = generalFlags;
|
caps_event->capabilities = generalFlags;
|
||||||
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) caps_event);
|
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) caps_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,11 +167,10 @@ static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16
|
|||||||
UINT16 lengthCapability;
|
UINT16 lengthCapability;
|
||||||
UINT16 cCapabilitiesSets;
|
UINT16 cCapabilitiesSets;
|
||||||
UINT16 capabilitySetType;
|
UINT16 capabilitySetType;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
|
Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
|
||||||
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
|
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
|
||||||
|
|
||||||
DEBUG_CLIPRDR("cCapabilitiesSets %d", cCapabilitiesSets);
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities");
|
||||||
|
|
||||||
for (i = 0; i < cCapabilitiesSets; i++)
|
for (i = 0; i < cCapabilitiesSets; i++)
|
||||||
{
|
{
|
||||||
@ -194,9 +182,8 @@ static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16
|
|||||||
case CB_CAPSTYPE_GENERAL:
|
case CB_CAPSTYPE_GENERAL:
|
||||||
cliprdr_process_general_capability(cliprdr, s);
|
cliprdr_process_general_capability(cliprdr, s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("unknown cliprdr capability set: %d", capabilitySetType);
|
WLog_ERR(TAG, "unknown cliprdr capability set: %d", capabilitySetType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,25 +193,20 @@ static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr)
|
|||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s;
|
||||||
UINT32 flags;
|
UINT32 flags;
|
||||||
|
|
||||||
s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
|
s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending Capabilities");
|
DEBUG_CLIPRDR("Sending Capabilities");
|
||||||
|
|
||||||
flags = CB_USE_LONG_FORMAT_NAMES
|
flags = CB_USE_LONG_FORMAT_NAMES
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
| CB_STREAM_FILECLIP_ENABLED
|
| CB_STREAM_FILECLIP_ENABLED
|
||||||
| CB_FILECLIP_NO_FILE_PATHS
|
| CB_FILECLIP_NO_FILE_PATHS
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
|
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
|
||||||
Stream_Write_UINT16(s, 0); /* pad1 */
|
Stream_Write_UINT16(s, 0); /* pad1 */
|
||||||
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL); /* capabilitySetType */
|
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL); /* capabilitySetType */
|
||||||
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability */
|
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability */
|
||||||
Stream_Write_UINT32(s, CB_CAPS_VERSION_2); /* version */
|
Stream_Write_UINT32(s, CB_CAPS_VERSION_2); /* version */
|
||||||
Stream_Write_UINT32(s, flags); /* generalFlags */
|
Stream_Write_UINT32(s, flags); /* generalFlags */
|
||||||
|
|
||||||
cliprdr_packet_send(cliprdr, s);
|
cliprdr_packet_send(cliprdr, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,10 +214,11 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI
|
|||||||
{
|
{
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "MonitorReady");
|
||||||
|
|
||||||
if (context->custom)
|
if (context->custom)
|
||||||
{
|
{
|
||||||
CLIPRDR_MONITOR_READY monitorReady;
|
CLIPRDR_MONITOR_READY monitorReady;
|
||||||
|
|
||||||
monitorReady.msgType = CB_MONITOR_READY;
|
monitorReady.msgType = CB_MONITOR_READY;
|
||||||
monitorReady.msgFlags = flags;
|
monitorReady.msgFlags = flags;
|
||||||
monitorReady.dataLen = length;
|
monitorReady.dataLen = length;
|
||||||
@ -251,7 +234,6 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI
|
|||||||
cliprdr_send_clip_caps(cliprdr);
|
cliprdr_send_clip_caps(cliprdr);
|
||||||
|
|
||||||
event = (RDP_CB_MONITOR_READY_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
|
event = (RDP_CB_MONITOR_READY_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
|
||||||
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) event);
|
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,8 +242,10 @@ static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream
|
|||||||
{
|
{
|
||||||
RDP_CB_FILECONTENTS_REQUEST_EVENT* cb_event;
|
RDP_CB_FILECONTENTS_REQUEST_EVENT* cb_event;
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsRequest");
|
||||||
|
|
||||||
cb_event = (RDP_CB_FILECONTENTS_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
cb_event = (RDP_CB_FILECONTENTS_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
||||||
CliprdrChannel_FilecontentsRequest, NULL, NULL);
|
CliprdrChannel_FilecontentsRequest, NULL, NULL);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, cb_event->streamId);
|
Stream_Read_UINT32(s, cb_event->streamId);
|
||||||
Stream_Read_UINT32(s, cb_event->lindex);
|
Stream_Read_UINT32(s, cb_event->lindex);
|
||||||
@ -270,7 +254,6 @@ static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream
|
|||||||
Stream_Read_UINT32(s, cb_event->nPositionHigh);
|
Stream_Read_UINT32(s, cb_event->nPositionHigh);
|
||||||
Stream_Read_UINT32(s, cb_event->cbRequested);
|
Stream_Read_UINT32(s, cb_event->cbRequested);
|
||||||
//Stream_Read_UINT32(s, cb_event->clipDataId);
|
//Stream_Read_UINT32(s, cb_event->clipDataId);
|
||||||
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,8 +261,10 @@ static void cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStrea
|
|||||||
{
|
{
|
||||||
RDP_CB_FILECONTENTS_RESPONSE_EVENT* cb_event;
|
RDP_CB_FILECONTENTS_RESPONSE_EVENT* cb_event;
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsResponse");
|
||||||
|
|
||||||
cb_event = (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
cb_event = (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
||||||
CliprdrChannel_FilecontentsResponse, NULL, NULL);
|
CliprdrChannel_FilecontentsResponse, NULL, NULL);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, cb_event->streamId);
|
Stream_Read_UINT32(s, cb_event->streamId);
|
||||||
|
|
||||||
@ -297,8 +282,10 @@ static void cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UI
|
|||||||
{
|
{
|
||||||
RDP_CB_LOCK_CLIPDATA_EVENT* cb_event;
|
RDP_CB_LOCK_CLIPDATA_EVENT* cb_event;
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "LockClipData");
|
||||||
|
|
||||||
cb_event = (RDP_CB_LOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
cb_event = (RDP_CB_LOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
||||||
CliprdrChannel_LockClipdata, NULL, NULL);
|
CliprdrChannel_LockClipdata, NULL, NULL);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, cb_event->clipDataId);
|
Stream_Read_UINT32(s, cb_event->clipDataId);
|
||||||
|
|
||||||
@ -309,8 +296,10 @@ static void cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s,
|
|||||||
{
|
{
|
||||||
RDP_CB_UNLOCK_CLIPDATA_EVENT* cb_event;
|
RDP_CB_UNLOCK_CLIPDATA_EVENT* cb_event;
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "UnlockClipData");
|
||||||
|
|
||||||
cb_event = (RDP_CB_UNLOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
cb_event = (RDP_CB_UNLOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
||||||
CliprdrChannel_UnLockClipdata, NULL, NULL);
|
CliprdrChannel_UnLockClipdata, NULL, NULL);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, cb_event->clipDataId);
|
Stream_Read_UINT32(s, cb_event->clipDataId);
|
||||||
|
|
||||||
@ -323,16 +312,14 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
|||||||
UINT16 msgFlags;
|
UINT16 msgFlags;
|
||||||
UINT32 dataLen;
|
UINT32 dataLen;
|
||||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) plugin;
|
cliprdrPlugin* cliprdr = (cliprdrPlugin*) plugin;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, msgType);
|
Stream_Read_UINT16(s, msgType);
|
||||||
Stream_Read_UINT16(s, msgFlags);
|
Stream_Read_UINT16(s, msgFlags);
|
||||||
Stream_Read_UINT32(s, dataLen);
|
Stream_Read_UINT32(s, dataLen);
|
||||||
|
|
||||||
DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d",
|
DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d",
|
||||||
CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen);
|
CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen);
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_CLIPRDR
|
#ifdef WITH_DEBUG_CLIPRDR
|
||||||
winpr_HexDump(Stream_Buffer(s), dataLen + 8);
|
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (msgType)
|
switch (msgType)
|
||||||
@ -340,56 +327,44 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
|||||||
case CB_CLIP_CAPS:
|
case CB_CLIP_CAPS:
|
||||||
cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_MONITOR_READY:
|
case CB_MONITOR_READY:
|
||||||
cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_FORMAT_LIST:
|
case CB_FORMAT_LIST:
|
||||||
cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_FORMAT_LIST_RESPONSE:
|
case CB_FORMAT_LIST_RESPONSE:
|
||||||
cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_FORMAT_DATA_REQUEST:
|
case CB_FORMAT_DATA_REQUEST:
|
||||||
cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_FORMAT_DATA_RESPONSE:
|
case CB_FORMAT_DATA_RESPONSE:
|
||||||
cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_FILECONTENTS_REQUEST:
|
case CB_FILECONTENTS_REQUEST:
|
||||||
cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_FILECONTENTS_RESPONSE:
|
case CB_FILECONTENTS_RESPONSE:
|
||||||
cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_LOCK_CLIPDATA:
|
case CB_LOCK_CLIPDATA:
|
||||||
cliprdr_process_lock_clipdata(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_lock_clipdata(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CB_UNLOCK_CLIPDATA:
|
case CB_UNLOCK_CLIPDATA:
|
||||||
cliprdr_process_unlock_clipdata(cliprdr, s, dataLen, msgFlags);
|
cliprdr_process_unlock_clipdata(cliprdr, s, dataLen, msgFlags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("unknown msgType %d", msgType);
|
WLog_ERR(TAG, "unknown msgType %d", msgType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_REQUEST_EVENT * event)
|
static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_REQUEST_EVENT* event)
|
||||||
{
|
{
|
||||||
wStream *s;
|
wStream* s;
|
||||||
DEBUG_CLIPRDR("Sending File Contents Request.");
|
DEBUG_CLIPRDR("Sending File Contents Request.");
|
||||||
|
|
||||||
s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 24);
|
s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 24);
|
||||||
|
|
||||||
Stream_Write_UINT32(s, event->streamId);
|
Stream_Write_UINT32(s, event->streamId);
|
||||||
Stream_Write_UINT32(s, event->lindex);
|
Stream_Write_UINT32(s, event->lindex);
|
||||||
Stream_Write_UINT32(s, event->dwFlags);
|
Stream_Write_UINT32(s, event->dwFlags);
|
||||||
@ -397,14 +372,12 @@ static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RD
|
|||||||
Stream_Write_UINT32(s, event->nPositionHigh);
|
Stream_Write_UINT32(s, event->nPositionHigh);
|
||||||
Stream_Write_UINT32(s, event->cbRequested);
|
Stream_Write_UINT32(s, event->cbRequested);
|
||||||
//Stream_Write_UINT32(s, event->clipDataId);
|
//Stream_Write_UINT32(s, event->clipDataId);
|
||||||
|
|
||||||
cliprdr_packet_send(plugin, s);
|
cliprdr_packet_send(plugin, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cliprdr_process_filecontents_response_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_RESPONSE_EVENT * event)
|
static void cliprdr_process_filecontents_response_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_RESPONSE_EVENT* event)
|
||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s;
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending file contents response with size = %d", event->size);
|
DEBUG_CLIPRDR("Sending file contents response with size = %d", event->size);
|
||||||
|
|
||||||
if (event->size > 0)
|
if (event->size > 0)
|
||||||
@ -421,39 +394,30 @@ static void cliprdr_process_filecontents_response_event(cliprdrPlugin* plugin, R
|
|||||||
cliprdr_packet_send(plugin, s);
|
cliprdr_packet_send(plugin, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cliprdr_process_lock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_LOCK_CLIPDATA_EVENT * event)
|
static void cliprdr_process_lock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_LOCK_CLIPDATA_EVENT* event)
|
||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s;
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending Lock Request");
|
DEBUG_CLIPRDR("Sending Lock Request");
|
||||||
|
|
||||||
s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4);
|
s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4);
|
||||||
Stream_Write_UINT32(s, event->clipDataId);
|
Stream_Write_UINT32(s, event->clipDataId);
|
||||||
|
|
||||||
cliprdr_packet_send(plugin, s);
|
cliprdr_packet_send(plugin, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cliprdr_process_unlock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_UNLOCK_CLIPDATA_EVENT * event)
|
static void cliprdr_process_unlock_clipdata_event(cliprdrPlugin* plugin, RDP_CB_UNLOCK_CLIPDATA_EVENT* event)
|
||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s;
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending UnLock Request");
|
DEBUG_CLIPRDR("Sending UnLock Request");
|
||||||
|
|
||||||
s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4);
|
s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4);
|
||||||
Stream_Write_UINT32(s, event->clipDataId);
|
Stream_Write_UINT32(s, event->clipDataId);
|
||||||
|
|
||||||
cliprdr_packet_send(plugin, s);
|
cliprdr_packet_send(plugin, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cliprdr_process_tempdir_event(cliprdrPlugin* plugin, RDP_CB_TEMPDIR_EVENT * event)
|
static void cliprdr_process_tempdir_event(cliprdrPlugin* plugin, RDP_CB_TEMPDIR_EVENT* event)
|
||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s;
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending Temporary Directory.");
|
DEBUG_CLIPRDR("Sending Temporary Directory.");
|
||||||
s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, 520);
|
s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, 520);
|
||||||
|
|
||||||
Stream_Write(s, event->dirname, 520);
|
Stream_Write(s, event->dirname, 520);
|
||||||
|
|
||||||
cliprdr_packet_send(plugin, s);
|
cliprdr_packet_send(plugin, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,37 +428,29 @@ static void cliprdr_process_event(rdpSvcPlugin* plugin, wMessage* event)
|
|||||||
case CliprdrChannel_FormatList:
|
case CliprdrChannel_FormatList:
|
||||||
cliprdr_process_format_list_event((cliprdrPlugin*) plugin, (RDP_CB_FORMAT_LIST_EVENT*) event);
|
cliprdr_process_format_list_event((cliprdrPlugin*) plugin, (RDP_CB_FORMAT_LIST_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_DataRequest:
|
case CliprdrChannel_DataRequest:
|
||||||
cliprdr_process_format_data_request_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_REQUEST_EVENT*) event);
|
cliprdr_process_format_data_request_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_REQUEST_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_DataResponse:
|
case CliprdrChannel_DataResponse:
|
||||||
cliprdr_process_format_data_response_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_RESPONSE_EVENT*) event);
|
cliprdr_process_format_data_response_event((cliprdrPlugin*) plugin, (RDP_CB_DATA_RESPONSE_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_FilecontentsRequest:
|
case CliprdrChannel_FilecontentsRequest:
|
||||||
cliprdr_process_filecontents_request_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_REQUEST_EVENT *) event);
|
cliprdr_process_filecontents_request_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_REQUEST_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_FilecontentsResponse:
|
case CliprdrChannel_FilecontentsResponse:
|
||||||
cliprdr_process_filecontents_response_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_RESPONSE_EVENT *) event);
|
cliprdr_process_filecontents_response_event((cliprdrPlugin*) plugin, (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_LockClipdata:
|
case CliprdrChannel_LockClipdata:
|
||||||
cliprdr_process_lock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_LOCK_CLIPDATA_EVENT *) event);
|
cliprdr_process_lock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_LOCK_CLIPDATA_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_UnLockClipdata:
|
case CliprdrChannel_UnLockClipdata:
|
||||||
cliprdr_process_unlock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_UNLOCK_CLIPDATA_EVENT *) event);
|
cliprdr_process_unlock_clipdata_event((cliprdrPlugin*) plugin, (RDP_CB_UNLOCK_CLIPDATA_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CliprdrChannel_TemporaryDirectory:
|
case CliprdrChannel_TemporaryDirectory:
|
||||||
cliprdr_process_tempdir_event((cliprdrPlugin*) plugin, (RDP_CB_TEMPDIR_EVENT *) event);
|
cliprdr_process_tempdir_event((cliprdrPlugin*) plugin, (RDP_CB_TEMPDIR_EVENT*) event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("unknown event type %d", GetMessageType(event->id));
|
WLog_ERR(TAG, "unknown event type %d", GetMessageType(event->id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,12 +479,12 @@ int cliprdr_client_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILIT
|
|||||||
Stream_Write_UINT16(s, 0); /* pad1 */
|
Stream_Write_UINT16(s, 0); /* pad1 */
|
||||||
|
|
||||||
generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilities->capabilitySets;
|
generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilities->capabilitySets;
|
||||||
|
|
||||||
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */
|
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */
|
||||||
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */
|
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */
|
||||||
Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */
|
Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */
|
||||||
Stream_Write_UINT32(s, generalCapabilitySet->generalFlags); /* generalFlags */
|
Stream_Write_UINT32(s, generalCapabilitySet->generalFlags); /* generalFlags */
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientCapabilities");
|
||||||
cliprdr_packet_send(cliprdr, s);
|
cliprdr_packet_send(cliprdr, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -543,12 +499,10 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS
|
|||||||
CLIPRDR_FORMAT* format;
|
CLIPRDR_FORMAT* format;
|
||||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||||
|
|
||||||
for (index = 0; index < formatList->cFormats; index++)
|
for (index = 0; index < formatList->numFormats; index++)
|
||||||
{
|
{
|
||||||
format = (CLIPRDR_FORMAT*) &(formatList->formats[index]);
|
format = (CLIPRDR_FORMAT*) &(formatList->formats[index]);
|
||||||
|
|
||||||
length += 4;
|
length += 4;
|
||||||
|
|
||||||
formatNameSize = 2;
|
formatNameSize = 2;
|
||||||
|
|
||||||
if (format->formatName)
|
if (format->formatName)
|
||||||
@ -559,23 +513,19 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS
|
|||||||
|
|
||||||
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length);
|
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length);
|
||||||
|
|
||||||
for (index = 0; index < formatList->cFormats; index++)
|
for (index = 0; index < formatList->numFormats; index++)
|
||||||
{
|
{
|
||||||
format = (CLIPRDR_FORMAT*) &(formatList->formats[index]);
|
format = (CLIPRDR_FORMAT*) &(formatList->formats[index]);
|
||||||
|
|
||||||
Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */
|
Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */
|
||||||
|
|
||||||
if (format->formatName)
|
if (format->formatName)
|
||||||
{
|
{
|
||||||
int cchWideChar;
|
int cchWideChar;
|
||||||
LPWSTR lpWideCharStr;
|
LPWSTR lpWideCharStr;
|
||||||
|
|
||||||
lpWideCharStr = (LPWSTR) Stream_Pointer(s);
|
lpWideCharStr = (LPWSTR) Stream_Pointer(s);
|
||||||
cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2;
|
cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2;
|
||||||
|
|
||||||
formatNameSize = MultiByteToWideChar(CP_UTF8, 0,
|
formatNameSize = MultiByteToWideChar(CP_UTF8, 0,
|
||||||
format->formatName, -1, lpWideCharStr, cchWideChar) * 2;
|
format->formatName, -1, lpWideCharStr, cchWideChar) * 2;
|
||||||
|
|
||||||
Stream_Seek(s, formatNameSize);
|
Stream_Seek(s, formatNameSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -584,6 +534,8 @@ int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %d",
|
||||||
|
formatList->numFormats);
|
||||||
cliprdr_packet_send(cliprdr, s);
|
cliprdr_packet_send(cliprdr, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -598,6 +550,8 @@ int cliprdr_client_format_list_response(CliprdrClientContext* context, CLIPRDR_F
|
|||||||
formatListResponse->dataLen = 0;
|
formatListResponse->dataLen = 0;
|
||||||
|
|
||||||
s = cliprdr_packet_new(formatListResponse->msgType, formatListResponse->msgFlags, formatListResponse->dataLen);
|
s = cliprdr_packet_new(formatListResponse->msgType, formatListResponse->msgFlags, formatListResponse->dataLen);
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatListResponse");
|
||||||
cliprdr_packet_send(cliprdr, s);
|
cliprdr_packet_send(cliprdr, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -615,6 +569,7 @@ int cliprdr_client_format_data_request(CliprdrClientContext* context, CLIPRDR_FO
|
|||||||
s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags, formatDataRequest->dataLen);
|
s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags, formatDataRequest->dataLen);
|
||||||
Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
|
Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataRequest");
|
||||||
cliprdr_packet_send(cliprdr, s);
|
cliprdr_packet_send(cliprdr, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -628,8 +583,10 @@ int cliprdr_client_format_data_response(CliprdrClientContext* context, CLIPRDR_F
|
|||||||
formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE;
|
formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE;
|
||||||
|
|
||||||
s = cliprdr_packet_new(formatDataResponse->msgType, formatDataResponse->msgFlags, formatDataResponse->dataLen);
|
s = cliprdr_packet_new(formatDataResponse->msgType, formatDataResponse->msgFlags, formatDataResponse->dataLen);
|
||||||
|
|
||||||
Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
|
Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
|
||||||
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataResponse");
|
||||||
cliprdr_packet_send(cliprdr, s);
|
cliprdr_packet_send(cliprdr, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -647,13 +604,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
|||||||
cliprdr = (cliprdrPlugin*) calloc(1, sizeof(cliprdrPlugin));
|
cliprdr = (cliprdrPlugin*) calloc(1, sizeof(cliprdrPlugin));
|
||||||
|
|
||||||
cliprdr->plugin.channel_def.options =
|
cliprdr->plugin.channel_def.options =
|
||||||
CHANNEL_OPTION_INITIALIZED |
|
CHANNEL_OPTION_INITIALIZED |
|
||||||
CHANNEL_OPTION_ENCRYPT_RDP |
|
CHANNEL_OPTION_ENCRYPT_RDP |
|
||||||
CHANNEL_OPTION_COMPRESS_RDP |
|
CHANNEL_OPTION_COMPRESS_RDP |
|
||||||
CHANNEL_OPTION_SHOW_PROTOCOL;
|
CHANNEL_OPTION_SHOW_PROTOCOL;
|
||||||
|
|
||||||
strcpy(cliprdr->plugin.channel_def.name, "cliprdr");
|
strcpy(cliprdr->plugin.channel_def.name, "cliprdr");
|
||||||
|
|
||||||
|
cliprdr->log = WLog_Get("com.freerdp.channels.cliprdr.client");
|
||||||
|
|
||||||
cliprdr->plugin.connect_callback = cliprdr_process_connect;
|
cliprdr->plugin.connect_callback = cliprdr_process_connect;
|
||||||
cliprdr->plugin.receive_callback = cliprdr_process_receive;
|
cliprdr->plugin.receive_callback = cliprdr_process_receive;
|
||||||
cliprdr->plugin.event_callback = cliprdr_process_event;
|
cliprdr->plugin.event_callback = cliprdr_process_event;
|
||||||
@ -665,19 +624,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
|||||||
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
||||||
{
|
{
|
||||||
context = (CliprdrClientContext*) calloc(1, sizeof(CliprdrClientContext));
|
context = (CliprdrClientContext*) calloc(1, sizeof(CliprdrClientContext));
|
||||||
|
|
||||||
context->handle = (void*) cliprdr;
|
context->handle = (void*) cliprdr;
|
||||||
|
|
||||||
context->ClientCapabilities = cliprdr_client_capabilities;
|
context->ClientCapabilities = cliprdr_client_capabilities;
|
||||||
context->ClientFormatList = cliprdr_client_format_list;
|
context->ClientFormatList = cliprdr_client_format_list;
|
||||||
context->ClientFormatListResponse = cliprdr_client_format_list_response;
|
context->ClientFormatListResponse = cliprdr_client_format_list_response;
|
||||||
context->ClientFormatDataRequest = cliprdr_client_format_data_request;
|
context->ClientFormatDataRequest = cliprdr_client_format_data_request;
|
||||||
context->ClientFormatDataResponse = cliprdr_client_format_data_response;
|
context->ClientFormatDataResponse = cliprdr_client_format_data_response;
|
||||||
|
|
||||||
*(pEntryPointsEx->ppInterface) = (void*) context;
|
*(pEntryPointsEx->ppInterface) = (void*) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_plugin_init((rdpSvcPlugin*) cliprdr, pEntryPoints);
|
svc_plugin_init((rdpSvcPlugin*) cliprdr, pEntryPoints);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,16 @@
|
|||||||
|
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
#include <freerdp/utils/svc_plugin.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("cliprdr.client")
|
||||||
|
|
||||||
struct cliprdr_plugin
|
struct cliprdr_plugin
|
||||||
{
|
{
|
||||||
rdpSvcPlugin plugin;
|
rdpSvcPlugin plugin;
|
||||||
|
|
||||||
|
wLog* log;
|
||||||
BOOL received_caps;
|
BOOL received_caps;
|
||||||
BOOL use_long_format_names;
|
BOOL use_long_format_names;
|
||||||
BOOL stream_fileclip_enabled;
|
BOOL stream_fileclip_enabled;
|
||||||
@ -45,9 +49,9 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* data_out);
|
|||||||
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
|
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_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
|
#else
|
||||||
#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
#define DEBUG_CLIPRDR(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __CLIPRDR_MAIN_H */
|
#endif /* __CLIPRDR_MAIN_H */
|
||||||
|
@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <winpr/print.h>
|
#include <winpr/print.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include "cliprdr_main.h"
|
#include "cliprdr_main.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,9 +70,7 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
|
|||||||
UINT32 generalFlags;
|
UINT32 generalFlags;
|
||||||
CLIPRDR_HEADER header;
|
CLIPRDR_HEADER header;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "CliprdrServerSendCapabilities");
|
||||||
printf("CliprdrServerSendCapabilities\n");
|
|
||||||
|
|
||||||
header.msgType = CB_CLIP_CAPS;
|
header.msgType = CB_CLIP_CAPS;
|
||||||
header.msgFlags = 0;
|
header.msgFlags = 0;
|
||||||
header.dataLen = 16;
|
header.dataLen = 16;
|
||||||
@ -110,9 +109,7 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
|
|||||||
BOOL status;
|
BOOL status;
|
||||||
CLIPRDR_HEADER header;
|
CLIPRDR_HEADER header;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "CliprdrServerSendMonitorReady");
|
||||||
printf("CliprdrServerSendMonitorReady\n");
|
|
||||||
|
|
||||||
header.msgType = CB_MONITOR_READY;
|
header.msgType = CB_MONITOR_READY;
|
||||||
header.msgFlags = 0;
|
header.msgFlags = 0;
|
||||||
header.dataLen = 0;
|
header.dataLen = 0;
|
||||||
@ -138,9 +135,7 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
|
|||||||
BOOL status;
|
BOOL status;
|
||||||
CLIPRDR_HEADER header;
|
CLIPRDR_HEADER header;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "CliprdrServerSendFormatListResponse");
|
||||||
printf("CliprdrServerSendFormatListResponse\n");
|
|
||||||
|
|
||||||
header.msgType = CB_FORMAT_LIST_RESPONSE;
|
header.msgType = CB_FORMAT_LIST_RESPONSE;
|
||||||
header.msgFlags = CB_RESPONSE_OK;
|
header.msgFlags = CB_RESPONSE_OK;
|
||||||
header.dataLen = 0;
|
header.dataLen = 0;
|
||||||
@ -205,10 +200,8 @@ static int cliprdr_server_receive_temporary_directory(CliprdrServerContext* cont
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1,
|
ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1,
|
||||||
&(context->priv->ClientTemporaryDirectory), 0, NULL, NULL);
|
&(context->priv->ClientTemporaryDirectory), 0, NULL, NULL);
|
||||||
|
WLog_DBG(TAG, "ClientTemporaryDirectory: %s", context->priv->ClientTemporaryDirectory);
|
||||||
printf("ClientTemporaryDirectory: %s\n", context->priv->ClientTemporaryDirectory);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,9 +244,7 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context
|
|||||||
WCHAR* end;
|
WCHAR* end;
|
||||||
int length;
|
int length;
|
||||||
int position;
|
int position;
|
||||||
|
WLog_DBG(TAG, "");
|
||||||
printf("%s\n", __FUNCTION__);
|
|
||||||
|
|
||||||
position = Stream_GetPosition(s);
|
position = Stream_GetPosition(s);
|
||||||
Stream_SetPosition(s, Stream_Length(s));
|
Stream_SetPosition(s, Stream_Length(s));
|
||||||
end = (WCHAR*) Stream_Pointer(s);
|
end = (WCHAR*) Stream_Pointer(s);
|
||||||
@ -305,10 +296,10 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context
|
|||||||
|
|
||||||
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
|
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
|
||||||
{
|
{
|
||||||
printf("Format %d: Id: 0x%04X Name: %s Length: %d\n", i,
|
WLog_DBG(TAG, "Format %d: Id: 0x%04X Name: %s Length: %d", i,
|
||||||
context->priv->ClientFormatNames[i].id,
|
context->priv->ClientFormatNames[i].id,
|
||||||
context->priv->ClientFormatNames[i].name,
|
context->priv->ClientFormatNames[i].name,
|
||||||
context->priv->ClientFormatNames[i].length);
|
context->priv->ClientFormatNames[i].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -316,7 +307,7 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context
|
|||||||
|
|
||||||
static int cliprdr_server_receive_short_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
static int cliprdr_server_receive_short_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||||
{
|
{
|
||||||
printf("%s: unimplemented\n", __FUNCTION__);
|
WLog_ERR(TAG, "%s: unimplemented");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,8 +331,8 @@ static int cliprdr_server_receive_format_list(CliprdrServerContext* context, wSt
|
|||||||
|
|
||||||
static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||||
{
|
{
|
||||||
printf("CliprdrServerReceivePdu: msgType: %d msgFlags: 0x%08X dataLen: %d\n",
|
WLog_DBG(TAG, "CliprdrServerReceivePdu: msgType: %d msgFlags: 0x%08X dataLen: %d",
|
||||||
header->msgType, header->msgFlags, header->dataLen);
|
header->msgType, header->msgFlags, header->dataLen);
|
||||||
|
|
||||||
switch (header->msgType)
|
switch (header->msgType)
|
||||||
{
|
{
|
||||||
@ -379,7 +370,7 @@ static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("Unexpected clipboard PDU type: %d\n", header->msgType);
|
WLog_DBG(TAG, "Unexpected clipboard PDU type: %d", header->msgType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,15 +422,14 @@ static void* cliprdr_server_thread(void* arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned);
|
||||||
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &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)
|
break;
|
||||||
Stream_Seek(s, BytesReturned);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH)
|
if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH)
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
#include <winpr/thread.h>
|
#include <winpr/thread.h>
|
||||||
|
|
||||||
#include <freerdp/server/cliprdr.h>
|
#include <freerdp/server/cliprdr.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("cliprdr.server")
|
||||||
#define CLIPRDR_HEADER_LENGTH 8
|
#define CLIPRDR_HEADER_LENGTH 8
|
||||||
|
|
||||||
struct _cliprdr_server_private
|
struct _cliprdr_server_private
|
||||||
|
@ -27,15 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
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} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@ struct _DISP_PLUGIN
|
|||||||
DISP_LISTENER_CALLBACK* listener_callback;
|
DISP_LISTENER_CALLBACK* listener_callback;
|
||||||
|
|
||||||
UINT32 MaxNumMonitors;
|
UINT32 MaxNumMonitors;
|
||||||
UINT32 MaxMonitorWidth;
|
UINT32 MaxMonitorAreaFactorA;
|
||||||
UINT32 MaxMonitorHeight;
|
UINT32 MaxMonitorAreaFactorB;
|
||||||
};
|
};
|
||||||
typedef struct _DISP_PLUGIN DISP_PLUGIN;
|
typedef struct _DISP_PLUGIN DISP_PLUGIN;
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
|||||||
|
|
||||||
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
|
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++)
|
for (index = 0; index < NumMonitors; index++)
|
||||||
{
|
{
|
||||||
@ -110,14 +110,17 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
|||||||
if (Monitors[index].Width < 200)
|
if (Monitors[index].Width < 200)
|
||||||
Monitors[index].Width = 200;
|
Monitors[index].Width = 200;
|
||||||
|
|
||||||
if (Monitors[index].Width > disp->MaxMonitorWidth)
|
if (Monitors[index].Width > 8192)
|
||||||
Monitors[index].Width = disp->MaxMonitorWidth;
|
Monitors[index].Width = 8192;
|
||||||
|
|
||||||
|
if (Monitors[index].Width % 2)
|
||||||
|
Monitors[index].Width++;
|
||||||
|
|
||||||
if (Monitors[index].Height < 200)
|
if (Monitors[index].Height < 200)
|
||||||
Monitors[index].Height = 200;
|
Monitors[index].Height = 200;
|
||||||
|
|
||||||
if (Monitors[index].Height > disp->MaxMonitorHeight)
|
if (Monitors[index].Height > 8192)
|
||||||
Monitors[index].Height = disp->MaxMonitorHeight;
|
Monitors[index].Height = 8192;
|
||||||
|
|
||||||
Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */
|
Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */
|
||||||
Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */
|
Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */
|
||||||
@ -127,20 +130,19 @@ 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].PhysicalWidth); /* PhysicalWidth (4 bytes) */
|
||||||
Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */
|
Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */
|
||||||
Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (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
|
|
||||||
|
|
||||||
Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
|
Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
|
||||||
Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (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
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_SealLength(s);
|
Stream_SealLength(s);
|
||||||
@ -158,11 +160,13 @@ int disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream*
|
|||||||
|
|
||||||
disp = (DISP_PLUGIN*) callback->plugin;
|
disp = (DISP_PLUGIN*) callback->plugin;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */
|
if (Stream_GetRemainingLength(s) < 12)
|
||||||
Stream_Read_UINT32(s, disp->MaxMonitorWidth); /* MaxMonitorWidth (4 bytes) */
|
return -1;
|
||||||
Stream_Read_UINT32(s, disp->MaxMonitorHeight); /* MaxMonitorHeight (4 bytes) */
|
|
||||||
|
|
||||||
//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);
|
// disp->MaxNumMonitors, disp->MaxMonitorWidth, disp->MaxMonitorHeight);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -173,10 +177,13 @@ int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
UINT32 type;
|
UINT32 type;
|
||||||
UINT32 length;
|
UINT32 length;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, type); /* Type (4 bytes) */
|
Stream_Read_UINT32(s, type); /* Type (4 bytes) */
|
||||||
Stream_Read_UINT32(s, length); /* Length (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)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -220,8 +227,10 @@ static int disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallbac
|
|||||||
DISP_CHANNEL_CALLBACK* callback;
|
DISP_CHANNEL_CALLBACK* callback;
|
||||||
DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback;
|
DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback;
|
||||||
|
|
||||||
callback = (DISP_CHANNEL_CALLBACK*) malloc(sizeof(DISP_CHANNEL_CALLBACK));
|
callback = (DISP_CHANNEL_CALLBACK*) calloc(1, sizeof(DISP_CHANNEL_CALLBACK));
|
||||||
ZeroMemory(callback, sizeof(DISP_CHANNEL_CALLBACK));
|
|
||||||
|
if (!callback)
|
||||||
|
return -1;
|
||||||
|
|
||||||
callback->iface.OnDataReceived = disp_on_data_received;
|
callback->iface.OnDataReceived = disp_on_data_received;
|
||||||
callback->iface.OnClose = disp_on_close;
|
callback->iface.OnClose = disp_on_close;
|
||||||
@ -240,8 +249,10 @@ static int disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager
|
|||||||
int status;
|
int status;
|
||||||
DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin;
|
DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin;
|
||||||
|
|
||||||
disp->listener_callback = (DISP_LISTENER_CALLBACK*) malloc(sizeof(DISP_LISTENER_CALLBACK));
|
disp->listener_callback = (DISP_LISTENER_CALLBACK*) calloc(1, sizeof(DISP_LISTENER_CALLBACK));
|
||||||
ZeroMemory(disp->listener_callback, sizeof(DISP_LISTENER_CALLBACK));
|
|
||||||
|
if (!disp->listener_callback)
|
||||||
|
return -1;
|
||||||
|
|
||||||
disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection;
|
disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection;
|
||||||
disp->listener_callback->plugin = pPlugin;
|
disp->listener_callback->plugin = pPlugin;
|
||||||
@ -281,11 +292,7 @@ int disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, DIS
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STATIC_CHANNELS
|
int disp_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
#define DVCPluginEntry disp_DVCPluginEntry
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
DISP_PLUGIN* disp;
|
DISP_PLUGIN* disp;
|
||||||
@ -317,8 +324,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||||||
disp->iface.pInterface = (void*) context;
|
disp->iface.pInterface = (void*) context;
|
||||||
|
|
||||||
disp->MaxNumMonitors = 16;
|
disp->MaxNumMonitors = 16;
|
||||||
disp->MaxMonitorWidth = 8192;
|
disp->MaxMonitorAreaFactorA = 8192;
|
||||||
disp->MaxMonitorHeight = 8192;
|
disp->MaxMonitorAreaFactorB = 8192;
|
||||||
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
|
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,12 @@
|
|||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include <freerdp/client/disp.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_MONITOR_LAYOUT 0x00000002
|
||||||
#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000003
|
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */
|
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */
|
||||||
|
|
||||||
|
@ -28,16 +28,6 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
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)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
||||||
|
@ -130,7 +130,7 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UIN
|
|||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
drdynvc->channel_error = status;
|
drdynvc->channel_error = status;
|
||||||
DEBUG_WARN("VirtualChannelWrite failed %d", status);
|
WLog_ERR(TAG, "VirtualChannelWrite failed %d", status);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ int drdynvc_push_event(drdynvcPlugin* drdynvc, wMessage* event)
|
|||||||
|
|
||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("pVirtualChannelEventPush failed %d", status);
|
WLog_ERR(TAG, "pVirtualChannelEventPush failed %d", status);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ static int drdynvc_send_capability_response(drdynvcPlugin* drdynvc)
|
|||||||
|
|
||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("VirtualChannelWrite failed %d", status);
|
WLog_ERR(TAG, "VirtualChannelWrite failed %d", status);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cb
|
|||||||
|
|
||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("VirtualChannelWrite failed %d", status);
|
WLog_ERR(TAG, "VirtualChannelWrite failed %d", status);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +329,7 @@ static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbC
|
|||||||
|
|
||||||
if (error != CHANNEL_RC_OK)
|
if (error != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("VirtualChannelWrite failed %d", error);
|
WLog_ERR(TAG, "VirtualChannelWrite failed %d", error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ static void drdynvc_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
|
WLog_ERR(TAG, "unknown drdynvc cmd 0x%x", Cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,7 +398,7 @@ static void drdynvc_process_connect(rdpSvcPlugin* plugin)
|
|||||||
for (index = 0; index < settings->DynamicChannelCount; index++)
|
for (index = 0; index < settings->DynamicChannelCount; index++)
|
||||||
{
|
{
|
||||||
args = settings->DynamicChannelArray[index];
|
args = settings->DynamicChannelArray[index];
|
||||||
dvcman_load_addin(drdynvc->channel_mgr, args);
|
dvcman_load_addin(drdynvc->channel_mgr, args, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
dvcman_init(drdynvc->channel_mgr);
|
dvcman_init(drdynvc->channel_mgr);
|
||||||
|
@ -26,12 +26,13 @@
|
|||||||
|
|
||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("dvcman.client")
|
||||||
#ifdef WITH_DEBUG_DVC
|
#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
|
#else
|
||||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
#define DEBUG_DVC(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -71,7 +71,7 @@ static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_WARN("Maximum DVC listener number reached.");
|
WLog_WARN(TAG, "Maximum DVC listener number reached.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* p
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_WARN("event_type %d push failed.", GetMessageType(pEvent->id));
|
WLog_ERR(TAG, "event_type %d push failed.", GetMessageType(pEvent->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -108,7 +108,7 @@ static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const cha
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_WARN("Maximum DVC plugin number reached.");
|
WLog_WARN(TAG, "Maximum DVC plugin number reached.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,6 +135,11 @@ ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||||||
return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args;
|
return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* dvcman_get_rdp_settings(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
|
{
|
||||||
|
return (void*) ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->settings;
|
||||||
|
}
|
||||||
|
|
||||||
UINT32 dvcman_get_channel_id(IWTSVirtualChannel * channel)
|
UINT32 dvcman_get_channel_id(IWTSVirtualChannel * channel)
|
||||||
{
|
{
|
||||||
return ((DVCMAN_CHANNEL*) channel)->channel_id;
|
return ((DVCMAN_CHANNEL*) channel)->channel_id;
|
||||||
@ -208,13 +213,11 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
|||||||
return (IWTSVirtualChannelManager*) dvcman;
|
return (IWTSVirtualChannelManager*) dvcman;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args)
|
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, rdpSettings* settings)
|
||||||
{
|
{
|
||||||
DVCMAN_ENTRY_POINTS entryPoints;
|
DVCMAN_ENTRY_POINTS entryPoints;
|
||||||
PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
|
PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
|
||||||
|
WLog_INFO(TAG, "Loading Dynamic Virtual Channel %s", args->argv[0]);
|
||||||
fprintf(stderr, "Loading Dynamic Virtual Channel %s\n", args->argv[0]);
|
|
||||||
|
|
||||||
pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(args->argv[0],
|
pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(args->argv[0],
|
||||||
NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC);
|
NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC);
|
||||||
|
|
||||||
@ -223,8 +226,10 @@ int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args)
|
|||||||
entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
|
entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
|
||||||
entryPoints.iface.GetPlugin = dvcman_get_plugin;
|
entryPoints.iface.GetPlugin = dvcman_get_plugin;
|
||||||
entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
|
entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
|
||||||
|
entryPoints.iface.GetRdpSettings = dvcman_get_rdp_settings;
|
||||||
entryPoints.dvcman = (DVCMAN*) pChannelMgr;
|
entryPoints.dvcman = (DVCMAN*) pChannelMgr;
|
||||||
entryPoints.args = args;
|
entryPoints.args = args;
|
||||||
|
entryPoints.settings = settings;
|
||||||
|
|
||||||
pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints);
|
pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints);
|
||||||
}
|
}
|
||||||
@ -381,8 +386,7 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_WARN("channel rejected by plugin");
|
WLog_ERR(TAG, "channel rejected by plugin");
|
||||||
|
|
||||||
free(channel);
|
free(channel);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -402,14 +406,15 @@ int dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId
|
|||||||
|
|
||||||
if (!channel)
|
if (!channel)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
WLog_ERR(TAG, "ChannelId %d not found!", ChannelId);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel->status == 0)
|
if (channel->status == 0)
|
||||||
{
|
{
|
||||||
pCallback = channel->channel_callback;
|
pCallback = channel->channel_callback;
|
||||||
pCallback->OnOpen(pCallback);
|
if (pCallback->OnOpen)
|
||||||
|
pCallback->OnOpen(pCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -426,7 +431,7 @@ int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelI
|
|||||||
|
|
||||||
if (!channel)
|
if (!channel)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
WLog_ERR(TAG, "ChannelId %d not found!", ChannelId);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +465,7 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI
|
|||||||
|
|
||||||
if (!channel)
|
if (!channel)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
WLog_ERR(TAG, "ChannelId %d not found!", ChannelId);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +473,7 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI
|
|||||||
Stream_Release(channel->dvc_data);
|
Stream_Release(channel->dvc_data);
|
||||||
|
|
||||||
channel->dvc_data = StreamPool_Take(channel->dvcman->pool, length);
|
channel->dvc_data = StreamPool_Take(channel->dvcman->pool, length);
|
||||||
Stream_AddRef(channel->dvc_data);
|
channel->dvc_data_length = length;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -483,7 +488,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C
|
|||||||
|
|
||||||
if (!channel)
|
if (!channel)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
WLog_ERR(TAG, "ChannelId %d not found!", ChannelId);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,7 +497,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C
|
|||||||
/* Fragmented data */
|
/* Fragmented data */
|
||||||
if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(channel->dvc_data))
|
if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(channel->dvc_data))
|
||||||
{
|
{
|
||||||
DEBUG_WARN("data exceeding declared length!");
|
WLog_ERR(TAG, "data exceeding declared length!");
|
||||||
Stream_Release(channel->dvc_data);
|
Stream_Release(channel->dvc_data);
|
||||||
channel->dvc_data = NULL;
|
channel->dvc_data = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
@ -500,7 +505,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C
|
|||||||
|
|
||||||
Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize);
|
Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize);
|
||||||
|
|
||||||
if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data))
|
if (((size_t) Stream_GetPosition(channel->dvc_data)) >= channel->dvc_data_length)
|
||||||
{
|
{
|
||||||
Stream_SealLength(channel->dvc_data);
|
Stream_SealLength(channel->dvc_data);
|
||||||
Stream_SetPosition(channel->dvc_data, 0);
|
Stream_SetPosition(channel->dvc_data, 0);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
|
#include <freerdp/settings.h>
|
||||||
|
|
||||||
#include <winpr/synch.h>
|
#include <winpr/synch.h>
|
||||||
#include <winpr/collections.h>
|
#include <winpr/collections.h>
|
||||||
@ -65,6 +66,7 @@ struct _DVCMAN_ENTRY_POINTS
|
|||||||
|
|
||||||
DVCMAN* dvcman;
|
DVCMAN* dvcman;
|
||||||
ADDIN_ARGV* args;
|
ADDIN_ARGV* args;
|
||||||
|
rdpSettings* settings;
|
||||||
};
|
};
|
||||||
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
|
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
|
||||||
|
|
||||||
@ -80,12 +82,13 @@ struct _DVCMAN_CHANNEL
|
|||||||
IWTSVirtualChannelCallback* channel_callback;
|
IWTSVirtualChannelCallback* channel_callback;
|
||||||
|
|
||||||
wStream* dvc_data;
|
wStream* dvc_data;
|
||||||
|
UINT32 dvc_data_length;
|
||||||
CRITICAL_SECTION lock;
|
CRITICAL_SECTION lock;
|
||||||
};
|
};
|
||||||
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
|
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
|
||||||
|
|
||||||
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin);
|
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin);
|
||||||
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args);
|
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args, rdpSettings* settings);
|
||||||
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
|
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
|
||||||
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
|
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
|
||||||
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName);
|
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName);
|
||||||
|
@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -67,15 +67,14 @@ static void* drdynvc_server_thread(void* arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned);
|
||||||
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &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)
|
break;
|
||||||
Stream_Seek(s, BytesReturned);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,17 +33,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
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})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -49,7 +49,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FCNTL_H
|
#ifdef HAVE_FCNTL_H
|
||||||
|
#define __USE_GNU /* for O_PATH */
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#undef __USE_GNU
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma comment(lib, "Shlwapi.lib")
|
||||||
|
#include <Shlwapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "drive_file.h"
|
#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)
|
if (STAT(file->fullpath, &st) == 0)
|
||||||
{
|
{
|
||||||
file->is_dir = (S_ISDIR(st.st_mode) ? TRUE : FALSE);
|
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
|
#ifndef WIN32
|
||||||
if (st.st_size > (unsigned long) 0x07FFFFFFF)
|
if (st.st_size > (unsigned long) 0x07FFFFFFF)
|
||||||
largeFile = TRUE;
|
largeFile = TRUE;
|
||||||
@ -301,6 +313,25 @@ DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id,
|
|||||||
return NULL;
|
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;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,6 +456,29 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
|
|||||||
return TRUE;
|
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)
|
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
|
||||||
{
|
{
|
||||||
char* s = NULL;
|
char* s = NULL;
|
||||||
@ -433,7 +487,11 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
|||||||
int status;
|
int status;
|
||||||
char* fullpath;
|
char* fullpath;
|
||||||
struct STAT st;
|
struct STAT st;
|
||||||
|
#if defined(__linux__) && !defined(ANDROID)
|
||||||
|
struct timespec tv[2];
|
||||||
|
#else
|
||||||
struct timeval tv[2];
|
struct timeval tv[2];
|
||||||
|
#endif
|
||||||
UINT64 LastWriteTime;
|
UINT64 LastWriteTime;
|
||||||
UINT32 FileAttributes;
|
UINT32 FileAttributes;
|
||||||
UINT32 FileNameLength;
|
UINT32 FileNameLength;
|
||||||
@ -454,14 +512,20 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
tv[0].tv_sec = st.st_atime;
|
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_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
|
||||||
tv[1].tv_usec = 0;
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
/* TODO on win32 */
|
/* TODO on win32 */
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
|
tv[0].tv_usec = 0;
|
||||||
|
tv[1].tv_usec = 0;
|
||||||
utimes(file->fullpath, tv);
|
utimes(file->fullpath, tv);
|
||||||
|
#elif defined (__linux__)
|
||||||
|
tv[0].tv_nsec = 0;
|
||||||
|
tv[1].tv_nsec = 0;
|
||||||
|
futimens(file->fd, tv);
|
||||||
#else
|
#else
|
||||||
|
tv[0].tv_usec = 0;
|
||||||
|
tv[1].tv_usec = 0;
|
||||||
futimes(file->fd, tv);
|
futimes(file->fd, tv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -492,6 +556,9 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
|||||||
case FileDispositionInformation:
|
case FileDispositionInformation:
|
||||||
/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
|
/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
|
||||||
/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
|
/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
|
||||||
|
if (file->is_dir && !dir_empty(file->fullpath))
|
||||||
|
break;
|
||||||
|
|
||||||
if (Length)
|
if (Length)
|
||||||
Stream_Read_UINT8(input, file->delete_pending);
|
Stream_Read_UINT8(input, file->delete_pending);
|
||||||
else
|
else
|
||||||
|
@ -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_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input);
|
||||||
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
|
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
|
||||||
const char* path, wStream* output);
|
const char* path, wStream* output);
|
||||||
|
int dir_empty(const char *path);
|
||||||
|
|
||||||
extern UINT sys_code_page;
|
extern UINT sys_code_page;
|
||||||
|
|
||||||
|
@ -346,6 +346,9 @@ static void drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file->is_dir && !dir_empty(file->fullpath))
|
||||||
|
irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length);
|
Stream_Write_UINT32(irp->output, Length);
|
||||||
|
|
||||||
irp->Complete(irp);
|
irp->Complete(irp);
|
||||||
|
@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS)
|
|||||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_SERVER_CHANNELS)
|
||||||
|
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||||
|
endif()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
set(OPTION_DEFAULT OFF)
|
set(OPTION_DEFAULT OFF)
|
||||||
set(OPTION_CLIENT_DEFAULT ON)
|
set(OPTION_CLIENT_DEFAULT ON)
|
||||||
set(OPTION_SERVER_DEFAULT OFF)
|
set(OPTION_SERVER_DEFAULT ON)
|
||||||
|
|
||||||
define_channel_options(NAME "echo" TYPE "dynamic"
|
define_channel_options(NAME "echo" TYPE "dynamic"
|
||||||
DESCRIPTION "Echo Virtual Channel Extension"
|
DESCRIPTION "Echo Virtual Channel Extension"
|
||||||
|
@ -27,12 +27,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -26,12 +26,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
#include <winpr/cmdline.h>
|
#include <winpr/cmdline.h>
|
||||||
|
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
|
|
||||||
#include <winpr/stream.h>
|
|
||||||
|
|
||||||
#include "echo_main.h"
|
#include "echo_main.h"
|
||||||
|
|
||||||
typedef struct _ECHO_LISTENER_CALLBACK ECHO_LISTENER_CALLBACK;
|
typedef struct _ECHO_LISTENER_CALLBACK ECHO_LISTENER_CALLBACK;
|
||||||
@ -63,47 +62,21 @@ struct _ECHO_PLUGIN
|
|||||||
|
|
||||||
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||||
{
|
{
|
||||||
int error;
|
int status;
|
||||||
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
||||||
BYTE *pBuffer = Stream_Pointer(data);
|
BYTE* pBuffer = Stream_Pointer(data);
|
||||||
UINT32 cbSize = Stream_GetRemainingLength(data);
|
UINT32 cbSize = Stream_GetRemainingLength(data);
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
/* echo back what we have received. ECHO does not have any message IDs. */
|
/* 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)
|
static int echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||||
{
|
{
|
||||||
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
||||||
|
|
||||||
DEBUG_DVC("");
|
|
||||||
|
|
||||||
free(callback);
|
free(callback);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -116,10 +89,10 @@ static int echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallbac
|
|||||||
ECHO_CHANNEL_CALLBACK* callback;
|
ECHO_CHANNEL_CALLBACK* callback;
|
||||||
ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*) pListenerCallback;
|
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));
|
if (!callback)
|
||||||
ZeroMemory(callback, sizeof(ECHO_CHANNEL_CALLBACK));
|
return -1;
|
||||||
|
|
||||||
callback->iface.OnDataReceived = echo_on_data_received;
|
callback->iface.OnDataReceived = echo_on_data_received;
|
||||||
callback->iface.OnClose = echo_on_close;
|
callback->iface.OnClose = echo_on_close;
|
||||||
@ -136,10 +109,10 @@ static int echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager
|
|||||||
{
|
{
|
||||||
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
|
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));
|
if (!echo->listener_callback)
|
||||||
ZeroMemory(echo->listener_callback, sizeof(ECHO_LISTENER_CALLBACK));
|
return -1;
|
||||||
|
|
||||||
echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection;
|
echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection;
|
||||||
echo->listener_callback->plugin = pPlugin;
|
echo->listener_callback->plugin = pPlugin;
|
||||||
@ -153,36 +126,35 @@ static int echo_plugin_terminated(IWTSPlugin* pPlugin)
|
|||||||
{
|
{
|
||||||
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
|
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
|
||||||
|
|
||||||
DEBUG_DVC("");
|
if (echo)
|
||||||
|
{
|
||||||
free(echo);
|
free(echo);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STATIC_CHANNELS
|
int echo_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
#define DVCPluginEntry echo_DVCPluginEntry
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|
||||||
{
|
{
|
||||||
int error = 0;
|
int status = 0;
|
||||||
ECHO_PLUGIN* echo;
|
ECHO_PLUGIN* echo;
|
||||||
|
|
||||||
echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo");
|
echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo");
|
||||||
|
|
||||||
if (echo == NULL)
|
if (!echo)
|
||||||
{
|
{
|
||||||
echo = (ECHO_PLUGIN*) malloc(sizeof(ECHO_PLUGIN));
|
echo = (ECHO_PLUGIN*) calloc(1, sizeof(ECHO_PLUGIN));
|
||||||
ZeroMemory(echo, sizeof(ECHO_PLUGIN));
|
|
||||||
|
if (!echo)
|
||||||
|
return -1;
|
||||||
|
|
||||||
echo->iface.Initialize = echo_plugin_initialize;
|
echo->iface.Initialize = echo_plugin_initialize;
|
||||||
echo->iface.Connected = NULL;
|
echo->iface.Connected = NULL;
|
||||||
echo->iface.Disconnected = NULL;
|
echo->iface.Disconnected = NULL;
|
||||||
echo->iface.Terminated = echo_plugin_terminated;
|
echo->iface.Terminated = echo_plugin_terminated;
|
||||||
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo);
|
status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,13 @@
|
|||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.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
|
#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
|
#else
|
||||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
#define DEBUG_DVC(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __ECHO_MAIN_H */
|
#endif /* __ECHO_MAIN_H */
|
||||||
|
31
channels/echo/server/CMakeLists.txt
Normal file
31
channels/echo/server/CMakeLists.txt
Normal 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")
|
||||||
|
|
||||||
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
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")
|
234
channels/echo/server/echo_main.c
Normal file
234
channels/echo/server/echo_main.c
Normal 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);
|
||||||
|
}
|
26
channels/encomsp/CMakeLists.txt
Normal file
26
channels/encomsp/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# 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("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()
|
13
channels/encomsp/ChannelOptions.cmake
Normal file
13
channels/encomsp/ChannelOptions.cmake
Normal 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})
|
||||||
|
|
34
channels/encomsp/client/CMakeLists.txt
Normal file
34
channels/encomsp/client/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# 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_client("encomsp")
|
||||||
|
|
||||||
|
include_directories(..)
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_SRCS
|
||||||
|
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(${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")
|
949
channels/encomsp/client/encomsp_main.c
Normal file
949
channels/encomsp/client/encomsp_main.c
Normal file
@ -0,0 +1,949 @@
|
|||||||
|
/**
|
||||||
|
* 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->MsgPipe->In, 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;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_USER:
|
||||||
|
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->MsgPipe->In))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (MessageQueue_Peek(encomsp->MsgPipe->In, &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->MsgPipe = MessagePipe_New();
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
MessagePipe_PostQuit(encomsp->MsgPipe, 0);
|
||||||
|
WaitForSingleObject(encomsp->thread, INFINITE);
|
||||||
|
|
||||||
|
MessagePipe_Free(encomsp->MsgPipe);
|
||||||
|
CloseHandle(encomsp->thread);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
51
channels/encomsp/client/encomsp_main.h
Normal file
51
channels/encomsp/client/encomsp_main.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
HANDLE thread;
|
||||||
|
wStream* data_in;
|
||||||
|
void* InitHandle;
|
||||||
|
DWORD OpenHandle;
|
||||||
|
wMessagePipe* MsgPipe;
|
||||||
|
};
|
||||||
|
typedef struct encomsp_plugin encomspPlugin;
|
||||||
|
|
||||||
|
#endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */
|
@ -1,5 +1,5 @@
|
|||||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
# FreeRDP X11 cmake build script
|
# FreeRDP cmake build script
|
||||||
#
|
#
|
||||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
#
|
#
|
||||||
@ -15,22 +15,22 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
set(MODULE_NAME "xfreerdp-server-cli")
|
define_channel_server("encomsp")
|
||||||
set(MODULE_PREFIX "FREERDP_SERVER_X11")
|
|
||||||
|
|
||||||
include_directories(..)
|
include_directories(..)
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_SRCS
|
set(${MODULE_PREFIX}_SRCS
|
||||||
xfreerdp.c)
|
encomsp_main.c
|
||||||
|
encomsp_main.h)
|
||||||
|
|
||||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "xfreerdp-server" RUNTIME_OUTPUT_DIRECTORY "..")
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} xfreerdp-server)
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/X11")
|
|
||||||
|
|
||||||
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
273
channels/encomsp/server/encomsp_main.c
Normal file
273
channels/encomsp/server/encomsp_main.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
36
channels/encomsp/server/encomsp_main.h
Normal file
36
channels/encomsp/server/encomsp_main.h
Normal 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 */
|
@ -24,17 +24,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp winpr)
|
||||||
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})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -40,15 +40,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
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)
|
|
||||||
|
|
||||||
if(WITH_CUPS)
|
if(WITH_CUPS)
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES})
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES})
|
||||||
|
@ -20,17 +20,20 @@
|
|||||||
#ifndef __PRINTER_WIN_H
|
#ifndef __PRINTER_WIN_H
|
||||||
#define __PRINTER_WIN_H
|
#define __PRINTER_WIN_H
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
rdpPrinterDriver* printer_win_get_driver(void);
|
rdpPrinterDriver* printer_win_get_driver(void);
|
||||||
|
|
||||||
|
#define PRINTER_TAG CHANNELS_TAG("printer.client")
|
||||||
#ifdef WITH_DEBUG_WINPR
|
#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
|
#else
|
||||||
#define DEBUG_WINPR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
#define DEBUG_WINPR(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -29,12 +29,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
|
||||||
#include <freerdp/utils/rail.h>
|
#include <freerdp/utils/rail.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rail_orders.h"
|
#include "rail_orders.h"
|
||||||
|
|
||||||
@ -522,7 +523,7 @@ BOOL rail_order_recv(railPlugin* rail, wStream* s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Unknown RAIL PDU order reveived.");
|
WLog_ERR(TAG, "Unknown RAIL PDU order reveived.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,11 @@
|
|||||||
#ifndef __RAIL_ORDERS_H
|
#ifndef __RAIL_ORDERS_H
|
||||||
#define __RAIL_ORDERS_H
|
#define __RAIL_ORDERS_H
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include "rail_main.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_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_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam);
|
||||||
BOOL rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo);
|
BOOL rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo);
|
||||||
|
@ -31,17 +31,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
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})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/client/channels.h>
|
#include <freerdp/client/channels.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rdpdr_main.h"
|
#include "rdpdr_main.h"
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ BOOL devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device)
|
|||||||
if (!ServiceName)
|
if (!ServiceName)
|
||||||
return FALSE;
|
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);
|
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -451,7 +452,7 @@ static void* drive_hotplug_thread_func(void* arg)
|
|||||||
|
|
||||||
if (mfd < 0)
|
if (mfd < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR: Unable to open /proc/mounts.");
|
WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,6 +461,8 @@ static void* drive_hotplug_thread_func(void* arg)
|
|||||||
tv.tv_sec = 1;
|
tv.tv_sec = 1;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
handle_hotplug(rdpdr);
|
||||||
|
|
||||||
while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
|
while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
|
||||||
{
|
{
|
||||||
if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(rdpdr->stopEvent, 0) == WAIT_OBJECT_0)
|
||||||
@ -659,9 +662,8 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
|
|||||||
Stream_Write(s, Stream_Buffer(device->data), data_len);
|
Stream_Write(s, Stream_Buffer(device->data), data_len);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
WLog_INFO(TAG, "registered device #%d: %s (type=%d id=%d)\n",
|
||||||
fprintf(stderr, "registered device #%d: %s (type=%d id=%d)\n",
|
count, device->name, device->type, device->id);
|
||||||
count, device->name, device->type, device->id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,7 +845,7 @@ int rdpdr_send(rdpdrPlugin* rdpdr, wStream* s)
|
|||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
fprintf(stderr, "rdpdr_send: VirtualChannelWrite failed %d\n", status);
|
WLog_ERR(TAG, "rdpdr_send: VirtualChannelWrite failed %d\n", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -881,7 +883,7 @@ static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr,
|
|||||||
{
|
{
|
||||||
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "svc_plugin_process_received: read error\n");
|
WLog_ERR(TAG, "svc_plugin_process_received: read error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpdr->data_in = NULL;
|
rdpdr->data_in = NULL;
|
||||||
@ -901,7 +903,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev
|
|||||||
|
|
||||||
if (!rdpdr)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -961,7 +963,7 @@ static void rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa
|
|||||||
|
|
||||||
if (status != CHANNEL_RC_OK)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1007,7 +1009,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT
|
|||||||
|
|
||||||
if (!rdpdr)
|
if (!rdpdr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "rdpdr_virtual_channel_init_event: error no match\n");
|
WLog_ERR(TAG, "rdpdr_virtual_channel_init_event: error no match\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,9 @@
|
|||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
|
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdprd.client")
|
||||||
|
|
||||||
typedef struct rdpdr_plugin rdpdrPlugin;
|
typedef struct rdpdr_plugin rdpdrPlugin;
|
||||||
|
|
||||||
|
@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -25,8 +25,11 @@
|
|||||||
#include <winpr/print.h>
|
#include <winpr/print.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include "rdpdr_main.h"
|
#include "rdpdr_main.h"
|
||||||
|
|
||||||
|
#define TAG "rdpdr.server"
|
||||||
|
|
||||||
static UINT32 g_ClientId = 0;
|
static UINT32 g_ClientId = 0;
|
||||||
|
|
||||||
static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
||||||
@ -35,27 +38,18 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
|||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "RdpdrServerSendAnnounceRequest");
|
||||||
printf("RdpdrServerSendAnnounceRequest\n");
|
|
||||||
|
|
||||||
header.Component = RDPDR_CTYP_CORE;
|
header.Component = RDPDR_CTYP_CORE;
|
||||||
header.PacketId = PAKID_CORE_SERVER_ANNOUNCE;
|
header.PacketId = PAKID_CORE_SERVER_ANNOUNCE;
|
||||||
|
|
||||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8);
|
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (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->VersionMajor); /* VersionMajor (2 bytes) */
|
||||||
Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
|
Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
|
||||||
Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
|
Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
|
||||||
|
|
||||||
Stream_SealLength(s);
|
Stream_SealLength(s);
|
||||||
|
|
||||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,16 +58,12 @@ static int rdpdr_server_receive_announce_response(RdpdrServerContext* context, w
|
|||||||
UINT32 ClientId;
|
UINT32 ClientId;
|
||||||
UINT16 VersionMajor;
|
UINT16 VersionMajor;
|
||||||
UINT16 VersionMinor;
|
UINT16 VersionMinor;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */
|
Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */
|
||||||
Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */
|
Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */
|
||||||
Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */
|
Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */
|
||||||
|
WLog_DBG(TAG, "Client Announce Response: VersionMajor: 0x%04X VersionMinor: 0x%04X ClientId: 0x%04X",
|
||||||
printf("Client Announce Response: VersionMajor: 0x%04X VersionMinor: 0x%04X ClientId: 0x%04X\n",
|
VersionMajor, VersionMinor, ClientId);
|
||||||
VersionMajor, VersionMinor, ClientId);
|
|
||||||
|
|
||||||
context->priv->ClientId = ClientId;
|
context->priv->ClientId = ClientId;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +71,6 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context,
|
|||||||
{
|
{
|
||||||
UINT32 UnicodeFlag;
|
UINT32 UnicodeFlag;
|
||||||
UINT32 ComputerNameLen;
|
UINT32 ComputerNameLen;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */
|
Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */
|
||||||
Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */
|
Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */
|
||||||
Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */
|
Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */
|
||||||
@ -100,7 +89,7 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context,
|
|||||||
if (UnicodeFlag)
|
if (UnicodeFlag)
|
||||||
{
|
{
|
||||||
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
||||||
-1, &(context->priv->ClientComputerName), 0, NULL, NULL);
|
-1, &(context->priv->ClientComputerName), 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -108,9 +97,7 @@ static int rdpdr_server_receive_client_name_request(RdpdrServerContext* context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream_Seek(s, ComputerNameLen);
|
Stream_Seek(s, ComputerNameLen);
|
||||||
|
WLog_DBG(TAG, "ClientComputerName: %s", context->priv->ClientComputerName);
|
||||||
printf("ClientComputerName: %s\n", context->priv->ClientComputerName);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +125,6 @@ static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context,
|
|||||||
UINT16 VersionMajor;
|
UINT16 VersionMajor;
|
||||||
UINT16 VersionMinor;
|
UINT16 VersionMinor;
|
||||||
UINT32 SpecialTypeDeviceCap;
|
UINT32 SpecialTypeDeviceCap;
|
||||||
|
|
||||||
Stream_Seek_UINT32(s); /* osType (4 bytes), ignored on receipt */
|
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_Seek_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */
|
||||||
Stream_Read_UINT16(s, VersionMajor); /* protocolMajorVersion (2 bytes) */
|
Stream_Read_UINT16(s, VersionMajor); /* protocolMajorVersion (2 bytes) */
|
||||||
@ -149,9 +135,7 @@ static int rdpdr_server_read_general_capability_set(RdpdrServerContext* context,
|
|||||||
Stream_Read_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
|
Stream_Read_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
|
||||||
Stream_Seek_UINT32(s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
|
Stream_Seek_UINT32(s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
|
||||||
Stream_Read_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
|
Stream_Read_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
|
||||||
|
|
||||||
context->priv->UserLoggedOnPdu = (extendedPdu & RDPDR_USER_LOGGEDON_PDU) ? TRUE : FALSE;
|
context->priv->UserLoggedOnPdu = (extendedPdu & RDPDR_USER_LOGGEDON_PDU) ? TRUE : FALSE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,11 +146,9 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
|
|||||||
UINT32 extraFlags1;
|
UINT32 extraFlags1;
|
||||||
UINT32 SpecialTypeDeviceCap;
|
UINT32 SpecialTypeDeviceCap;
|
||||||
RDPDR_CAPABILITY_HEADER header;
|
RDPDR_CAPABILITY_HEADER header;
|
||||||
|
|
||||||
header.CapabilityType = CAP_GENERAL_TYPE;
|
header.CapabilityType = CAP_GENERAL_TYPE;
|
||||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH + 36;
|
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH + 36;
|
||||||
header.Version = GENERAL_CAPABILITY_VERSION_02;
|
header.Version = GENERAL_CAPABILITY_VERSION_02;
|
||||||
|
|
||||||
ioCode1 = 0;
|
ioCode1 = 0;
|
||||||
ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */
|
ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */
|
||||||
ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */
|
ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */
|
||||||
@ -184,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_LOCK_CONTROL; /* always set */
|
||||||
ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */
|
ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */
|
||||||
ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */
|
ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */
|
||||||
|
|
||||||
extendedPdu = 0;
|
extendedPdu = 0;
|
||||||
extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */
|
extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */
|
||||||
extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */
|
extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */
|
||||||
@ -194,12 +175,9 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
|
|||||||
|
|
||||||
extraFlags1 = 0;
|
extraFlags1 = 0;
|
||||||
extraFlags1 |= ENABLE_ASYNCIO; /* optional */
|
extraFlags1 |= ENABLE_ASYNCIO; /* optional */
|
||||||
|
|
||||||
SpecialTypeDeviceCap = 0;
|
SpecialTypeDeviceCap = 0;
|
||||||
|
|
||||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||||
rdpdr_server_write_capability_set_header(s, &header);
|
rdpdr_server_write_capability_set_header(s, &header);
|
||||||
|
|
||||||
Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */
|
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_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */
|
||||||
Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */
|
Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */
|
||||||
@ -210,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, 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, 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */
|
||||||
Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
|
Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,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)
|
static int rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s)
|
||||||
{
|
{
|
||||||
RDPDR_CAPABILITY_HEADER header;
|
RDPDR_CAPABILITY_HEADER header;
|
||||||
|
|
||||||
header.CapabilityType = CAP_PRINTER_TYPE;
|
header.CapabilityType = CAP_PRINTER_TYPE;
|
||||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||||
header.Version = PRINT_CAPABILITY_VERSION_01;
|
header.Version = PRINT_CAPABILITY_VERSION_01;
|
||||||
|
|
||||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||||
rdpdr_server_write_capability_set_header(s, &header);
|
rdpdr_server_write_capability_set_header(s, &header);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,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)
|
static int rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s)
|
||||||
{
|
{
|
||||||
RDPDR_CAPABILITY_HEADER header;
|
RDPDR_CAPABILITY_HEADER header;
|
||||||
|
|
||||||
header.CapabilityType = CAP_PORT_TYPE;
|
header.CapabilityType = CAP_PORT_TYPE;
|
||||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||||
header.Version = PORT_CAPABILITY_VERSION_01;
|
header.Version = PORT_CAPABILITY_VERSION_01;
|
||||||
|
|
||||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||||
rdpdr_server_write_capability_set_header(s, &header);
|
rdpdr_server_write_capability_set_header(s, &header);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,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)
|
static int rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s)
|
||||||
{
|
{
|
||||||
RDPDR_CAPABILITY_HEADER header;
|
RDPDR_CAPABILITY_HEADER header;
|
||||||
|
|
||||||
header.CapabilityType = CAP_DRIVE_TYPE;
|
header.CapabilityType = CAP_DRIVE_TYPE;
|
||||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||||
header.Version = DRIVE_CAPABILITY_VERSION_02;
|
header.Version = DRIVE_CAPABILITY_VERSION_02;
|
||||||
|
|
||||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||||
rdpdr_server_write_capability_set_header(s, &header);
|
rdpdr_server_write_capability_set_header(s, &header);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,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)
|
static int rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s)
|
||||||
{
|
{
|
||||||
RDPDR_CAPABILITY_HEADER header;
|
RDPDR_CAPABILITY_HEADER header;
|
||||||
|
|
||||||
header.CapabilityType = CAP_SMARTCARD_TYPE;
|
header.CapabilityType = CAP_SMARTCARD_TYPE;
|
||||||
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH;
|
||||||
header.Version = SMARTCARD_CAPABILITY_VERSION_01;
|
header.Version = SMARTCARD_CAPABILITY_VERSION_01;
|
||||||
|
|
||||||
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
Stream_EnsureRemainingCapacity(s, header.CapabilityLength);
|
||||||
rdpdr_server_write_capability_set_header(s, &header);
|
rdpdr_server_write_capability_set_header(s, &header);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,34 +262,23 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
|
|||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
UINT16 numCapabilities;
|
UINT16 numCapabilities;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "RdpdrServerSendCoreCapabilityRequest");
|
||||||
printf("RdpdrServerSendCoreCapabilityRequest\n");
|
|
||||||
|
|
||||||
header.Component = RDPDR_CTYP_CORE;
|
header.Component = RDPDR_CTYP_CORE;
|
||||||
header.PacketId = PAKID_CORE_SERVER_CAPABILITY;
|
header.PacketId = PAKID_CORE_SERVER_CAPABILITY;
|
||||||
|
|
||||||
numCapabilities = 5;
|
numCapabilities = 5;
|
||||||
|
|
||||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 512);
|
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 512);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
|
Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
|
||||||
Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */
|
Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */
|
||||||
|
|
||||||
rdpdr_server_write_general_capability_set(context, s);
|
rdpdr_server_write_general_capability_set(context, s);
|
||||||
rdpdr_server_write_printer_capability_set(context, s);
|
rdpdr_server_write_printer_capability_set(context, s);
|
||||||
rdpdr_server_write_port_capability_set(context, s);
|
rdpdr_server_write_port_capability_set(context, s);
|
||||||
rdpdr_server_write_drive_capability_set(context, s);
|
rdpdr_server_write_drive_capability_set(context, s);
|
||||||
rdpdr_server_write_smartcard_capability_set(context, s);
|
rdpdr_server_write_smartcard_capability_set(context, s);
|
||||||
|
|
||||||
Stream_SealLength(s);
|
Stream_SealLength(s);
|
||||||
|
|
||||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +287,6 @@ static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* con
|
|||||||
int i;
|
int i;
|
||||||
UINT16 numCapabilities;
|
UINT16 numCapabilities;
|
||||||
RDPDR_CAPABILITY_HEADER capabilityHeader;
|
RDPDR_CAPABILITY_HEADER capabilityHeader;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
|
Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */
|
||||||
Stream_Seek_UINT16(s); /* Padding (2 bytes) */
|
Stream_Seek_UINT16(s); /* Padding (2 bytes) */
|
||||||
|
|
||||||
@ -364,7 +317,7 @@ static int rdpdr_server_receive_core_capability_response(RdpdrServerContext* con
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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);
|
Stream_Seek(s, capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -379,27 +332,18 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
|||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "RdpdrServerSendClientIdConfirm");
|
||||||
printf("RdpdrServerSendClientIdConfirm\n");
|
|
||||||
|
|
||||||
header.Component = RDPDR_CTYP_CORE;
|
header.Component = RDPDR_CTYP_CORE;
|
||||||
header.PacketId = PAKID_CORE_CLIENTID_CONFIRM;
|
header.PacketId = PAKID_CORE_CLIENTID_CONFIRM;
|
||||||
|
|
||||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8);
|
s = Stream_New(NULL, RDPDR_HEADER_LENGTH + 8);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (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->VersionMajor); /* VersionMajor (2 bytes) */
|
||||||
Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
|
Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */
|
||||||
Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
|
Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */
|
||||||
|
|
||||||
Stream_SealLength(s);
|
Stream_SealLength(s);
|
||||||
|
|
||||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,12 +355,9 @@ static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext*
|
|||||||
UINT32 DeviceId;
|
UINT32 DeviceId;
|
||||||
char PreferredDosName[9];
|
char PreferredDosName[9];
|
||||||
UINT32 DeviceDataLength;
|
UINT32 DeviceDataLength;
|
||||||
|
|
||||||
PreferredDosName[8] = 0;
|
PreferredDosName[8] = 0;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */
|
Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */
|
||||||
|
WLog_DBG(TAG, "DeviceCount: %d", DeviceCount);
|
||||||
printf("%s: DeviceCount: %d\n", __FUNCTION__, DeviceCount);
|
|
||||||
|
|
||||||
for (i = 0; i < DeviceCount; i++)
|
for (i = 0; i < DeviceCount; i++)
|
||||||
{
|
{
|
||||||
@ -424,9 +365,8 @@ static int rdpdr_server_receive_device_list_announce_request(RdpdrServerContext*
|
|||||||
Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */
|
Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */
|
||||||
Stream_Read(s, PreferredDosName, 8); /* PreferredDosName (8 bytes) */
|
Stream_Read(s, PreferredDosName, 8); /* PreferredDosName (8 bytes) */
|
||||||
Stream_Read_UINT32(s, DeviceDataLength); /* DeviceDataLength (4 bytes) */
|
Stream_Read_UINT32(s, DeviceDataLength); /* DeviceDataLength (4 bytes) */
|
||||||
|
WLog_DBG(TAG, "Device %d Name: %s Id: 0x%04X DataLength: %d",
|
||||||
printf("Device %d Name: %s Id: 0x%04X DataLength: %d\n",
|
i, PreferredDosName, DeviceId, DeviceDataLength);
|
||||||
i, PreferredDosName, DeviceId, DeviceDataLength);
|
|
||||||
|
|
||||||
switch (DeviceId)
|
switch (DeviceId)
|
||||||
{
|
{
|
||||||
@ -461,32 +401,23 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
|||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
ULONG written;
|
ULONG written;
|
||||||
|
WLog_DBG(TAG, "%s");
|
||||||
printf("%s\n", __FUNCTION__);
|
|
||||||
|
|
||||||
header.Component = RDPDR_CTYP_CORE;
|
header.Component = RDPDR_CTYP_CORE;
|
||||||
header.PacketId = PAKID_CORE_USER_LOGGEDON;
|
header.PacketId = PAKID_CORE_USER_LOGGEDON;
|
||||||
|
|
||||||
s = Stream_New(NULL, RDPDR_HEADER_LENGTH);
|
s = Stream_New(NULL, RDPDR_HEADER_LENGTH);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
Stream_SealLength(s);
|
Stream_SealLength(s);
|
||||||
|
|
||||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header)
|
||||||
{
|
{
|
||||||
printf("RdpdrServerReceivePdu: Component: 0x%04X PacketId: 0x%04X\n",
|
WLog_DBG(TAG, "RdpdrServerReceivePdu: Component: 0x%04X PacketId: 0x%04X",
|
||||||
header->Component, header->PacketId);
|
header->Component, header->PacketId);
|
||||||
|
winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s));
|
||||||
winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
|
|
||||||
|
|
||||||
if (header->Component == RDPDR_CTYP_CORE)
|
if (header->Component == RDPDR_CTYP_CORE)
|
||||||
{
|
{
|
||||||
@ -507,6 +438,7 @@ static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDP
|
|||||||
|
|
||||||
if (context->priv->UserLoggedOnPdu)
|
if (context->priv->UserLoggedOnPdu)
|
||||||
rdpdr_server_send_user_logged_on(context);
|
rdpdr_server_send_user_logged_on(context);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAKID_CORE_DEVICELIST_ANNOUNCE:
|
case PAKID_CORE_DEVICELIST_ANNOUNCE:
|
||||||
@ -545,7 +477,7 @@ static int rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDP
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Unknown RDPDR_HEADER.Component: 0x%04X\n", header->Component);
|
WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: 0x%04X", header->Component);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,13 +496,10 @@ static void* rdpdr_server_thread(void* arg)
|
|||||||
HANDLE ChannelEvent;
|
HANDLE ChannelEvent;
|
||||||
DWORD BytesReturned;
|
DWORD BytesReturned;
|
||||||
RdpdrServerContext* context;
|
RdpdrServerContext* context;
|
||||||
|
|
||||||
context = (RdpdrServerContext*) arg;
|
context = (RdpdrServerContext*) arg;
|
||||||
|
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
BytesReturned = 0;
|
BytesReturned = 0;
|
||||||
ChannelEvent = NULL;
|
ChannelEvent = NULL;
|
||||||
|
|
||||||
s = Stream_New(NULL, 4096);
|
s = Stream_New(NULL, 4096);
|
||||||
|
|
||||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
|
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE)
|
||||||
@ -584,13 +513,11 @@ static void* rdpdr_server_thread(void* arg)
|
|||||||
nCount = 0;
|
nCount = 0;
|
||||||
events[nCount++] = ChannelEvent;
|
events[nCount++] = ChannelEvent;
|
||||||
events[nCount++] = context->priv->StopEvent;
|
events[nCount++] = context->priv->StopEvent;
|
||||||
|
|
||||||
rdpdr_server_send_announce_request(context);
|
rdpdr_server_send_announce_request(context);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
BytesReturned = 0;
|
BytesReturned = 0;
|
||||||
|
|
||||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||||
|
|
||||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||||
@ -598,37 +525,34 @@ static void* rdpdr_server_thread(void* arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Pointer(s),
|
WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned);
|
||||||
Stream_Capacity(s) - Stream_GetPosition(s), &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)
|
break;
|
||||||
Stream_Seek(s, BytesReturned);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Stream_GetPosition(s) >= RDPDR_HEADER_LENGTH)
|
if (Stream_GetPosition(s) >= RDPDR_HEADER_LENGTH)
|
||||||
{
|
{
|
||||||
position = Stream_GetPosition(s);
|
position = Stream_GetPosition(s);
|
||||||
Stream_SetPosition(s, 0);
|
Stream_SetPosition(s, 0);
|
||||||
|
|
||||||
Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */
|
Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */
|
||||||
Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
Stream_SetPosition(s, position);
|
Stream_SetPosition(s, position);
|
||||||
|
|
||||||
Stream_SealLength(s);
|
Stream_SealLength(s);
|
||||||
Stream_SetPosition(s, RDPDR_HEADER_LENGTH);
|
Stream_SetPosition(s, RDPDR_HEADER_LENGTH);
|
||||||
|
|
||||||
rdpdr_server_receive_pdu(context, s, &header);
|
rdpdr_server_receive_pdu(context, s, &header);
|
||||||
Stream_SetPosition(s, 0);
|
Stream_SetPosition(s, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,48 +564,38 @@ static int rdpdr_server_start(RdpdrServerContext* context)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
context->priv->Thread = CreateThread(NULL, 0,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rdpdr_server_stop(RdpdrServerContext* context)
|
static int rdpdr_server_stop(RdpdrServerContext* context)
|
||||||
{
|
{
|
||||||
SetEvent(context->priv->StopEvent);
|
SetEvent(context->priv->StopEvent);
|
||||||
|
|
||||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||||
CloseHandle(context->priv->Thread);
|
CloseHandle(context->priv->Thread);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
|
RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm)
|
||||||
{
|
{
|
||||||
RdpdrServerContext* context;
|
RdpdrServerContext* context;
|
||||||
|
|
||||||
context = (RdpdrServerContext*) malloc(sizeof(RdpdrServerContext));
|
context = (RdpdrServerContext*) malloc(sizeof(RdpdrServerContext));
|
||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
ZeroMemory(context, sizeof(RdpdrServerContext));
|
ZeroMemory(context, sizeof(RdpdrServerContext));
|
||||||
|
|
||||||
context->vcm = vcm;
|
context->vcm = vcm;
|
||||||
|
|
||||||
context->Start = rdpdr_server_start;
|
context->Start = rdpdr_server_start;
|
||||||
context->Stop = rdpdr_server_stop;
|
context->Stop = rdpdr_server_stop;
|
||||||
|
|
||||||
context->priv = (RdpdrServerPrivate*) malloc(sizeof(RdpdrServerPrivate));
|
context->priv = (RdpdrServerPrivate*) malloc(sizeof(RdpdrServerPrivate));
|
||||||
|
|
||||||
if (context->priv)
|
if (context->priv)
|
||||||
{
|
{
|
||||||
ZeroMemory(context->priv, sizeof(RdpdrServerPrivate));
|
ZeroMemory(context->priv, sizeof(RdpdrServerPrivate));
|
||||||
|
|
||||||
context->priv->VersionMajor = RDPDR_VERSION_MAJOR;
|
context->priv->VersionMajor = RDPDR_VERSION_MAJOR;
|
||||||
context->priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
|
context->priv->VersionMinor = RDPDR_VERSION_MINOR_RDP6X;
|
||||||
context->priv->ClientId = g_ClientId++;
|
context->priv->ClientId = g_ClientId++;
|
||||||
|
|
||||||
context->priv->UserLoggedOnPdu = TRUE;
|
context->priv->UserLoggedOnPdu = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,17 +29,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
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})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -201,8 +201,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);
|
status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL);
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_RDPEI
|
#ifdef WITH_DEBUG_RDPEI
|
||||||
fprintf(stderr, "rdpei_send_pdu: eventId: %d (%s) length: %d status: %d\n",
|
WLog_DBG(TAG, "rdpei_send_pdu: eventId: %d (%s) length: %d status: %d",
|
||||||
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status);
|
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -239,17 +239,22 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback)
|
|||||||
void rdpei_print_contact_flags(UINT32 contactFlags)
|
void rdpei_print_contact_flags(UINT32 contactFlags)
|
||||||
{
|
{
|
||||||
if (contactFlags & CONTACT_FLAG_DOWN)
|
if (contactFlags & CONTACT_FLAG_DOWN)
|
||||||
printf(" CONTACT_FLAG_DOWN");
|
WLog_DBG(TAG, " CONTACT_FLAG_DOWN");
|
||||||
|
|
||||||
if (contactFlags & CONTACT_FLAG_UPDATE)
|
if (contactFlags & CONTACT_FLAG_UPDATE)
|
||||||
printf(" CONTACT_FLAG_UPDATE");
|
WLog_DBG(TAG, " CONTACT_FLAG_UPDATE");
|
||||||
|
|
||||||
if (contactFlags & CONTACT_FLAG_UP)
|
if (contactFlags & CONTACT_FLAG_UP)
|
||||||
printf(" CONTACT_FLAG_UP");
|
WLog_DBG(TAG, " CONTACT_FLAG_UP");
|
||||||
|
|
||||||
if (contactFlags & CONTACT_FLAG_INRANGE)
|
if (contactFlags & CONTACT_FLAG_INRANGE)
|
||||||
printf(" CONTACT_FLAG_INRANGE");
|
WLog_DBG(TAG, " CONTACT_FLAG_INRANGE");
|
||||||
|
|
||||||
if (contactFlags & CONTACT_FLAG_INCONTACT)
|
if (contactFlags & CONTACT_FLAG_INCONTACT)
|
||||||
printf(" CONTACT_FLAG_INCONTACT");
|
WLog_DBG(TAG, " CONTACT_FLAG_INCONTACT");
|
||||||
|
|
||||||
if (contactFlags & CONTACT_FLAG_CANCELED)
|
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)
|
int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
|
||||||
@ -259,8 +264,8 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
|
|||||||
RDPINPUT_CONTACT_DATA* contact;
|
RDPINPUT_CONTACT_DATA* contact;
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_RDPEI
|
#ifdef WITH_DEBUG_RDPEI
|
||||||
printf("contactCount: %d\n", frame->contactCount);
|
WLog_DBG(TAG, "contactCount: %d", frame->contactCount);
|
||||||
printf("frameOffset: 0x%08X\n", (UINT32) frame->frameOffset);
|
WLog_DBG(TAG, "frameOffset: 0x%08X", (UINT32) frame->frameOffset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rdpei_write_2byte_unsigned(s, frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */
|
rdpei_write_2byte_unsigned(s, frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */
|
||||||
@ -284,13 +289,12 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
|
|||||||
contact->contactRectBottom = contact->y + rectSize;
|
contact->contactRectBottom = contact->y + rectSize;
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_RDPEI
|
#ifdef WITH_DEBUG_RDPEI
|
||||||
printf("contact[%d].contactId: %d\n", index, contact->contactId);
|
WLog_DBG(TAG, "contact[%d].contactId: %d", index, contact->contactId);
|
||||||
printf("contact[%d].fieldsPresent: %d\n", index, contact->fieldsPresent);
|
WLog_DBG(TAG, "contact[%d].fieldsPresent: %d", index, contact->fieldsPresent);
|
||||||
printf("contact[%d].x: %d\n", index, contact->x);
|
WLog_DBG(TAG, "contact[%d].x: %d", index, contact->x);
|
||||||
printf("contact[%d].y: %d\n", index, contact->y);
|
WLog_DBG(TAG, "contact[%d].y: %d", index, contact->y);
|
||||||
printf("contact[%d].contactFlags: 0x%04X", index, contact->contactFlags);
|
WLog_DBG(TAG, "contact[%d].contactFlags: 0x%04X", index, contact->contactFlags);
|
||||||
rdpei_print_contact_flags(contact->contactFlags);
|
rdpei_print_contact_flags(contact->contactFlags);
|
||||||
printf("\n");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */
|
Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */
|
||||||
@ -371,7 +375,7 @@ int rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
#if 0
|
#if 0
|
||||||
if (protocolVersion != RDPINPUT_PROTOCOL_V10)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -408,8 +412,8 @@ int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */
|
Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_RDPEI
|
#ifdef WITH_DEBUG_RDPEI
|
||||||
fprintf(stderr, "rdpei_recv_pdu: eventId: %d (%s) length: %d\n",
|
WLog_DBG(TAG, "rdpei_recv_pdu: eventId: %d (%s) length: %d",
|
||||||
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength);
|
eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (eventId)
|
switch (eventId)
|
||||||
|
@ -27,10 +27,12 @@
|
|||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include <freerdp/client/rdpei.h>
|
#include <freerdp/client/rdpei.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpei.client")
|
||||||
|
|
||||||
#define RDPINPUT_HEADER_LENGTH 6
|
#define RDPINPUT_HEADER_LENGTH 6
|
||||||
|
|
||||||
/* Protocol Version */
|
/* Protocol Version */
|
||||||
@ -100,9 +102,9 @@ struct _RDPINPUT_CONTACT_POINT
|
|||||||
typedef struct _RDPINPUT_CONTACT_POINT RDPINPUT_CONTACT_POINT;
|
typedef struct _RDPINPUT_CONTACT_POINT RDPINPUT_CONTACT_POINT;
|
||||||
|
|
||||||
#ifdef WITH_DEBUG_DVC
|
#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
|
#else
|
||||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
#define DEBUG_DVC(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_MAIN_H */
|
#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_MAIN_H */
|
||||||
|
@ -31,17 +31,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-codec 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})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -23,9 +23,14 @@
|
|||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
#include <freerdp/log.h>
|
||||||
|
|
||||||
|
#include "rdpgfx_common.h"
|
||||||
|
|
||||||
#include "rdpgfx_codec.h"
|
#include "rdpgfx_codec.h"
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpgfx.client")
|
||||||
|
|
||||||
int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@ -33,8 +38,6 @@ int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
|||||||
|
|
||||||
int rdpgfx_decode_remotefx(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
int rdpgfx_decode_remotefx(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "RdpGfxDecodeRemoteFx\n");
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,8 +51,91 @@ int rdpgfx_decode_planar(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
|||||||
return 1;
|
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;
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +149,6 @@ int rdpgfx_decode_progressive(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rdpgfx_decode_progressive_v2(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
@ -103,7 +184,6 @@ int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||||
status = rdpgfx_decode_progressive_v2(gfx, cmd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId)
|
|||||||
|
|
||||||
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
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->cmdId); /* cmdId (2 bytes) */
|
||||||
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||||
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
||||||
@ -105,6 +108,9 @@ int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
|
|||||||
|
|
||||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16)
|
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->x); /* x (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pt16->y); /* y (2 bytes) */
|
Stream_Read_UINT16(s, pt16->y); /* y (2 bytes) */
|
||||||
|
|
||||||
@ -121,6 +127,9 @@ int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
|||||||
|
|
||||||
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
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->left); /* left (2 bytes) */
|
||||||
Stream_Read_UINT16(s, rect16->top); /* top (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->right); /* right (2 bytes) */
|
||||||
@ -141,6 +150,9 @@ int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
|||||||
|
|
||||||
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32)
|
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->B); /* B (1 byte) */
|
||||||
Stream_Read_UINT8(s, color32->G); /* G (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->R); /* R (1 byte) */
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <winpr/collections.h>
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rdpgfx_common.h"
|
#include "rdpgfx_common.h"
|
||||||
#include "rdpgfx_codec.h"
|
#include "rdpgfx_codec.h"
|
||||||
@ -56,20 +57,13 @@ int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
|||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
|
|
||||||
gfx->ThinClient = TRUE;
|
|
||||||
gfx->SmallCache = FALSE;
|
|
||||||
gfx->H264 = FALSE;
|
|
||||||
|
|
||||||
gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600;
|
|
||||||
|
|
||||||
header.flags = 0;
|
header.flags = 0;
|
||||||
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
|
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
|
||||||
|
|
||||||
pdu.capsSetCount = 1;
|
pdu.capsSetCount = 0;
|
||||||
pdu.capsSets = (RDPGFX_CAPSET*) capsSets;
|
pdu.capsSets = (RDPGFX_CAPSET*) capsSets;
|
||||||
|
|
||||||
capsSet = &capsSets[0];
|
capsSet = &capsSets[pdu.capsSetCount++];
|
||||||
|
|
||||||
capsSet->version = RDPGFX_CAPVERSION_8;
|
capsSet->version = RDPGFX_CAPVERSION_8;
|
||||||
capsSet->flags = 0;
|
capsSet->flags = 0;
|
||||||
|
|
||||||
@ -79,8 +73,7 @@ int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
|||||||
if (gfx->SmallCache)
|
if (gfx->SmallCache)
|
||||||
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
||||||
|
|
||||||
capsSet = &capsSets[1];
|
capsSet = &capsSets[pdu.capsSetCount++];
|
||||||
|
|
||||||
capsSet->version = RDPGFX_CAPVERSION_81;
|
capsSet->version = RDPGFX_CAPVERSION_81;
|
||||||
capsSet->flags = 0;
|
capsSet->flags = 0;
|
||||||
|
|
||||||
@ -131,9 +124,14 @@ int rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
|
|
||||||
pdu.capsSet = &capsSet;
|
pdu.capsSet = &capsSet;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 12)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, capsSet.version); /* version (4 bytes) */
|
Stream_Read_UINT32(s, capsSet.version); /* version (4 bytes) */
|
||||||
Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */
|
Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */
|
||||||
Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */
|
Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */
|
||||||
|
|
||||||
|
/*TODO: interpret this answer*/
|
||||||
|
|
||||||
WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%04X flags: 0x%04X",
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%04X flags: 0x%04X",
|
||||||
capsSet.version, capsSet.flags);
|
capsSet.version, capsSet.flags);
|
||||||
@ -180,10 +178,16 @@ int rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 12)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */
|
Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */
|
Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.monitorCount); /* monitorCount (4 bytes) */
|
Stream_Read_UINT32(s, pdu.monitorCount); /* monitorCount (4 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (pdu.monitorCount * 20))
|
||||||
|
return -1;
|
||||||
|
|
||||||
pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF));
|
pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF));
|
||||||
|
|
||||||
if (!pdu.monitorDefArray)
|
if (!pdu.monitorDefArray)
|
||||||
@ -200,6 +204,10 @@ int rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s
|
|||||||
}
|
}
|
||||||
|
|
||||||
pad = 340 - (RDPGFX_HEADER_SIZE + 12 + (pdu.monitorCount * 20));
|
pad = 340 - (RDPGFX_HEADER_SIZE + 12 + (pdu.monitorCount * 20));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) pad)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Seek(s, pad); /* pad (total size is 340 bytes) */
|
Stream_Seek(s, pad); /* pad (total size is 340 bytes) */
|
||||||
|
|
||||||
WLog_Print(gfx->log, WLOG_DEBUG, "RecvResetGraphicsPdu: width: %d height: %d count: %d",
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvResetGraphicsPdu: width: %d height: %d count: %d",
|
||||||
@ -221,6 +229,9 @@ int rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
||||||
|
|
||||||
WLog_Print(gfx->log, WLOG_DEBUG, "RecvEvictCacheEntryPdu: cacheSlot: %d", pdu.cacheSlot);
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvEvictCacheEntryPdu: cacheSlot: %d", pdu.cacheSlot);
|
||||||
@ -240,8 +251,14 @@ int rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.importedEntriesCount); /* cacheSlot (2 bytes) */
|
Stream_Read_UINT16(s, pdu.importedEntriesCount); /* cacheSlot (2 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) (pdu.importedEntriesCount * 2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
pdu.cacheSlots = (UINT16*) calloc(pdu.importedEntriesCount, sizeof(UINT16));
|
pdu.cacheSlots = (UINT16*) calloc(pdu.importedEntriesCount, sizeof(UINT16));
|
||||||
|
|
||||||
if (!pdu.cacheSlots)
|
if (!pdu.cacheSlots)
|
||||||
@ -260,6 +277,8 @@ int rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea
|
|||||||
context->CacheImportReply(context, &pdu);
|
context->CacheImportReply(context, &pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(pdu.cacheSlots);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,6 +288,9 @@ int rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 7)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.width); /* width (2 bytes) */
|
Stream_Read_UINT16(s, pdu.width); /* width (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.height); /* height (2 bytes) */
|
Stream_Read_UINT16(s, pdu.height); /* height (2 bytes) */
|
||||||
@ -291,6 +313,9 @@ int rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
|
|
||||||
WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteSurfacePdu: surfaceId: %d", pdu.surfaceId);
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteSurfacePdu: surfaceId: %d", pdu.surfaceId);
|
||||||
@ -309,6 +334,9 @@ int rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
|
Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
||||||
|
|
||||||
@ -332,6 +360,9 @@ int rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
|
||||||
|
|
||||||
WLog_Print(gfx->log, WLOG_DEBUG, "RecvEndFramePdu: frameId: %d\n", pdu.frameId);
|
WLog_Print(gfx->log, WLOG_DEBUG, "RecvEndFramePdu: frameId: %d\n", pdu.frameId);
|
||||||
@ -362,6 +393,9 @@ int rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 17)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
||||||
Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */
|
Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */
|
||||||
@ -395,9 +429,16 @@ int rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream
|
|||||||
cmd.length = pdu.bitmapDataLength;
|
cmd.length = pdu.bitmapDataLength;
|
||||||
cmd.data = pdu.bitmapData;
|
cmd.data = pdu.bitmapData;
|
||||||
|
|
||||||
if (context && context->SurfaceCommand)
|
if (cmd.codecId == RDPGFX_CODECID_H264)
|
||||||
{
|
{
|
||||||
context->SurfaceCommand(context, &cmd);
|
rdpgfx_decode(gfx, &cmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (context && context->SurfaceCommand)
|
||||||
|
{
|
||||||
|
context->SurfaceCommand(context, &cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -410,6 +451,9 @@ int rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 13)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
||||||
@ -451,6 +495,9 @@ int rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* callback, w
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 6)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */
|
||||||
|
|
||||||
@ -473,12 +520,16 @@ int rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
|
|
||||||
rdpgfx_read_color32(s, &(pdu.fillPixel)); /* fillPixel (4 bytes) */
|
rdpgfx_read_color32(s, &(pdu.fillPixel)); /* fillPixel (4 bytes) */
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.fillRectCount); /* fillRectCount (2 bytes) */
|
Stream_Read_UINT16(s, pdu.fillRectCount); /* fillRectCount (2 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) (pdu.fillRectCount * 8))
|
||||||
|
return -1;
|
||||||
|
|
||||||
pdu.fillRects = (RDPGFX_RECT16*) calloc(pdu.fillRectCount, sizeof(RDPGFX_RECT16));
|
pdu.fillRects = (RDPGFX_RECT16*) calloc(pdu.fillRectCount, sizeof(RDPGFX_RECT16));
|
||||||
|
|
||||||
if (!pdu.fillRects)
|
if (!pdu.fillRects)
|
||||||
@ -497,6 +548,8 @@ int rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
{
|
{
|
||||||
context->SolidFill(context, &pdu);
|
context->SolidFill(context, &pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(pdu.fillRects);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -509,13 +562,17 @@ int rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 14)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.surfaceIdDest); /* surfaceIdDest (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceIdDest); /* surfaceIdDest (2 bytes) */
|
||||||
|
|
||||||
rdpgfx_read_rect16(s, &(pdu.rectSrc)); /* rectSrc (8 bytes ) */
|
rdpgfx_read_rect16(s, &(pdu.rectSrc)); /* rectSrc (8 bytes ) */
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */
|
Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) (pdu.destPtsCount * 4))
|
||||||
|
return -1;
|
||||||
|
|
||||||
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
||||||
|
|
||||||
if (!pdu.destPts)
|
if (!pdu.destPts)
|
||||||
@ -538,6 +595,8 @@ int rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea
|
|||||||
context->SurfaceToSurface(context, &pdu);
|
context->SurfaceToSurface(context, &pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(pdu.destPts);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,6 +606,9 @@ int rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream*
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 20)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */
|
Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
||||||
@ -574,10 +636,16 @@ int rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream*
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 6)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */
|
Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) (pdu.destPtsCount * 4))
|
||||||
|
return -1;
|
||||||
|
|
||||||
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
||||||
|
|
||||||
if (!pdu.destPts)
|
if (!pdu.destPts)
|
||||||
@ -608,6 +676,9 @@ int rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wSt
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 12)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */
|
Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */
|
Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */
|
||||||
@ -630,6 +701,9 @@ int rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wSt
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 18)
|
||||||
|
return -1;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||||
Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */
|
Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */
|
||||||
Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */
|
Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */
|
||||||
@ -655,7 +729,10 @@ int rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
|
|
||||||
beg = Stream_GetPosition(s);
|
beg = Stream_GetPosition(s);
|
||||||
|
|
||||||
rdpgfx_read_header(s, &header);
|
status = rdpgfx_read_header(s, &header);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
WLog_Print(gfx->log, WLOG_DEBUG, "cmdId: %s (0x%04X) flags: 0x%04X pduLength: %d",
|
WLog_Print(gfx->log, WLOG_DEBUG, "cmdId: %s (0x%04X) flags: 0x%04X pduLength: %d",
|
||||||
@ -733,17 +810,23 @@ int rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Unknown GFX cmdId: 0x%04X\n", header.cmdId);
|
status = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04X)",
|
||||||
|
rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
end = Stream_GetPosition(s);
|
end = Stream_GetPosition(s);
|
||||||
|
|
||||||
if (end != (beg + header.pduLength))
|
if (end != (beg + header.pduLength))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unexpected gfx pdu end: Actual: %d, Expected: %d\n",
|
WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %d",
|
||||||
end, (beg + header.pduLength));
|
end, (beg + header.pduLength));
|
||||||
|
|
||||||
Stream_SetPosition(s, (beg + header.pduLength));
|
Stream_SetPosition(s, (beg + header.pduLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,18 +846,24 @@ static int rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
|||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
printf("zgfx_decompress failure! status: %d\n", status);
|
WLog_DBG(TAG, "zgfx_decompress failure! status: %d", status);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = Stream_New(pDstData, DstSize);
|
s = Stream_New(pDstData, DstSize);
|
||||||
|
|
||||||
while (Stream_GetPosition(s) < Stream_Length(s))
|
while (((size_t) Stream_GetPosition(s)) < Stream_Length(s))
|
||||||
{
|
{
|
||||||
status = rdpgfx_recv_pdu(callback, s);
|
status = rdpgfx_recv_pdu(callback, s);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
|
//free(Stream_Buffer(data));
|
||||||
|
//Stream_Free(data,TRUE);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -960,11 +1049,7 @@ void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot)
|
|||||||
return pData;
|
return pData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STATIC_CHANNELS
|
int rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
#define DVCPluginEntry rdpgfx_DVCPluginEntry
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
RDPGFX_PLUGIN* gfx;
|
RDPGFX_PLUGIN* gfx;
|
||||||
@ -979,7 +1064,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||||||
if (!gfx)
|
if (!gfx)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
gfx->log = WLog_Get("com.freerdp.gfx.client");
|
gfx->log = WLog_Get(TAG);
|
||||||
|
gfx->settings = (rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints);
|
||||||
|
|
||||||
gfx->iface.Initialize = rdpgfx_plugin_initialize;
|
gfx->iface.Initialize = rdpgfx_plugin_initialize;
|
||||||
gfx->iface.Connected = NULL;
|
gfx->iface.Connected = NULL;
|
||||||
@ -991,7 +1077,18 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||||||
if (!gfx->SurfaceTable)
|
if (!gfx->SurfaceTable)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
gfx->ThinClient = TRUE;
|
gfx->ThinClient = gfx->settings->GfxThinClient;
|
||||||
|
gfx->SmallCache = gfx->settings->GfxSmallCache;
|
||||||
|
gfx->Progressive = gfx->settings->GfxProgressive;
|
||||||
|
gfx->ProgressiveV2 = gfx->settings->GfxProgressiveV2;
|
||||||
|
gfx->H264 = gfx->settings->GfxH264;
|
||||||
|
|
||||||
|
if (gfx->H264)
|
||||||
|
gfx->SmallCache = TRUE;
|
||||||
|
|
||||||
|
if (gfx->SmallCache)
|
||||||
|
gfx->ThinClient = FALSE;
|
||||||
|
|
||||||
gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600;
|
gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600;
|
||||||
|
|
||||||
context = (RdpgfxClientContext*) calloc(1, sizeof(RdpgfxClientContext));
|
context = (RdpgfxClientContext*) calloc(1, sizeof(RdpgfxClientContext));
|
||||||
@ -1010,6 +1107,9 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|||||||
|
|
||||||
gfx->zgfx = zgfx_context_new(FALSE);
|
gfx->zgfx = zgfx_context_new(FALSE);
|
||||||
|
|
||||||
|
if (!gfx->zgfx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*) gfx);
|
status = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*) gfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,11 @@
|
|||||||
#include <winpr/collections.h>
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
#include <freerdp/client/rdpgfx.h>
|
#include <freerdp/client/rdpgfx.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/codec/zgfx.h>
|
#include <freerdp/codec/zgfx.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpgfx.client")
|
||||||
|
|
||||||
struct _RDPGFX_CHANNEL_CALLBACK
|
struct _RDPGFX_CHANNEL_CALLBACK
|
||||||
{
|
{
|
||||||
IWTSVirtualChannelCallback iface;
|
IWTSVirtualChannelCallback iface;
|
||||||
@ -59,9 +61,12 @@ struct _RDPGFX_PLUGIN
|
|||||||
RDPGFX_LISTENER_CALLBACK* listener_callback;
|
RDPGFX_LISTENER_CALLBACK* listener_callback;
|
||||||
|
|
||||||
wLog* log;
|
wLog* log;
|
||||||
|
rdpSettings* settings;
|
||||||
|
|
||||||
BOOL ThinClient;
|
BOOL ThinClient;
|
||||||
BOOL SmallCache;
|
BOOL SmallCache;
|
||||||
|
BOOL Progressive;
|
||||||
|
BOOL ProgressiveV2;
|
||||||
BOOL H264;
|
BOOL H264;
|
||||||
|
|
||||||
ZGFX_CONTEXT* zgfx;
|
ZGFX_CONTEXT* zgfx;
|
||||||
|
@ -25,17 +25,7 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
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})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -27,15 +27,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
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} ${ALSA_LIBRARIES})
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/codec/dsp.h>
|
#include <freerdp/codec/dsp.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rdpsnd_main.h"
|
#include "rdpsnd_main.h"
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ struct rdpsnd_alsa_plugin
|
|||||||
#define SND_PCM_CHECK(_func, _status) \
|
#define SND_PCM_CHECK(_func, _status) \
|
||||||
if (_status < 0) \
|
if (_status < 0) \
|
||||||
{ \
|
{ \
|
||||||
fprintf(stderr, "%s: %d\n", _func, _status); \
|
WLog_ERR(TAG, "%s: %d\n", _func, _status); \
|
||||||
return -1; \
|
return -1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +106,8 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa)
|
|||||||
|
|
||||||
if (alsa->buffer_size > buffer_size_max)
|
if (alsa->buffer_size > buffer_size_max)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Warning: requested sound buffer size %d, got %d instead\n",
|
WLog_ERR(TAG, "Warning: requested sound buffer size %d, got %d instead\n",
|
||||||
(int) alsa->buffer_size, (int) buffer_size_max);
|
(int) alsa->buffer_size, (int) buffer_size_max);
|
||||||
alsa->buffer_size = buffer_size_max;
|
alsa->buffer_size = buffer_size_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
|
|||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_mixer_open failed");
|
WLog_ERR(TAG, "snd_mixer_open failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
|
|||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_mixer_attach failed");
|
WLog_ERR(TAG, "snd_mixer_attach failed");
|
||||||
snd_mixer_close(alsa->mixer_handle);
|
snd_mixer_close(alsa->mixer_handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -279,7 +279,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
|
|||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_mixer_selem_register failed");
|
WLog_ERR(TAG, "snd_mixer_selem_register failed");
|
||||||
snd_mixer_close(alsa->mixer_handle);
|
snd_mixer_close(alsa->mixer_handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
|
|||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_mixer_load failed");
|
WLog_ERR(TAG, "snd_mixer_load failed");
|
||||||
snd_mixer_close(alsa->mixer_handle);
|
snd_mixer_close(alsa->mixer_handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ static void rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, i
|
|||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("snd_pcm_open failed");
|
WLog_ERR(TAG, "snd_pcm_open failed");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -579,7 +579,7 @@ static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
|
|||||||
}
|
}
|
||||||
else if (status < 0)
|
else if (status < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "status: %d\n", status);
|
WLog_ERR(TAG, "status: %d\n", status);
|
||||||
snd_pcm_close(alsa->pcm_handle);
|
snd_pcm_close(alsa->pcm_handle);
|
||||||
alsa->pcm_handle = NULL;
|
alsa->pcm_handle = NULL;
|
||||||
rdpsnd_alsa_open((rdpsndDevicePlugin*) alsa, NULL, alsa->latency);
|
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->wLocalTimeB += wave->wPlaybackDelay;
|
||||||
wave->wLatency = (UINT16) (wave->wLocalTimeB - wave->wLocalTimeA);
|
wave->wLatency = (UINT16) (wave->wLocalTimeB - wave->wLocalTimeA);
|
||||||
wave->wTimeStampB = wave->wTimeStampA + wave->wLatency;
|
wave->wTimeStampB = wave->wTimeStampA + wave->wLatency;
|
||||||
|
//WLog_ERR(TAG, "wTimeStampA: %d wTimeStampB: %d wLatency: %d\n", wave->wTimeStampA, wave->wTimeStampB, wave->wLatency);
|
||||||
//fprintf(stderr, "wTimeStampA: %d wTimeStampB: %d wLatency: %d\n", wave->wTimeStampA, wave->wTimeStampB, wave->wLatency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] =
|
static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] =
|
||||||
|
@ -33,16 +33,13 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
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}
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
||||||
${AUDIO_TOOL}
|
${AUDIO_TOOL}
|
||||||
${CORE_AUDIO}
|
${CORE_AUDIO}
|
||||||
${CORE_FOUNDATION})
|
${CORE_FOUNDATION})
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp}
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#define reportResult(result,operation) (_reportResult((result),(operation),__FILE__,__LINE__))
|
#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) {
|
static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
|
||||||
if ( result != ERR_SUCCESS ) {
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -108,7 +108,7 @@ bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
|
|||||||
if ( virtualAddress != bufferAddress+buffer->length ) {
|
if ( virtualAddress != bufferAddress+buffer->length ) {
|
||||||
// If the memory is not contiguous, clean up both allocated buffers and try again
|
// If the memory is not contiguous, clean up both allocated buffers and try again
|
||||||
if ( retries-- == 0 ) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,16 +33,13 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
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}
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
||||||
${AUDIO_TOOL}
|
${AUDIO_TOOL}
|
||||||
${CORE_AUDIO}
|
${CORE_AUDIO}
|
||||||
${CORE_FOUNDATION})
|
${CORE_FOUNDATION})
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp)
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
@ -121,7 +121,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
|
|||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "AudioQueueNewOutput failure\n");
|
WLog_ERR(TAG, "AudioQueueNewOutput failure\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
|
|||||||
|
|
||||||
if (status != 0)
|
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++)
|
for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++)
|
||||||
@ -144,7 +144,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
|
|||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "AudioQueueAllocateBuffer failed\n");
|
WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value)
|
|||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume);
|
WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +238,7 @@ static void rdpsnd_mac_start(rdpsndDevicePlugin* device)
|
|||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "AudioQueueStart failed\n");
|
WLog_ERR(TAG, "AudioQueueStart failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
mac->isPlaying = TRUE;
|
mac->isPlaying = TRUE;
|
||||||
|
@ -28,13 +28,7 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES})
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils
|
|
||||||
${OPENSLES_LIBRARIES})
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES})
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/codec/dsp.h>
|
#include <freerdp/codec/dsp.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "opensl_io.h"
|
#include "opensl_io.h"
|
||||||
#include "rdpsnd_main.h"
|
#include "rdpsnd_main.h"
|
||||||
@ -187,7 +187,7 @@ static void rdpsnd_opensles_open(rdpsndDevicePlugin* device,
|
|||||||
assert(opensles->stream);
|
assert(opensles->stream);
|
||||||
|
|
||||||
if (!opensles->stream)
|
if (!opensles->stream)
|
||||||
DEBUG_WARN("android_OpenAudioDevice failed");
|
WLog_ERR(TAG, "android_OpenAudioDevice failed");
|
||||||
else
|
else
|
||||||
rdpsnd_opensles_set_volume(device, opensles->volume);
|
rdpsnd_opensles_set_volume(device, opensles->volume);
|
||||||
|
|
||||||
@ -364,7 +364,7 @@ static void rdpsnd_opensles_play(rdpsndDevicePlugin* device,
|
|||||||
|
|
||||||
ret = android_AudioOut(opensles->stream, src.s, size / 2);
|
ret = android_AudioOut(opensles->stream, src.s, size / 2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
DEBUG_WARN("android_AudioOut failed (%d)", ret);
|
WLog_ERR(TAG, "android_AudioOut failed (%d)", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_opensles_start(rdpsndDevicePlugin* device)
|
static void rdpsnd_opensles_start(rdpsndDevicePlugin* device)
|
||||||
|
@ -27,12 +27,8 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
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)
|
|
||||||
|
|
||||||
list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY})
|
list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY})
|
||||||
|
list(APPEND ${MODULE_PREFIX}_LIBS freerdp)
|
||||||
|
|
||||||
if(GSM_FOUND)
|
if(GSM_FOUND)
|
||||||
list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES})
|
list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES})
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/utils/signal.h>
|
#include <freerdp/utils/signal.h>
|
||||||
|
|
||||||
#include "rdpsnd_main.h"
|
#include "rdpsnd_main.h"
|
||||||
@ -195,13 +195,12 @@ void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
fprintf(stderr, "Server ");
|
WLog_ERR(TAG, "Server ");
|
||||||
rdpsnd_print_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
|
rdpsnd_print_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
|
||||||
fprintf(stderr, "\n");
|
WLog_ERR(TAG, "\n");
|
||||||
|
WLog_ERR(TAG, "Client ");
|
||||||
fprintf(stderr, "Client ");
|
|
||||||
rdpsnd_print_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
|
rdpsnd_print_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
|
||||||
fprintf(stderr, "\n");
|
WLog_ERR(TAG, "\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,7 +543,7 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
|
|||||||
Stream_Seek_UINT8(s); /* bPad */
|
Stream_Seek_UINT8(s); /* bPad */
|
||||||
Stream_Read_UINT16(s, BodySize);
|
Stream_Read_UINT16(s, BodySize);
|
||||||
|
|
||||||
//fprintf(stderr, "msgType %d BodySize %d\n", msgType, BodySize);
|
//WLog_ERR(TAG, "msgType %d BodySize %d\n", msgType, BodySize);
|
||||||
|
|
||||||
switch (msgType)
|
switch (msgType)
|
||||||
{
|
{
|
||||||
@ -569,7 +568,7 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("unknown msgType %d", msgType);
|
WLog_ERR(TAG, "unknown msgType %d", msgType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,7 +579,7 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlug
|
|||||||
{
|
{
|
||||||
if (rdpsnd->device)
|
if (rdpsnd->device)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("existing device, abort.");
|
WLog_ERR(TAG, "existing device, abort.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,7 +605,7 @@ static BOOL rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD
|
|||||||
|
|
||||||
if (entry(&entryPoints) != 0)
|
if (entry(&entryPoints) != 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("%s entry returns error.", name);
|
WLog_ERR(TAG, "%s entry returns error.", name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,7 +794,7 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
|
|||||||
|
|
||||||
if (!rdpsnd->device)
|
if (!rdpsnd->device)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("no sound device.");
|
WLog_ERR(TAG, "no sound device.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,7 +874,7 @@ int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s)
|
|||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
fprintf(stderr, "rdpdr_virtual_channel_write: VirtualChannelWrite failed %d\n", status);
|
WLog_ERR(TAG, "rdpdr_virtual_channel_write: VirtualChannelWrite failed %d\n", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -907,7 +906,7 @@ static void rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin,
|
|||||||
{
|
{
|
||||||
if (Stream_Capacity(s) != Stream_GetPosition(s))
|
if (Stream_Capacity(s) != Stream_GetPosition(s))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "rdpsnd_virtual_channel_event_data_received: read error\n");
|
WLog_ERR(TAG, "rdpsnd_virtual_channel_event_data_received: read error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin->data_in = NULL;
|
plugin->data_in = NULL;
|
||||||
@ -927,7 +926,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event(DWORD openHandle, UINT e
|
|||||||
|
|
||||||
if (!plugin)
|
if (!plugin)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "rdpsnd_virtual_channel_open_event: error no match\n");
|
WLog_ERR(TAG, "rdpsnd_virtual_channel_open_event: error no match\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,7 +986,7 @@ static void rdpsnd_virtual_channel_event_connected(rdpsndPlugin* plugin, LPVOID
|
|||||||
|
|
||||||
if (status != CHANNEL_RC_OK)
|
if (status != CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "rdpsnd_virtual_channel_event_connected: open failed: status: %d\n", status);
|
WLog_ERR(TAG, "rdpsnd_virtual_channel_event_connected: open failed: status: %d\n", status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1040,7 +1039,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event(LPVOID pInitHandle, UINT
|
|||||||
|
|
||||||
if (!plugin)
|
if (!plugin)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "rdpsnd_virtual_channel_init_event: error no match\n");
|
WLog_ERR(TAG, "rdpsnd_virtual_channel_init_event: error no match\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,12 @@
|
|||||||
#include <freerdp/svc.h>
|
#include <freerdp/svc.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/client/rdpsnd.h>
|
#include <freerdp/client/rdpsnd.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpsnd.client")
|
||||||
|
|
||||||
#if defined(WITH_DEBUG_SND)
|
#if defined(WITH_DEBUG_SND)
|
||||||
#define DEBUG_SND(fmt, ...) DEBUG_CLASS("rdpsnd", fmt, ## __VA_ARGS__)
|
#define DEBUG_SND(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define DEBUG_SND(fmt, ...) do { } while (0)
|
#define DEBUG_SND(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,17 +26,9 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES 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} winmm.lib)
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib)
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp)
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/codec/dsp.h>
|
#include <freerdp/codec/dsp.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rdpsnd_main.h"
|
#include "rdpsnd_main.h"
|
||||||
|
|
||||||
@ -101,11 +102,11 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO
|
|||||||
switch (uMsg)
|
switch (uMsg)
|
||||||
{
|
{
|
||||||
case MM_WOM_OPEN:
|
case MM_WOM_OPEN:
|
||||||
fprintf(stderr, "MM_WOM_OPEN\n");
|
WLog_ERR(TAG, "MM_WOM_OPEN\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MM_WOM_CLOSE:
|
case MM_WOM_CLOSE:
|
||||||
fprintf(stderr, "MM_WOM_CLOSE\n");
|
WLog_ERR(TAG, "MM_WOM_CLOSE\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MM_WOM_DONE:
|
case MM_WOM_DONE:
|
||||||
@ -121,9 +122,8 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO
|
|||||||
if (!wave)
|
if (!wave)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fprintf(stderr, "MM_WOM_DONE: dwBufferLength: %d cBlockNo: %d\n",
|
WLog_ERR(TAG, "MM_WOM_DONE: dwBufferLength: %d cBlockNo: %d\n",
|
||||||
lpWaveHdr->dwBufferLength, wave->cBlockNo);
|
lpWaveHdr->dwBufferLength, wave->cBlockNo);
|
||||||
|
|
||||||
wave->wLocalTimeB = GetTickCount();
|
wave->wLocalTimeB = GetTickCount();
|
||||||
wTimeDelta = wave->wLocalTimeB - wave->wLocalTimeA;
|
wTimeDelta = wave->wLocalTimeB - wave->wLocalTimeA;
|
||||||
wave->wTimeStampB = wave->wTimeStampA + wTimeDelta;
|
wave->wTimeStampB = wave->wTimeStampA + wTimeDelta;
|
||||||
@ -155,7 +155,7 @@ static void rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
|||||||
|
|
||||||
if (mmResult != MMSYSERR_NOERROR)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "waveOutOpen failed: %d\n", mmResult);
|
WLog_ERR(TAG, "waveOutOpen failed: %d\n", mmResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ static void rdpsnd_winmm_close(rdpsndDevicePlugin* device)
|
|||||||
|
|
||||||
if (mmResult != MMSYSERR_NOERROR)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "waveOutClose failure: %d\n", mmResult);
|
WLog_ERR(TAG, "waveOutClose failure: %d\n", mmResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
winmm->hWaveOut = NULL;
|
winmm->hWaveOut = NULL;
|
||||||
@ -299,7 +299,7 @@ void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
|
|||||||
|
|
||||||
if (mmResult != MMSYSERR_NOERROR)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "waveOutPrepareHeader failure: %d\n", mmResult);
|
WLog_ERR(TAG, "waveOutPrepareHeader failure: %d\n", mmResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +307,7 @@ void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
|
|||||||
|
|
||||||
if (mmResult != MMSYSERR_NOERROR)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "waveOutWrite failure: %d\n", mmResult);
|
WLog_ERR(TAG, "waveOutWrite failure: %d\n", mmResult);
|
||||||
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,7 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -29,9 +29,11 @@
|
|||||||
#include <winpr/print.h>
|
#include <winpr/print.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rdpsnd_main.h"
|
#include "rdpsnd_main.h"
|
||||||
|
|
||||||
static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
||||||
{
|
{
|
||||||
int pos;
|
int pos;
|
||||||
UINT16 i;
|
UINT16 i;
|
||||||
@ -107,8 +109,7 @@ static BOOL rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStrea
|
|||||||
|
|
||||||
Stream_Read_UINT16(s, quality);
|
Stream_Read_UINT16(s, quality);
|
||||||
Stream_Seek_UINT16(s); // reserved
|
Stream_Seek_UINT16(s); // reserved
|
||||||
|
WLog_ERR(TAG, "Client requested sound quality: %#0X\n", quality);
|
||||||
fprintf(stderr, "Client requested sound quality: %#0X\n", quality);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
|
|||||||
{
|
{
|
||||||
int i, num_known_format = 0;
|
int i, num_known_format = 0;
|
||||||
UINT32 flags, vol, pitch;
|
UINT32 flags, vol, pitch;
|
||||||
UINT16 udpPort, version;
|
UINT16 udpPort;
|
||||||
BYTE lastblock;
|
BYTE lastblock;
|
||||||
|
|
||||||
if (Stream_GetRemainingLength(s) < 20)
|
if (Stream_GetRemainingLength(s) < 20)
|
||||||
@ -128,7 +129,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
|
|||||||
Stream_Read_UINT16(s, udpPort); /* wDGramPort */
|
Stream_Read_UINT16(s, udpPort); /* wDGramPort */
|
||||||
Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
|
Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
|
||||||
Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
|
Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
|
||||||
Stream_Read_UINT16(s, version); /* wVersion */
|
Stream_Read_UINT16(s, context->clientVersion); /* wVersion */
|
||||||
Stream_Seek_UINT8(s); /* bPad */
|
Stream_Seek_UINT8(s); /* bPad */
|
||||||
|
|
||||||
/* this check is only a guess as cbSize can influence the size of a format record */
|
/* this check is only a guess as cbSize can influence the size of a format record */
|
||||||
@ -137,7 +138,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
|
|||||||
|
|
||||||
if (!context->num_client_formats)
|
if (!context->num_client_formats)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: client doesn't support any format!\n", __FUNCTION__);
|
WLog_ERR(TAG, "%s: client doesn't support any format!\n", __FUNCTION__);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
|
|||||||
|
|
||||||
if (!context->num_client_formats)
|
if (!context->num_client_formats)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: client doesn't support any known format!\n", __FUNCTION__);
|
WLog_ERR(TAG, "%s: client doesn't support any known format!\n", __FUNCTION__);
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,49 +188,20 @@ out_free:
|
|||||||
|
|
||||||
static void* rdpsnd_server_thread(void* arg)
|
static void* rdpsnd_server_thread(void* arg)
|
||||||
{
|
{
|
||||||
wStream* s;
|
DWORD nCount, status;
|
||||||
DWORD status;
|
|
||||||
DWORD nCount;
|
|
||||||
void* buffer;
|
|
||||||
BYTE msgType;
|
|
||||||
UINT16 BodySize;
|
|
||||||
HANDLE events[8];
|
HANDLE events[8];
|
||||||
HANDLE ChannelEvent;
|
|
||||||
DWORD bytesReturned;
|
|
||||||
RdpsndServerContext* context;
|
RdpsndServerContext* context;
|
||||||
BOOL doRun;
|
BOOL doRun;
|
||||||
BOOL waitingHeader;
|
|
||||||
DWORD expectedBytes;
|
|
||||||
|
|
||||||
context = (RdpsndServerContext *)arg;
|
context = (RdpsndServerContext *)arg;
|
||||||
|
|
||||||
buffer = NULL;
|
|
||||||
bytesReturned = 0;
|
|
||||||
|
|
||||||
s = Stream_New(NULL, 4096);
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n",
|
|
||||||
__FUNCTION__, bytesReturned);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
|
||||||
WTSFreeMemory(buffer);
|
|
||||||
|
|
||||||
nCount = 0;
|
nCount = 0;
|
||||||
events[nCount++] = ChannelEvent;
|
events[nCount++] = context->priv->channelEvent;
|
||||||
events[nCount++] = context->priv->StopEvent;
|
events[nCount++] = context->priv->StopEvent;
|
||||||
|
|
||||||
if (!rdpsnd_server_send_formats(context, s))
|
if (!rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
doRun = TRUE;
|
doRun = TRUE;
|
||||||
waitingHeader = TRUE;
|
|
||||||
expectedBytes = 4;
|
|
||||||
while (doRun)
|
while (doRun)
|
||||||
{
|
{
|
||||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||||
@ -237,69 +209,17 @@ static void* rdpsnd_server_thread(void* arg)
|
|||||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!WTSVirtualChannelRead(ChannelEvent, 0, (PCHAR)Stream_Pointer(s), expectedBytes, &bytesReturned))
|
if (rdpsnd_server_handle_messages(context) == 0)
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
expectedBytes -= bytesReturned;
|
|
||||||
Stream_Seek(s, bytesReturned);
|
|
||||||
|
|
||||||
if (expectedBytes)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Stream_SetPosition(s, 0);
|
|
||||||
if (waitingHeader)
|
|
||||||
{
|
|
||||||
/* header case */
|
|
||||||
Stream_Read_UINT8(s, msgType);
|
|
||||||
Stream_Seek_UINT8(s); /* bPad */
|
|
||||||
Stream_Read_UINT16(s, BodySize);
|
|
||||||
|
|
||||||
expectedBytes = BodySize;
|
|
||||||
waitingHeader = FALSE;
|
|
||||||
Stream_SetPosition(s, 0);
|
|
||||||
Stream_EnsureCapacity(s, BodySize);
|
|
||||||
if (expectedBytes)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* when here we have the header + the body */
|
|
||||||
switch (msgType)
|
|
||||||
{
|
|
||||||
case SNDC_WAVECONFIRM:
|
|
||||||
doRun = rdpsnd_server_recv_waveconfirm(context, s);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SNDC_QUALITYMODE:
|
|
||||||
doRun = rdpsnd_server_recv_quality_mode(context, s);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SNDC_FORMATS:
|
|
||||||
doRun = rdpsnd_server_recv_formats(context, s);
|
|
||||||
if (doRun)
|
|
||||||
{
|
|
||||||
IFCALL(context->Activated, context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedBytes = 4;
|
|
||||||
waitingHeader = TRUE;
|
|
||||||
Stream_SetPosition(s, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
Stream_Free(s, TRUE);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL rdpsnd_server_initialize(RdpsndServerContext* context)
|
static BOOL rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
|
||||||
{
|
{
|
||||||
|
context->priv->ownThread = ownThread;
|
||||||
return context->Start(context) >= 0;
|
return context->Start(context) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +231,7 @@ static BOOL rdpsnd_server_select_format(RdpsndServerContext* context, int client
|
|||||||
|
|
||||||
if (client_format_index < 0 || client_format_index >= context->num_client_formats)
|
if (client_format_index < 0 || client_format_index >= context->num_client_formats)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: index %d is not correct.\n", __FUNCTION__, client_format_index);
|
WLog_ERR(TAG, "%s: index %d is not correct.\n", __FUNCTION__, client_format_index);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,7 +243,7 @@ static BOOL rdpsnd_server_select_format(RdpsndServerContext* context, int client
|
|||||||
|
|
||||||
if (format->nSamplesPerSec == 0)
|
if (format->nSamplesPerSec == 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: invalid Client Sound Format!!\n", __FUNCTION__);
|
WLog_ERR(TAG, "%s: invalid Client Sound Format!!\n", __FUNCTION__);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,22 +466,42 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
|||||||
|
|
||||||
static int rdpsnd_server_start(RdpsndServerContext* context)
|
static int rdpsnd_server_start(RdpsndServerContext* context)
|
||||||
{
|
{
|
||||||
context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd");
|
void *buffer = NULL;
|
||||||
if (!context->priv->ChannelHandle)
|
DWORD bytesReturned;
|
||||||
|
RdpsndServerPrivate *priv = context->priv;
|
||||||
|
|
||||||
|
priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd");
|
||||||
|
if (!priv->ChannelHandle)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
context->priv->rdpsnd_pdu = Stream_New(NULL, 4096);
|
if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE)))
|
||||||
if (!context->priv->rdpsnd_pdu)
|
{
|
||||||
|
WLog_ERR(TAG, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n",
|
||||||
|
__FUNCTION__, bytesReturned);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
WTSFreeMemory(buffer);
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE));
|
||||||
|
WTSFreeMemory(buffer);
|
||||||
|
|
||||||
|
priv->rdpsnd_pdu = Stream_New(NULL, 4096);
|
||||||
|
if (!priv->rdpsnd_pdu)
|
||||||
goto out_close;
|
goto out_close;
|
||||||
|
|
||||||
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
if (!context->priv->StopEvent)
|
|
||||||
goto out_pdu;
|
|
||||||
|
|
||||||
context->priv->Thread = CreateThread(NULL, 0,
|
if (priv->ownThread)
|
||||||
(LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL);
|
{
|
||||||
if (!context->priv->Thread)
|
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
goto out_stopEvent;
|
if (!context->priv->StopEvent)
|
||||||
|
goto out_pdu;
|
||||||
|
|
||||||
|
context->priv->Thread = CreateThread(NULL, 0,
|
||||||
|
(LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL);
|
||||||
|
if (!context->priv->Thread)
|
||||||
|
goto out_stopEvent;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -579,12 +519,15 @@ out_close:
|
|||||||
|
|
||||||
static int rdpsnd_server_stop(RdpsndServerContext* context)
|
static int rdpsnd_server_stop(RdpsndServerContext* context)
|
||||||
{
|
{
|
||||||
if (context->priv->StopEvent)
|
if (context->priv->ownThread)
|
||||||
{
|
{
|
||||||
SetEvent(context->priv->StopEvent);
|
if (context->priv->StopEvent)
|
||||||
|
{
|
||||||
|
SetEvent(context->priv->StopEvent);
|
||||||
|
|
||||||
WaitForSingleObject(context->priv->Thread, INFINITE);
|
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||||
CloseHandle(context->priv->Thread);
|
CloseHandle(context->priv->Thread);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -593,8 +536,9 @@ static int rdpsnd_server_stop(RdpsndServerContext* context)
|
|||||||
RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
|
RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
|
||||||
{
|
{
|
||||||
RdpsndServerContext* context;
|
RdpsndServerContext* context;
|
||||||
|
RdpsndServerPrivate *priv;
|
||||||
|
|
||||||
context = (RdpsndServerContext*) calloc(1, sizeof(RdpsndServerContext));
|
context = (RdpsndServerContext *)calloc(1, sizeof(RdpsndServerContext));
|
||||||
if (!context)
|
if (!context)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -610,16 +554,25 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
|
|||||||
context->SetVolume = rdpsnd_server_set_volume;
|
context->SetVolume = rdpsnd_server_set_volume;
|
||||||
context->Close = rdpsnd_server_close;
|
context->Close = rdpsnd_server_close;
|
||||||
|
|
||||||
context->priv = (RdpsndServerPrivate*) calloc(1, sizeof(RdpsndServerPrivate));
|
context->priv = priv = (RdpsndServerPrivate *)calloc(1, sizeof(RdpsndServerPrivate));
|
||||||
if (!context->priv)
|
if (!priv)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
context->priv->dsp_context = freerdp_dsp_context_new();
|
priv->dsp_context = freerdp_dsp_context_new();
|
||||||
if (!context->priv->dsp_context)
|
if (!priv->dsp_context)
|
||||||
goto out_free_priv;
|
goto out_free_priv;
|
||||||
|
|
||||||
|
priv->input_stream = Stream_New(NULL, 4);
|
||||||
|
if (!priv->input_stream)
|
||||||
|
goto out_free_dsp;
|
||||||
|
|
||||||
|
priv->expectedBytes = 4;
|
||||||
|
priv->waitingHeader = TRUE;
|
||||||
|
priv->ownThread = TRUE;
|
||||||
return context;
|
return context;
|
||||||
|
|
||||||
|
out_free_dsp:
|
||||||
|
freerdp_dsp_context_free(priv->dsp_context);
|
||||||
out_free_priv:
|
out_free_priv:
|
||||||
free(context->priv);
|
free(context->priv);
|
||||||
out_free:
|
out_free:
|
||||||
@ -627,6 +580,15 @@ out_free:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rdpsnd_server_context_reset(RdpsndServerContext *context)
|
||||||
|
{
|
||||||
|
context->priv->expectedBytes = 4;
|
||||||
|
context->priv->waitingHeader = TRUE;
|
||||||
|
|
||||||
|
Stream_SetPosition(context->priv->input_stream, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void rdpsnd_server_context_free(RdpsndServerContext* context)
|
void rdpsnd_server_context_free(RdpsndServerContext* context)
|
||||||
{
|
{
|
||||||
if (!context->priv->StopEvent)
|
if (!context->priv->StopEvent)
|
||||||
@ -652,3 +614,99 @@ void rdpsnd_server_context_free(RdpsndServerContext* context)
|
|||||||
|
|
||||||
free(context);
|
free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext *context)
|
||||||
|
{
|
||||||
|
return context->priv->channelEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle rpdsnd messages - server side
|
||||||
|
*
|
||||||
|
* @param Server side context
|
||||||
|
*
|
||||||
|
* @return -1 if no data could be read,
|
||||||
|
* 0 on error (like connection close),
|
||||||
|
* 1 on succsess (also if further bytes need to be read)
|
||||||
|
*/
|
||||||
|
int rdpsnd_server_handle_messages(RdpsndServerContext *context)
|
||||||
|
{
|
||||||
|
DWORD bytesReturned;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
RdpsndServerPrivate *priv = context->priv;
|
||||||
|
wStream *s = priv->input_stream;
|
||||||
|
|
||||||
|
if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned))
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_NO_DATA)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
WLog_ERR(TAG, "%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->waitingHeader)
|
||||||
|
{
|
||||||
|
/* header case */
|
||||||
|
Stream_Read_UINT8(s, priv->msgType);
|
||||||
|
Stream_Seek_UINT8(s); /* bPad */
|
||||||
|
Stream_Read_UINT16(s, priv->expectedBytes);
|
||||||
|
|
||||||
|
priv->waitingHeader = FALSE;
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
if (priv->expectedBytes)
|
||||||
|
{
|
||||||
|
Stream_EnsureCapacity(s, priv->expectedBytes);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* when here we have the header + the body */
|
||||||
|
#ifdef WITH_DEBUG_SND
|
||||||
|
WLog_DBG(TAG, "message type %d", priv->msgType);
|
||||||
|
#endif
|
||||||
|
priv->expectedBytes = 4;
|
||||||
|
priv->waitingHeader = TRUE;
|
||||||
|
|
||||||
|
switch (priv->msgType)
|
||||||
|
{
|
||||||
|
case SNDC_WAVECONFIRM:
|
||||||
|
ret = rdpsnd_server_recv_waveconfirm(context, s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SNDC_FORMATS:
|
||||||
|
ret = rdpsnd_server_recv_formats(context, s);
|
||||||
|
|
||||||
|
if (ret && context->clientVersion < 6)
|
||||||
|
IFCALL(context->Activated, context);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SNDC_QUALITYMODE:
|
||||||
|
ret = rdpsnd_server_recv_quality_mode(context, s);
|
||||||
|
Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */
|
||||||
|
|
||||||
|
if (ret && context->clientVersion >= 6)
|
||||||
|
IFCALL(context->Activated, context);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
WLog_ERR(TAG, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, priv->msgType);
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -27,14 +27,23 @@
|
|||||||
|
|
||||||
#include <freerdp/codec/dsp.h>
|
#include <freerdp/codec/dsp.h>
|
||||||
#include <freerdp/channels/wtsvc.h>
|
#include <freerdp/channels/wtsvc.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/server/rdpsnd.h>
|
#include <freerdp/server/rdpsnd.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpsnd.server")
|
||||||
|
|
||||||
struct _rdpsnd_server_private
|
struct _rdpsnd_server_private
|
||||||
{
|
{
|
||||||
|
BOOL ownThread;
|
||||||
HANDLE Thread;
|
HANDLE Thread;
|
||||||
HANDLE StopEvent;
|
HANDLE StopEvent;
|
||||||
|
HANDLE channelEvent;
|
||||||
void* ChannelHandle;
|
void* ChannelHandle;
|
||||||
|
|
||||||
|
BOOL waitingHeader;
|
||||||
|
DWORD expectedBytes;
|
||||||
|
BYTE msgType;
|
||||||
|
wStream* input_stream;
|
||||||
wStream* rdpsnd_pdu;
|
wStream* rdpsnd_pdu;
|
||||||
BYTE* out_buffer;
|
BYTE* out_buffer;
|
||||||
int out_buffer_size;
|
int out_buffer_size;
|
||||||
|
26
channels/remdesk/CMakeLists.txt
Normal file
26
channels/remdesk/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# 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("remdesk")
|
||||||
|
|
||||||
|
if(WITH_CLIENT_CHANNELS)
|
||||||
|
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_SERVER_CHANNELS)
|
||||||
|
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||||
|
endif()
|
12
channels/remdesk/ChannelOptions.cmake
Normal file
12
channels/remdesk/ChannelOptions.cmake
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
set(OPTION_DEFAULT OFF)
|
||||||
|
set(OPTION_CLIENT_DEFAULT ON)
|
||||||
|
set(OPTION_SERVER_DEFAULT ON)
|
||||||
|
|
||||||
|
define_channel_options(NAME "remdesk" TYPE "static"
|
||||||
|
DESCRIPTION "Remote Assistance Virtual Channel Extension"
|
||||||
|
SPECIFICATIONS "[MS-RA]"
|
||||||
|
DEFAULT ${OPTION_DEFAULT})
|
||||||
|
|
||||||
|
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||||
|
define_channel_server_options(${OPTION_SERVER_DEFAULT})
|
32
channels/remdesk/client/CMakeLists.txt
Normal file
32
channels/remdesk/client/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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_client("remdesk")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_SRCS
|
||||||
|
remdesk_main.c
|
||||||
|
remdesk_main.h)
|
||||||
|
|
||||||
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
|
|
||||||
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
803
channels/remdesk/client/remdesk_main.c
Normal file
803
channels/remdesk/client/remdesk_main.c
Normal file
@ -0,0 +1,803 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Remote Assistance 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/assistance.h>
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
#include <freerdp/client/remdesk.h>
|
||||||
|
|
||||||
|
#include "remdesk_main.h"
|
||||||
|
|
||||||
|
RemdeskClientContext* remdesk_get_client_interface(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
RemdeskClientContext* pInterface;
|
||||||
|
pInterface = (RemdeskClientContext*) remdesk->channelEntryPoints.pInterface;
|
||||||
|
return pInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s)
|
||||||
|
{
|
||||||
|
UINT32 status = 0;
|
||||||
|
|
||||||
|
if (!remdesk)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
status = remdesk->channelEntryPoints.pVirtualChannelWrite(remdesk->OpenHandle,
|
||||||
|
Stream_Buffer(s), (UINT32) Stream_Length(s), s);
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "VirtualChannelWrite failed %d", status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remdesk_generate_expert_blob(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
char* pass;
|
||||||
|
char* password;
|
||||||
|
rdpSettings* settings = remdesk->settings;
|
||||||
|
|
||||||
|
if (remdesk->ExpertBlob)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (settings->RemoteAssistancePassword)
|
||||||
|
password = settings->RemoteAssistancePassword;
|
||||||
|
else
|
||||||
|
password = settings->Password;
|
||||||
|
|
||||||
|
if (!password)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
name = settings->Username;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
name = "Expert";
|
||||||
|
|
||||||
|
remdesk->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(password,
|
||||||
|
settings->RemoteAssistancePassStub, &(remdesk->EncryptedPassStubSize));
|
||||||
|
|
||||||
|
if (!remdesk->EncryptedPassStub)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub, remdesk->EncryptedPassStubSize);
|
||||||
|
|
||||||
|
if (!pass)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass);
|
||||||
|
|
||||||
|
if (!remdesk->ExpertBlob)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
UINT32 ChannelNameLen;
|
||||||
|
char* pChannelName = NULL;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */
|
||||||
|
|
||||||
|
if (ChannelNameLen > 64)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((ChannelNameLen % 2) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < ChannelNameLen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ZeroMemory(header->ChannelName, sizeof(header->ChannelName));
|
||||||
|
|
||||||
|
pChannelName = (char*) header->ChannelName;
|
||||||
|
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
||||||
|
ChannelNameLen / 2, &pChannelName, 32, NULL, NULL);
|
||||||
|
|
||||||
|
Stream_Seek(s, ChannelNameLen);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
UINT32 ChannelNameLen;
|
||||||
|
WCHAR ChannelNameW[32];
|
||||||
|
|
||||||
|
ZeroMemory(ChannelNameW, sizeof(ChannelNameW));
|
||||||
|
|
||||||
|
for (index = 0; index < 32; index++)
|
||||||
|
{
|
||||||
|
ChannelNameW[index] = (WCHAR) header->ChannelName[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelNameLen = (strlen(header->ChannelName) + 1) * 2;
|
||||||
|
|
||||||
|
Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */
|
||||||
|
Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */
|
||||||
|
|
||||||
|
Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader)
|
||||||
|
{
|
||||||
|
remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader);
|
||||||
|
Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize)
|
||||||
|
{
|
||||||
|
ctlHeader->msgType = msgType;
|
||||||
|
strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME);
|
||||||
|
ctlHeader->DataLength = 4 + msgSize;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
UINT32 versionMajor;
|
||||||
|
UINT32 versionMinor;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
wStream* s;
|
||||||
|
REMDESK_CTL_VERSION_INFO_PDU pdu;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
|
||||||
|
|
||||||
|
pdu.versionMajor = 1;
|
||||||
|
pdu.versionMinor = 2;
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */
|
||||||
|
Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(remdesk, s);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_result_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header, UINT32 *pResult)
|
||||||
|
{
|
||||||
|
UINT32 result;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, result); /* result (4 bytes) */
|
||||||
|
|
||||||
|
*pResult = result;
|
||||||
|
//WLog_DBG(TAG, "RemdeskRecvResult: 0x%04X", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
wStream* s;
|
||||||
|
int cbExpertBlobW = 0;
|
||||||
|
WCHAR* expertBlobW = NULL;
|
||||||
|
int cbRaConnectionStringW = 0;
|
||||||
|
WCHAR* raConnectionStringW = NULL;
|
||||||
|
REMDESK_CTL_AUTHENTICATE_PDU pdu;
|
||||||
|
|
||||||
|
status = remdesk_generate_expert_blob(remdesk);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pdu.expertBlob = remdesk->ExpertBlob;
|
||||||
|
pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket;
|
||||||
|
|
||||||
|
status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cbRaConnectionStringW = status * 2;
|
||||||
|
|
||||||
|
status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cbExpertBlobW = status * 2;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE,
|
||||||
|
cbRaConnectionStringW + cbExpertBlobW);
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW);
|
||||||
|
Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW);
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(remdesk, s);
|
||||||
|
|
||||||
|
free(raConnectionStringW);
|
||||||
|
free(expertBlobW);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
wStream* s;
|
||||||
|
int cbRaConnectionStringW = 0;
|
||||||
|
WCHAR* raConnectionStringW = NULL;
|
||||||
|
REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu;
|
||||||
|
|
||||||
|
pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket;
|
||||||
|
|
||||||
|
status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cbRaConnectionStringW = status * 2;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_REMOTE_CONTROL_DESKTOP, cbRaConnectionStringW);
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW);
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(remdesk, s);
|
||||||
|
|
||||||
|
free(raConnectionStringW);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
wStream* s;
|
||||||
|
int cbExpertBlobW = 0;
|
||||||
|
WCHAR* expertBlobW = NULL;
|
||||||
|
REMDESK_CTL_VERIFY_PASSWORD_PDU pdu;
|
||||||
|
|
||||||
|
status = remdesk_generate_expert_blob(remdesk);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pdu.expertBlob = remdesk->ExpertBlob;
|
||||||
|
|
||||||
|
status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cbExpertBlobW = status * 2;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW);
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(remdesk, s);
|
||||||
|
|
||||||
|
free(expertBlobW);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
wStream* s;
|
||||||
|
REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu;
|
||||||
|
|
||||||
|
status = remdesk_generate_expert_blob(remdesk);
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pdu.EncryptedPasswordLength = remdesk->EncryptedPassStubSize;
|
||||||
|
pdu.EncryptedPassword = remdesk->EncryptedPassStub;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
|
||||||
|
pdu.EncryptedPasswordLength);
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(remdesk, s);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
UINT32 msgType = 0;
|
||||||
|
UINT32 result = 0;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
|
||||||
|
|
||||||
|
//WLog_DBG(TAG, "msgType: %d", msgType);
|
||||||
|
|
||||||
|
switch (msgType)
|
||||||
|
{
|
||||||
|
case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_RESULT:
|
||||||
|
status = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_AUTHENTICATE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_SERVER_ANNOUNCE:
|
||||||
|
status = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_DISCONNECT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_VERSIONINFO:
|
||||||
|
status = remdesk_recv_ctl_version_info_pdu(remdesk, s, header);
|
||||||
|
|
||||||
|
if (remdesk->Version == 1)
|
||||||
|
{
|
||||||
|
if (status >= 0)
|
||||||
|
status = remdesk_send_ctl_version_info_pdu(remdesk);
|
||||||
|
|
||||||
|
if (status >= 0)
|
||||||
|
status = remdesk_send_ctl_authenticate_pdu(remdesk);
|
||||||
|
|
||||||
|
if (status >= 0)
|
||||||
|
status = remdesk_send_ctl_remote_control_desktop_pdu(remdesk);
|
||||||
|
}
|
||||||
|
else if (remdesk->Version == 2)
|
||||||
|
{
|
||||||
|
if (status >= 0)
|
||||||
|
status = remdesk_send_ctl_expert_on_vista_pdu(remdesk);
|
||||||
|
|
||||||
|
if (status >= 0)
|
||||||
|
status = remdesk_send_ctl_verify_password_pdu(remdesk);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_ISCONNECTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_VERIFY_PASSWORD:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_EXPERT_ON_VISTA:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_RANOVICE_NAME:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_RAEXPERT_NAME:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_TOKEN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
WLog_ERR(TAG, "unknown msgType: %d", msgType);
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
REMDESK_CHANNEL_HEADER header;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
WLog_DBG(TAG, "RemdeskReceive: %d", Stream_GetRemainingLength(s));
|
||||||
|
winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
remdesk_read_channel_header(s, &header);
|
||||||
|
|
||||||
|
if (strcmp(header.ChannelName, "RC_CTL") == 0)
|
||||||
|
{
|
||||||
|
status = remdesk_recv_ctl_pdu(remdesk, s, &header);
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "70") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "71") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, ".") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "1000.") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "RA_FX") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remdesk_process_connect(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
remdesk->settings = (rdpSettings*) remdesk->channelEntryPoints.pExtendedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
static wListDictionary* g_InitHandles;
|
||||||
|
static wListDictionary* g_OpenHandles;
|
||||||
|
|
||||||
|
void remdesk_add_init_handle_data(void* pInitHandle, void* pUserData)
|
||||||
|
{
|
||||||
|
if (!g_InitHandles)
|
||||||
|
g_InitHandles = ListDictionary_New(TRUE);
|
||||||
|
|
||||||
|
ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* remdesk_get_init_handle_data(void* pInitHandle)
|
||||||
|
{
|
||||||
|
void* pUserData = NULL;
|
||||||
|
pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
|
||||||
|
return pUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remdesk_remove_init_handle_data(void* pInitHandle)
|
||||||
|
{
|
||||||
|
ListDictionary_Remove(g_InitHandles, pInitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remdesk_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* remdesk_get_open_handle_data(DWORD openHandle)
|
||||||
|
{
|
||||||
|
void* pUserData = NULL;
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
|
||||||
|
return pUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remdesk_remove_open_handle_data(DWORD openHandle)
|
||||||
|
{
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
ListDictionary_Remove(g_OpenHandles, pOpenHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int remdesk_send(remdeskPlugin* remdesk, wStream* s)
|
||||||
|
{
|
||||||
|
UINT32 status = 0;
|
||||||
|
remdeskPlugin* plugin = (remdeskPlugin*) remdesk;
|
||||||
|
|
||||||
|
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, "VirtualChannelWrite failed %d", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk,
|
||||||
|
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 (remdesk->data_in)
|
||||||
|
Stream_Free(remdesk->data_in, TRUE);
|
||||||
|
|
||||||
|
remdesk->data_in = Stream_New(NULL, totalLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_in = remdesk->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, "read error");
|
||||||
|
}
|
||||||
|
|
||||||
|
remdesk->data_in = NULL;
|
||||||
|
Stream_SealLength(data_in);
|
||||||
|
Stream_SetPosition(data_in, 0);
|
||||||
|
|
||||||
|
MessageQueue_Post(remdesk->MsgPipe->In, NULL, 0, (void*) data_in, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID VCAPITYPE remdesk_virtual_channel_open_event(DWORD openHandle, UINT event,
|
||||||
|
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
|
||||||
|
{
|
||||||
|
remdeskPlugin* remdesk;
|
||||||
|
|
||||||
|
remdesk = (remdeskPlugin*) remdesk_get_open_handle_data(openHandle);
|
||||||
|
|
||||||
|
if (!remdesk)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "error no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case CHANNEL_EVENT_DATA_RECEIVED:
|
||||||
|
remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength, totalLength, dataFlags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_WRITE_COMPLETE:
|
||||||
|
Stream_Free((wStream*) pData, TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_USER:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* remdesk_virtual_channel_client_thread(void* arg)
|
||||||
|
{
|
||||||
|
wStream* data;
|
||||||
|
wMessage message;
|
||||||
|
remdeskPlugin* remdesk = (remdeskPlugin*) arg;
|
||||||
|
|
||||||
|
remdesk_process_connect(remdesk);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!MessageQueue_Wait(remdesk->MsgPipe->In))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (MessageQueue_Peek(remdesk->MsgPipe->In, &message, TRUE))
|
||||||
|
{
|
||||||
|
if (message.id == WMQ_QUIT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (message.id == 0)
|
||||||
|
{
|
||||||
|
data = (wStream*) message.wParam;
|
||||||
|
remdesk_process_receive(remdesk, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitThread(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData, UINT32 dataLength)
|
||||||
|
{
|
||||||
|
UINT32 status;
|
||||||
|
|
||||||
|
status = remdesk->channelEntryPoints.pVirtualChannelOpen(remdesk->InitHandle,
|
||||||
|
&remdesk->OpenHandle, remdesk->channelDef.name, remdesk_virtual_channel_open_event);
|
||||||
|
|
||||||
|
remdesk_add_open_handle_data(remdesk->OpenHandle, remdesk);
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "open failed: status: %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remdesk->MsgPipe = MessagePipe_New();
|
||||||
|
|
||||||
|
remdesk->thread = CreateThread(NULL, 0,
|
||||||
|
(LPTHREAD_START_ROUTINE) remdesk_virtual_channel_client_thread, (void*) remdesk, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
|
||||||
|
{
|
||||||
|
MessagePipe_PostQuit(remdesk->MsgPipe, 0);
|
||||||
|
WaitForSingleObject(remdesk->thread, INFINITE);
|
||||||
|
|
||||||
|
MessagePipe_Free(remdesk->MsgPipe);
|
||||||
|
CloseHandle(remdesk->thread);
|
||||||
|
|
||||||
|
remdesk->channelEntryPoints.pVirtualChannelClose(remdesk->OpenHandle);
|
||||||
|
|
||||||
|
if (remdesk->data_in)
|
||||||
|
{
|
||||||
|
Stream_Free(remdesk->data_in, TRUE);
|
||||||
|
remdesk->data_in = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
remdesk_remove_open_handle_data(remdesk->OpenHandle);
|
||||||
|
remdesk_remove_init_handle_data(remdesk->InitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID VCAPITYPE remdesk_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
|
||||||
|
{
|
||||||
|
remdeskPlugin* remdesk;
|
||||||
|
|
||||||
|
remdesk = (remdeskPlugin*) remdesk_get_init_handle_data(pInitHandle);
|
||||||
|
|
||||||
|
if (!remdesk)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "error no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case CHANNEL_EVENT_CONNECTED:
|
||||||
|
remdesk_virtual_channel_event_connected(remdesk, pData, dataLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_DISCONNECTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_TERMINATED:
|
||||||
|
remdesk_virtual_channel_event_terminated(remdesk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remdesk is always built-in */
|
||||||
|
#define VirtualChannelEntry remdesk_VirtualChannelEntry
|
||||||
|
|
||||||
|
BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||||
|
{
|
||||||
|
remdeskPlugin* remdesk;
|
||||||
|
RemdeskClientContext* context;
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
|
||||||
|
|
||||||
|
remdesk = (remdeskPlugin*) calloc(1, sizeof(remdeskPlugin));
|
||||||
|
|
||||||
|
if (!remdesk)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
remdesk->channelDef.options =
|
||||||
|
CHANNEL_OPTION_INITIALIZED |
|
||||||
|
CHANNEL_OPTION_ENCRYPT_RDP |
|
||||||
|
CHANNEL_OPTION_COMPRESS_RDP |
|
||||||
|
CHANNEL_OPTION_SHOW_PROTOCOL;
|
||||||
|
|
||||||
|
strcpy(remdesk->channelDef.name, "remdesk");
|
||||||
|
|
||||||
|
remdesk->Version = 2;
|
||||||
|
|
||||||
|
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
|
||||||
|
|
||||||
|
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
|
||||||
|
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
||||||
|
{
|
||||||
|
context = (RemdeskClientContext*) calloc(1, sizeof(RemdeskClientContext));
|
||||||
|
|
||||||
|
context->handle = (void*) remdesk;
|
||||||
|
|
||||||
|
*(pEntryPointsEx->ppInterface) = (void*) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
|
||||||
|
|
||||||
|
remdesk->channelEntryPoints.pVirtualChannelInit(&remdesk->InitHandle,
|
||||||
|
&remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, remdesk_virtual_channel_init_event);
|
||||||
|
|
||||||
|
remdesk->channelEntryPoints.pInterface = *(remdesk->channelEntryPoints.ppInterface);
|
||||||
|
remdesk->channelEntryPoints.ppInterface = &(remdesk->channelEntryPoints.pInterface);
|
||||||
|
|
||||||
|
remdesk_add_init_handle_data(remdesk->InitHandle, (void*) remdesk);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
58
channels/remdesk/client/remdesk_main.h
Normal file
58
channels/remdesk/client/remdesk_main.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Remote Assistance 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_REMDESK_CLIENT_MAIN_H
|
||||||
|
#define FREERDP_CHANNEL_REMDESK_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/svc.h>
|
||||||
|
#include <freerdp/addin.h>
|
||||||
|
#include <freerdp/settings.h>
|
||||||
|
|
||||||
|
#include <freerdp/client/remdesk.h>
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
#define TAG CHANNELS_TAG("remdesk.client")
|
||||||
|
|
||||||
|
struct remdesk_plugin
|
||||||
|
{
|
||||||
|
CHANNEL_DEF channelDef;
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
|
||||||
|
|
||||||
|
HANDLE thread;
|
||||||
|
wStream* data_in;
|
||||||
|
void* InitHandle;
|
||||||
|
DWORD OpenHandle;
|
||||||
|
wMessagePipe* MsgPipe;
|
||||||
|
rdpSettings* settings;
|
||||||
|
|
||||||
|
UINT32 Version;
|
||||||
|
char* ExpertBlob;
|
||||||
|
BYTE* EncryptedPassStub;
|
||||||
|
int EncryptedPassStubSize;
|
||||||
|
};
|
||||||
|
typedef struct remdesk_plugin remdeskPlugin;
|
||||||
|
|
||||||
|
#endif /* FREERDP_CHANNEL_REMDESK_CLIENT_MAIN_H */
|
34
channels/remdesk/server/CMakeLists.txt
Normal file
34
channels/remdesk/server/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# 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("remdesk")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_SRCS
|
||||||
|
remdesk_main.c
|
||||||
|
remdesk_main.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")
|
547
channels/remdesk/server/remdesk_main.c
Normal file
547
channels/remdesk/server/remdesk_main.c
Normal file
@ -0,0 +1,547 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Remote Assistance 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 "remdesk_main.h"
|
||||||
|
|
||||||
|
int remdesk_virtual_channel_write(RemdeskServerContext* context, wStream* s)
|
||||||
|
{
|
||||||
|
BOOL status;
|
||||||
|
ULONG BytesWritten = 0;
|
||||||
|
|
||||||
|
status = WTSVirtualChannelWrite(context->priv->ChannelHandle,
|
||||||
|
(PCHAR) Stream_Buffer(s), Stream_Length(s), &BytesWritten);
|
||||||
|
|
||||||
|
return (status) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
UINT32 ChannelNameLen;
|
||||||
|
char* pChannelName = NULL;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */
|
||||||
|
|
||||||
|
if (ChannelNameLen > 64)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((ChannelNameLen % 2) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < ChannelNameLen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ZeroMemory(header->ChannelName, sizeof(header->ChannelName));
|
||||||
|
|
||||||
|
pChannelName = (char*) header->ChannelName;
|
||||||
|
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
||||||
|
ChannelNameLen / 2, &pChannelName, 32, NULL, NULL);
|
||||||
|
|
||||||
|
Stream_Seek(s, ChannelNameLen);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
UINT32 ChannelNameLen;
|
||||||
|
WCHAR ChannelNameW[32];
|
||||||
|
|
||||||
|
ZeroMemory(ChannelNameW, sizeof(ChannelNameW));
|
||||||
|
|
||||||
|
for (index = 0; index < 32; index++)
|
||||||
|
{
|
||||||
|
ChannelNameW[index] = (WCHAR) header->ChannelName[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelNameLen = (strlen(header->ChannelName) + 1) * 2;
|
||||||
|
|
||||||
|
Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */
|
||||||
|
Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */
|
||||||
|
|
||||||
|
Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader)
|
||||||
|
{
|
||||||
|
remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader);
|
||||||
|
Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, UINT32 msgSize)
|
||||||
|
{
|
||||||
|
ctlHeader->msgType = msgType;
|
||||||
|
strcpy(ctlHeader->ChannelName, REMDESK_CHANNEL_CTL_NAME);
|
||||||
|
ctlHeader->DataLength = 4 + msgSize;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_result_pdu(RemdeskServerContext* context, UINT32 result)
|
||||||
|
{
|
||||||
|
wStream* s;
|
||||||
|
REMDESK_CTL_RESULT_PDU pdu;
|
||||||
|
|
||||||
|
pdu.result = result;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_RESULT, 4);
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write_UINT32(s, pdu.result); /* result (4 bytes) */
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(context, s);
|
||||||
|
|
||||||
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_send_ctl_version_info_pdu(RemdeskServerContext* context)
|
||||||
|
{
|
||||||
|
wStream* s;
|
||||||
|
REMDESK_CTL_VERSION_INFO_PDU pdu;
|
||||||
|
|
||||||
|
remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
|
||||||
|
|
||||||
|
pdu.versionMajor = 1;
|
||||||
|
pdu.versionMinor = 2;
|
||||||
|
|
||||||
|
s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength);
|
||||||
|
|
||||||
|
remdesk_write_ctl_header(s, &(pdu.ctlHeader));
|
||||||
|
|
||||||
|
Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */
|
||||||
|
Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
remdesk_virtual_channel_write(context, s);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_version_info_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
UINT32 versionMajor;
|
||||||
|
UINT32 versionMinor;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_remote_control_desktop_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
int cchStringW;
|
||||||
|
WCHAR* pStringW;
|
||||||
|
UINT32 msgLength;
|
||||||
|
int cbRaConnectionStringW = 0;
|
||||||
|
WCHAR* raConnectionStringW = NULL;
|
||||||
|
REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu;
|
||||||
|
|
||||||
|
msgLength = header->DataLength - 4;
|
||||||
|
|
||||||
|
pStringW = (WCHAR*) Stream_Pointer(s);
|
||||||
|
raConnectionStringW = pStringW;
|
||||||
|
cchStringW = 0;
|
||||||
|
|
||||||
|
while ((msgLength > 0) && pStringW[cchStringW])
|
||||||
|
{
|
||||||
|
msgLength -= 2;
|
||||||
|
cchStringW++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pStringW[cchStringW] || !cchStringW)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cchStringW++;
|
||||||
|
cbRaConnectionStringW = cchStringW * 2;
|
||||||
|
|
||||||
|
pdu.raConnectionString = NULL;
|
||||||
|
|
||||||
|
status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW,
|
||||||
|
cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
WLog_INFO(TAG, "RaConnectionString: %s",
|
||||||
|
pdu.raConnectionString);
|
||||||
|
free(pdu.raConnectionString);
|
||||||
|
|
||||||
|
remdesk_send_ctl_result_pdu(context, 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
int cchStringW;
|
||||||
|
WCHAR* pStringW;
|
||||||
|
UINT32 msgLength;
|
||||||
|
int cbExpertBlobW = 0;
|
||||||
|
WCHAR* expertBlobW = NULL;
|
||||||
|
int cbRaConnectionStringW = 0;
|
||||||
|
WCHAR* raConnectionStringW = NULL;
|
||||||
|
REMDESK_CTL_AUTHENTICATE_PDU pdu;
|
||||||
|
|
||||||
|
msgLength = header->DataLength - 4;
|
||||||
|
|
||||||
|
pStringW = (WCHAR*) Stream_Pointer(s);
|
||||||
|
raConnectionStringW = pStringW;
|
||||||
|
cchStringW = 0;
|
||||||
|
|
||||||
|
while ((msgLength > 0) && pStringW[cchStringW])
|
||||||
|
{
|
||||||
|
msgLength -= 2;
|
||||||
|
cchStringW++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pStringW[cchStringW] || !cchStringW)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cchStringW++;
|
||||||
|
cbRaConnectionStringW = cchStringW * 2;
|
||||||
|
|
||||||
|
pStringW += cchStringW;
|
||||||
|
expertBlobW = pStringW;
|
||||||
|
cchStringW = 0;
|
||||||
|
|
||||||
|
while ((msgLength > 0) && pStringW[cchStringW])
|
||||||
|
{
|
||||||
|
msgLength -= 2;
|
||||||
|
cchStringW++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pStringW[cchStringW] || !cchStringW)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cchStringW++;
|
||||||
|
cbExpertBlobW = cchStringW * 2;
|
||||||
|
|
||||||
|
pdu.raConnectionString = NULL;
|
||||||
|
|
||||||
|
status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW,
|
||||||
|
cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pdu.expertBlob = NULL;
|
||||||
|
|
||||||
|
status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW,
|
||||||
|
cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (status <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
WLog_INFO(TAG, "RaConnectionString: %s ExpertBlob: %s",
|
||||||
|
pdu.raConnectionString, pdu.expertBlob);
|
||||||
|
free(pdu.raConnectionString);
|
||||||
|
free(pdu.expertBlob);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
int cbExpertBlobW = 0;
|
||||||
|
WCHAR* expertBlobW = NULL;
|
||||||
|
REMDESK_CTL_VERIFY_PASSWORD_PDU pdu;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pdu.expertBlob = NULL;
|
||||||
|
expertBlobW = (WCHAR*) Stream_Pointer(s);
|
||||||
|
cbExpertBlobW = header->DataLength - 4;
|
||||||
|
|
||||||
|
status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL);
|
||||||
|
WLog_INFO(TAG, "ExpertBlob: %s", pdu.expertBlob);
|
||||||
|
remdesk_send_ctl_result_pdu(context, 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header)
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
UINT32 msgType = 0;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
|
||||||
|
WLog_INFO(TAG, "msgType: %d", msgType);
|
||||||
|
|
||||||
|
switch (msgType)
|
||||||
|
{
|
||||||
|
case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
|
||||||
|
status = remdesk_recv_ctl_remote_control_desktop_pdu(context, s, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_AUTHENTICATE:
|
||||||
|
status = remdesk_recv_ctl_authenticate_pdu(context, s, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_DISCONNECT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_VERSIONINFO:
|
||||||
|
status = remdesk_recv_ctl_version_info_pdu(context, s, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_ISCONNECTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_VERIFY_PASSWORD:
|
||||||
|
status = remdesk_recv_ctl_verify_password_pdu(context, s, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_EXPERT_ON_VISTA:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_RANOVICE_NAME:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_RAEXPERT_NAME:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMDESK_CTL_TOKEN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
WLog_ERR(TAG, "remdesk_recv_control_pdu: unknown msgType: %d", msgType);
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_server_receive_pdu(RemdeskServerContext* context, wStream* s)
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
REMDESK_CHANNEL_HEADER header;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
WLog_INFO(TAG, "RemdeskReceive: %d", Stream_GetRemainingLength(s));
|
||||||
|
winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
remdesk_read_channel_header(s, &header);
|
||||||
|
|
||||||
|
if (strcmp(header.ChannelName, "RC_CTL") == 0)
|
||||||
|
{
|
||||||
|
status = remdesk_recv_ctl_pdu(context, s, &header);
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "70") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "71") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, ".") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "1000.") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strcmp(header.ChannelName, "RA_FX") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* remdesk_server_thread(void* arg)
|
||||||
|
{
|
||||||
|
wStream* s;
|
||||||
|
DWORD status;
|
||||||
|
DWORD nCount;
|
||||||
|
void* buffer;
|
||||||
|
UINT32* pHeader;
|
||||||
|
UINT32 PduLength;
|
||||||
|
HANDLE events[8];
|
||||||
|
HANDLE ChannelEvent;
|
||||||
|
DWORD BytesReturned;
|
||||||
|
RemdeskServerContext* context;
|
||||||
|
|
||||||
|
context = (RemdeskServerContext*) 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;
|
||||||
|
|
||||||
|
remdesk_send_ctl_version_info_pdu(context);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||||
|
|
||||||
|
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||||
|
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
|
||||||
|
{
|
||||||
|
if (BytesReturned)
|
||||||
|
Stream_Seek(s, BytesReturned);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Stream_GetPosition(s) >= 8)
|
||||||
|
{
|
||||||
|
pHeader = (UINT32*) Stream_Buffer(s);
|
||||||
|
PduLength = pHeader[0] + pHeader[1] + 8;
|
||||||
|
|
||||||
|
if (PduLength >= Stream_GetPosition(s))
|
||||||
|
{
|
||||||
|
Stream_SealLength(s);
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
remdesk_server_receive_pdu(context, s);
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_server_start(RemdeskServerContext* context)
|
||||||
|
{
|
||||||
|
context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "remdesk");
|
||||||
|
|
||||||
|
if (!context->priv->ChannelHandle)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
|
context->priv->Thread = CreateThread(NULL, 0,
|
||||||
|
(LPTHREAD_START_ROUTINE) remdesk_server_thread, (void*) context, 0, NULL);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remdesk_server_stop(RemdeskServerContext* context)
|
||||||
|
{
|
||||||
|
SetEvent(context->priv->StopEvent);
|
||||||
|
|
||||||
|
WaitForSingleObject(context->priv->Thread, INFINITE);
|
||||||
|
CloseHandle(context->priv->Thread);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemdeskServerContext* remdesk_server_context_new(HANDLE vcm)
|
||||||
|
{
|
||||||
|
RemdeskServerContext* context;
|
||||||
|
|
||||||
|
context = (RemdeskServerContext*) calloc(1, sizeof(RemdeskServerContext));
|
||||||
|
|
||||||
|
if (context)
|
||||||
|
{
|
||||||
|
context->vcm = vcm;
|
||||||
|
|
||||||
|
context->Start = remdesk_server_start;
|
||||||
|
context->Stop = remdesk_server_stop;
|
||||||
|
|
||||||
|
context->priv = (RemdeskServerPrivate*) calloc(1, sizeof(RemdeskServerPrivate));
|
||||||
|
|
||||||
|
if (context->priv)
|
||||||
|
{
|
||||||
|
context->priv->Version = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remdesk_server_context_free(RemdeskServerContext* context)
|
||||||
|
{
|
||||||
|
if (context)
|
||||||
|
{
|
||||||
|
if (context->priv)
|
||||||
|
{
|
||||||
|
free(context->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(context);
|
||||||
|
}
|
||||||
|
}
|
42
channels/remdesk/server/remdesk_main.h
Normal file
42
channels/remdesk/server/remdesk_main.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Remote Assistance 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_REMDESK_MAIN_H
|
||||||
|
#define FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H
|
||||||
|
|
||||||
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/synch.h>
|
||||||
|
#include <winpr/thread.h>
|
||||||
|
|
||||||
|
#include <freerdp/server/remdesk.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("remdesk.server")
|
||||||
|
|
||||||
|
struct _remdesk_server_private
|
||||||
|
{
|
||||||
|
HANDLE Thread;
|
||||||
|
HANDLE StopEvent;
|
||||||
|
void* ChannelHandle;
|
||||||
|
|
||||||
|
UINT32 Version;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FREERDP_CHANNEL_SERVER_REMDESK_MAIN_H */
|
||||||
|
|
@ -18,21 +18,13 @@
|
|||||||
define_channel_client("serial")
|
define_channel_client("serial")
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_SRCS
|
set(${MODULE_PREFIX}_SRCS
|
||||||
serial_tty.c
|
|
||||||
serial_tty.h
|
|
||||||
serial_constants.h
|
|
||||||
serial_main.c)
|
serial_main.c)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
@ -1,154 +0,0 @@
|
|||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* Serial Port Device Service Virtual Channel
|
|
||||||
*
|
|
||||||
* Copyright 2011 O.S. Systems Software Ltda.
|
|
||||||
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
|
||||||
*
|
|
||||||
* 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 __SERIAL_CONSTANTS_H
|
|
||||||
#define __SERIAL_CONSTANTS_H
|
|
||||||
|
|
||||||
/* http://www.codeproject.com/KB/system/chaiyasit_t.aspx */
|
|
||||||
#define SERIAL_TIMEOUT_MAX 4294967295u
|
|
||||||
|
|
||||||
/* DR_CONTROL_REQ.IoControlCode */
|
|
||||||
enum DR_PORT_CONTROL_REQ
|
|
||||||
{
|
|
||||||
IOCTL_SERIAL_SET_BAUD_RATE = 0x001B0004,
|
|
||||||
IOCTL_SERIAL_GET_BAUD_RATE = 0x001B0050,
|
|
||||||
IOCTL_SERIAL_SET_LINE_CONTROL = 0x001B000C,
|
|
||||||
IOCTL_SERIAL_GET_LINE_CONTROL = 0x001B0054,
|
|
||||||
IOCTL_SERIAL_SET_TIMEOUTS = 0x001B001C,
|
|
||||||
IOCTL_SERIAL_GET_TIMEOUTS = 0x001B0020,
|
|
||||||
|
|
||||||
/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */
|
|
||||||
IOCTL_SERIAL_GET_CHARS = 0x001B0058,
|
|
||||||
IOCTL_SERIAL_SET_CHARS = 0x001B005C,
|
|
||||||
|
|
||||||
IOCTL_SERIAL_SET_DTR = 0x001B0024,
|
|
||||||
IOCTL_SERIAL_CLR_DTR = 0x001B0028,
|
|
||||||
IOCTL_SERIAL_RESET_DEVICE = 0x001B002C,
|
|
||||||
IOCTL_SERIAL_SET_RTS = 0x001B0030,
|
|
||||||
IOCTL_SERIAL_CLR_RTS = 0x001B0034,
|
|
||||||
IOCTL_SERIAL_SET_XOFF = 0x001B0038,
|
|
||||||
IOCTL_SERIAL_SET_XON = 0x001B003C,
|
|
||||||
IOCTL_SERIAL_SET_BREAK_ON = 0x001B0010,
|
|
||||||
IOCTL_SERIAL_SET_BREAK_OFF = 0x001B0014,
|
|
||||||
IOCTL_SERIAL_SET_QUEUE_SIZE = 0x001B0008,
|
|
||||||
IOCTL_SERIAL_GET_WAIT_MASK = 0x001B0040,
|
|
||||||
IOCTL_SERIAL_SET_WAIT_MASK = 0x001B0044,
|
|
||||||
IOCTL_SERIAL_WAIT_ON_MASK = 0x001B0048,
|
|
||||||
IOCTL_SERIAL_IMMEDIATE_CHAR = 0x001B0018,
|
|
||||||
IOCTL_SERIAL_PURGE = 0x001B004C,
|
|
||||||
IOCTL_SERIAL_GET_HANDFLOW = 0x001B0060,
|
|
||||||
IOCTL_SERIAL_SET_HANDFLOW = 0x001B0064,
|
|
||||||
IOCTL_SERIAL_GET_MODEMSTATUS = 0x001B0068,
|
|
||||||
IOCTL_SERIAL_GET_DTRRTS = 0x001B0078,
|
|
||||||
|
|
||||||
/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */
|
|
||||||
IOCTL_SERIAL_GET_COMMSTATUS = 0x001B006C,
|
|
||||||
|
|
||||||
IOCTL_SERIAL_GET_PROPERTIES = 0x001B0074,
|
|
||||||
IOCTL_SERIAL_XOFF_COUNTER = 0x001B0070,
|
|
||||||
IOCTL_SERIAL_LSRMST_INSERT = 0x001B007C,
|
|
||||||
IOCTL_SERIAL_CONFIG_SIZE = 0x001B0080,
|
|
||||||
IOCTL_SERIAL_GET_STATS = 0x001B008C,
|
|
||||||
IOCTL_SERIAL_CLEAR_STATS = 0x001B0090,
|
|
||||||
IOCTL_SERIAL_GET_MODEM_CONTROL = 0x001B0094,
|
|
||||||
IOCTL_SERIAL_SET_MODEM_CONTROL = 0x001B0098,
|
|
||||||
IOCTL_SERIAL_SET_FIFO_CONTROL = 0x001B009C,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_PURGE_MASK
|
|
||||||
{
|
|
||||||
SERIAL_PURGE_TXABORT = 0x00000001,
|
|
||||||
SERIAL_PURGE_RXABORT = 0x00000002,
|
|
||||||
SERIAL_PURGE_TXCLEAR = 0x00000004,
|
|
||||||
SERIAL_PURGE_RXCLEAR = 0x00000008,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_WAIT_MASK
|
|
||||||
{
|
|
||||||
SERIAL_EV_RXCHAR = 0x0001, /* Any Character received */
|
|
||||||
SERIAL_EV_RXFLAG = 0x0002, /* Received certain character */
|
|
||||||
SERIAL_EV_TXEMPTY = 0x0004, /* Transmitt Queue Empty */
|
|
||||||
SERIAL_EV_CTS = 0x0008, /* CTS changed state */
|
|
||||||
SERIAL_EV_DSR = 0x0010, /* DSR changed state */
|
|
||||||
SERIAL_EV_RLSD = 0x0020, /* RLSD changed state */
|
|
||||||
SERIAL_EV_BREAK = 0x0040, /* BREAK received */
|
|
||||||
SERIAL_EV_ERR = 0x0080, /* Line status error occurred */
|
|
||||||
SERIAL_EV_RING = 0x0100, /* Ring signal detected */
|
|
||||||
SERIAL_EV_PERR = 0x0200, /* Printer error occured */
|
|
||||||
SERIAL_EV_RX80FULL = 0x0400,/* Receive buffer is 80 percent full */
|
|
||||||
SERIAL_EV_EVENT1 = 0x0800, /* Provider specific event 1 */
|
|
||||||
SERIAL_EV_EVENT2 = 0x1000, /* Provider specific event 2 */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_MODEM_STATUS
|
|
||||||
{
|
|
||||||
SERIAL_MS_DTR = 0x01,
|
|
||||||
SERIAL_MS_RTS = 0x02,
|
|
||||||
SERIAL_MS_CTS = 0x10,
|
|
||||||
SERIAL_MS_DSR = 0x20,
|
|
||||||
SERIAL_MS_RNG = 0x40,
|
|
||||||
SERIAL_MS_CAR = 0x80,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_HANDFLOW
|
|
||||||
{
|
|
||||||
SERIAL_DTR_CONTROL = 0x01,
|
|
||||||
SERIAL_CTS_HANDSHAKE = 0x08,
|
|
||||||
SERIAL_ERROR_ABORT = 0x80000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_FLOW_CONTROL
|
|
||||||
{
|
|
||||||
SERIAL_XON_HANDSHAKE = 0x01,
|
|
||||||
SERIAL_XOFF_HANDSHAKE = 0x02,
|
|
||||||
SERIAL_DSR_SENSITIVITY = 0x40,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_CHARS
|
|
||||||
{
|
|
||||||
SERIAL_CHAR_EOF = 0,
|
|
||||||
SERIAL_CHAR_ERROR = 1,
|
|
||||||
SERIAL_CHAR_BREAK = 2,
|
|
||||||
SERIAL_CHAR_EVENT = 3,
|
|
||||||
SERIAL_CHAR_XON = 4,
|
|
||||||
SERIAL_CHAR_XOFF = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_ABORT_IO
|
|
||||||
{
|
|
||||||
SERIAL_ABORT_IO_NONE = 0,
|
|
||||||
SERIAL_ABORT_IO_WRITE = 1,
|
|
||||||
SERIAL_ABORT_IO_READ = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_STOP_BITS
|
|
||||||
{
|
|
||||||
SERIAL_STOP_BITS_1 = 0,
|
|
||||||
SERIAL_STOP_BITS_2 = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SERIAL_PARITY
|
|
||||||
{
|
|
||||||
SERIAL_NO_PARITY = 0,
|
|
||||||
SERIAL_ODD_PARITY = 1,
|
|
||||||
SERIAL_EVEN_PARITY = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2011 O.S. Systems Software Ltda.
|
* Copyright 2011 O.S. Systems Software Ltda.
|
||||||
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
||||||
|
* Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -23,115 +24,206 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_MODEM_H
|
|
||||||
#include <sys/modem.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYS_FILIO_H
|
|
||||||
#include <sys/filio.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYS_STRTIO_H
|
|
||||||
#include <sys/strtio.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "serial_tty.h"
|
|
||||||
#include "serial_constants.h"
|
|
||||||
|
|
||||||
|
#include <winpr/collections.h>
|
||||||
|
#include <winpr/comm.h>
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/wlog.h>
|
#include <winpr/stream.h>
|
||||||
#include <winpr/synch.h>
|
#include <winpr/synch.h>
|
||||||
#include <winpr/thread.h>
|
#include <winpr/thread.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/wlog.h>
|
||||||
#include <winpr/collections.h>
|
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
|
|
||||||
|
/* TODO: all #ifdef __linux__ could be removed once only some generic
|
||||||
|
* functions will be used. Replace CommReadFile by ReadFile,
|
||||||
|
* CommWriteFile by WriteFile etc.. */
|
||||||
|
#if defined __linux__ && !defined ANDROID
|
||||||
|
|
||||||
|
#define MAX_IRP_THREADS 5
|
||||||
|
|
||||||
typedef struct _SERIAL_DEVICE SERIAL_DEVICE;
|
typedef struct _SERIAL_DEVICE SERIAL_DEVICE;
|
||||||
|
|
||||||
struct _SERIAL_DEVICE
|
struct _SERIAL_DEVICE
|
||||||
{
|
{
|
||||||
DEVICE device;
|
DEVICE device;
|
||||||
|
BOOL permissive;
|
||||||
char* path;
|
SERIAL_DRIVER_ID ServerSerialDriverId;
|
||||||
SERIAL_TTY* tty;
|
HANDLE* hComm;
|
||||||
|
|
||||||
wLog* log;
|
wLog* log;
|
||||||
HANDLE thread;
|
HANDLE MainThread;
|
||||||
wMessageQueue* IrpQueue;
|
wMessageQueue* MainIrpQueue;
|
||||||
|
|
||||||
|
/* one thread per pending IRP and indexed according their CompletionId */
|
||||||
|
wListDictionary *IrpThreads;
|
||||||
|
UINT32 IrpThreadToBeTerminatedCount;
|
||||||
|
CRITICAL_SECTION TerminatingIrpThreadsLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _IRP_THREAD_DATA IRP_THREAD_DATA;
|
||||||
|
|
||||||
|
struct _IRP_THREAD_DATA
|
||||||
|
{
|
||||||
|
SERIAL_DEVICE *serial;
|
||||||
|
IRP *irp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
|
||||||
|
{
|
||||||
|
/* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */
|
||||||
|
|
||||||
|
switch(GetLastError())
|
||||||
|
{
|
||||||
|
case ERROR_BAD_DEVICE:
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
case ERROR_CALL_NOT_IMPLEMENTED:
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
case ERROR_CANCELLED:
|
||||||
|
return STATUS_CANCELLED;
|
||||||
|
|
||||||
|
case ERROR_INSUFFICIENT_BUFFER:
|
||||||
|
return STATUS_BUFFER_TOO_SMALL; /* NB: STATUS_BUFFER_SIZE_TOO_SMALL not defined */
|
||||||
|
|
||||||
|
case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */
|
||||||
|
return STATUS_INVALID_DEVICE_STATE;
|
||||||
|
|
||||||
|
case ERROR_INVALID_HANDLE:
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
case ERROR_INVALID_PARAMETER:
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
case ERROR_IO_DEVICE:
|
||||||
|
return STATUS_IO_DEVICE_ERROR;
|
||||||
|
|
||||||
|
case ERROR_IO_PENDING:
|
||||||
|
return STATUS_PENDING;
|
||||||
|
|
||||||
|
case ERROR_NOT_SUPPORTED:
|
||||||
|
return STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
case ERROR_TIMEOUT:
|
||||||
|
return STATUS_TIMEOUT;
|
||||||
|
|
||||||
|
/* no default */
|
||||||
|
}
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "unexpected last-error: 0x%lx", GetLastError());
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
int status;
|
DWORD DesiredAccess;
|
||||||
UINT32 FileId;
|
DWORD SharedAccess;
|
||||||
|
DWORD CreateDisposition;
|
||||||
UINT32 PathLength;
|
UINT32 PathLength;
|
||||||
char* path = NULL;
|
|
||||||
SERIAL_TTY* tty;
|
|
||||||
|
|
||||||
Stream_Seek_UINT32(irp->input); /* DesiredAccess (4 bytes) */
|
Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */
|
||||||
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
|
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
|
||||||
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
|
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
|
||||||
Stream_Seek_UINT32(irp->input); /* SharedAccess (4 bytes) */
|
Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */
|
||||||
Stream_Seek_UINT32(irp->input); /* CreateDisposition (4 bytes) */
|
Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */
|
||||||
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
|
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
|
||||||
|
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
|
||||||
|
Stream_Seek(irp->input, PathLength); /* Path (variable) */
|
||||||
|
|
||||||
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
|
assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */
|
||||||
|
|
||||||
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input),
|
|
||||||
PathLength / 2, &path, 0, NULL, NULL);
|
|
||||||
|
|
||||||
if (status < 1)
|
#ifndef _WIN32
|
||||||
path = (char*) calloc(1, 1);
|
/* Windows 2012 server sends on a first call :
|
||||||
|
* DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES
|
||||||
|
* SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ
|
||||||
|
* CreateDisposition = 0x00000001: CREATE_NEW
|
||||||
|
*
|
||||||
|
* then Windows 2012 sends :
|
||||||
|
* DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA
|
||||||
|
* SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ
|
||||||
|
* CreateDisposition = 0x00000001: CREATE_NEW
|
||||||
|
*
|
||||||
|
* assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE));
|
||||||
|
* assert(SharedAccess == 0);
|
||||||
|
* assert(CreateDisposition == OPEN_EXISTING);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
FileId = irp->devman->id_sequence++;
|
WLog_Print(serial->log, WLOG_DEBUG, "DesiredAccess: 0x%lX, SharedAccess: 0x%lX, CreateDisposition: 0x%lX", DesiredAccess, SharedAccess, CreateDisposition);
|
||||||
|
|
||||||
tty = serial_tty_new(serial->path, FileId);
|
/* FIXME: As of today only the flags below are supported by CommCreateFileA: */
|
||||||
|
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||||
|
SharedAccess = 0;
|
||||||
|
CreateDisposition = OPEN_EXISTING;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!tty)
|
serial->hComm = CreateFile(serial->device.name,
|
||||||
|
DesiredAccess,
|
||||||
|
SharedAccess,
|
||||||
|
NULL, /* SecurityAttributes */
|
||||||
|
CreateDisposition,
|
||||||
|
0, /* FlagsAndAttributes */
|
||||||
|
NULL); /* TemplateFile */
|
||||||
|
|
||||||
|
if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE))
|
||||||
{
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: Ox%lX\n", serial->device.name, GetLastError());
|
||||||
|
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||||
FileId = 0;
|
goto error_handle;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
serial->tty = tty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */
|
_comm_setServerSerialDriver(serial->hComm, serial->ServerSerialDriverId);
|
||||||
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
|
|
||||||
|
|
||||||
free(path);
|
_comm_set_permissive(serial->hComm, serial->permissive);
|
||||||
|
|
||||||
irp->Complete(irp);
|
/* NOTE: binary mode/raw mode required for the redirection. On
|
||||||
|
* Linux, CommCreateFileA forces this setting.
|
||||||
|
*/
|
||||||
|
/* ZeroMemory(&dcb, sizeof(DCB)); */
|
||||||
|
/* dcb.DCBlength = sizeof(DCB); */
|
||||||
|
/* GetCommState(serial->hComm, &dcb); */
|
||||||
|
/* dcb.fBinary = TRUE; */
|
||||||
|
/* SetCommState(serial->hComm, &dcb); */
|
||||||
|
|
||||||
|
assert(irp->FileId == 0);
|
||||||
|
irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
|
||||||
|
|
||||||
|
irp->IoStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %d, FileId: %d) created.", serial->device.name, irp->device->id, irp->FileId);
|
||||||
|
|
||||||
|
error_handle:
|
||||||
|
Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */
|
||||||
|
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
SERIAL_TTY* tty = serial->tty;
|
|
||||||
|
|
||||||
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
|
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
|
||||||
|
|
||||||
if (!tty)
|
if (!CloseHandle(serial->hComm))
|
||||||
{
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%d) closed.", serial->device.name, irp->device->id);
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||||
}
|
goto error_handle;
|
||||||
else
|
|
||||||
{
|
|
||||||
serial_tty_free(tty);
|
|
||||||
serial->tty = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %d, FileId: %d) closed.", serial->device.name, irp->device->id, irp->FileId);
|
||||||
|
|
||||||
|
serial->hComm = NULL;
|
||||||
|
irp->IoStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
error_handle:
|
||||||
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
||||||
|
|
||||||
irp->Complete(irp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
@ -139,119 +231,175 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
UINT32 Length;
|
UINT32 Length;
|
||||||
UINT64 Offset;
|
UINT64 Offset;
|
||||||
BYTE* buffer = NULL;
|
BYTE* buffer = NULL;
|
||||||
SERIAL_TTY* tty = serial->tty;
|
DWORD nbRead = 0;
|
||||||
|
|
||||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||||
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
||||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||||
|
|
||||||
if (!tty)
|
|
||||||
|
buffer = (BYTE*)calloc(Length, sizeof(BYTE));
|
||||||
|
if (buffer == NULL)
|
||||||
{
|
{
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_NO_MEMORY;
|
||||||
Length = 0;
|
goto error_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored
|
||||||
|
* assert(Offset == 0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "reading %d bytes from %s", Length, serial->device.name);
|
||||||
|
|
||||||
|
/* FIXME: CommReadFile to be replaced by ReadFile */
|
||||||
|
if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL))
|
||||||
|
{
|
||||||
|
irp->IoStatus = STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer = (BYTE*) malloc(Length);
|
WLog_Print(serial->log, WLOG_DEBUG, "read failure to %s, nbRead=%ld, last-error: 0x%lX", serial->device.name, nbRead, GetLastError());
|
||||||
|
|
||||||
if (!serial_tty_read(tty, buffer, &Length))
|
irp->IoStatus = _GetLastErrorToIoStatus(serial);
|
||||||
{
|
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
|
||||||
free(buffer);
|
|
||||||
buffer = NULL;
|
|
||||||
Length = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
WLog_Print(serial->log, WLOG_DEBUG, "%lu bytes read from %s", nbRead, serial->device.name);
|
||||||
|
|
||||||
if (Length > 0)
|
error_handle:
|
||||||
|
|
||||||
|
Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */
|
||||||
|
|
||||||
|
if (nbRead > 0)
|
||||||
{
|
{
|
||||||
Stream_EnsureRemainingCapacity(irp->output, Length);
|
Stream_EnsureRemainingCapacity(irp->output, nbRead);
|
||||||
Stream_Write(irp->output, buffer, Length);
|
Stream_Write(irp->output, buffer, nbRead); /* ReadData */
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
irp->Complete(irp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
int status;
|
|
||||||
UINT32 Length;
|
UINT32 Length;
|
||||||
UINT64 Offset;
|
UINT64 Offset;
|
||||||
SERIAL_TTY* tty = serial->tty;
|
DWORD nbWritten = 0;
|
||||||
|
|
||||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||||
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
||||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||||
|
|
||||||
if (!tty)
|
/* MS-RDPESP 3.2.5.1.5: The Offset field is ignored
|
||||||
{
|
* assert(Offset == 0);
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
*
|
||||||
Length = 0;
|
* Using a serial printer, noticed though this field could be
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
WLog_Print(serial->log, WLOG_DEBUG, "writing %d bytes to %s", Length, serial->device.name);
|
||||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
|
||||||
irp->Complete(irp);
|
/* FIXME: CommWriteFile to be replaced by WriteFile */
|
||||||
return;
|
if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten, NULL))
|
||||||
|
{
|
||||||
|
irp->IoStatus = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "write failure to %s, nbWritten=%ld, last-error: 0x%lX", serial->device.name, nbWritten, GetLastError());
|
||||||
|
|
||||||
|
irp->IoStatus = _GetLastErrorToIoStatus(serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = serial_tty_write(tty, Stream_Pointer(irp->input), Length);
|
WLog_Print(serial->log, WLOG_DEBUG, "%lu bytes written to %s", nbWritten, serial->device.name);
|
||||||
|
|
||||||
if (status < 0)
|
Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */
|
||||||
{
|
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
|
||||||
Length = 0;
|
|
||||||
|
|
||||||
printf("serial_tty_write failure: status: %d, errno: %d\n", status, errno);
|
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
|
||||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
|
||||||
irp->Complete(irp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
|
||||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
||||||
irp->Complete(irp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
UINT32 IoControlCode;
|
UINT32 IoControlCode;
|
||||||
UINT32 InputBufferLength;
|
UINT32 InputBufferLength;
|
||||||
|
BYTE* InputBuffer = NULL;
|
||||||
UINT32 OutputBufferLength;
|
UINT32 OutputBufferLength;
|
||||||
UINT32 abortIo = SERIAL_ABORT_IO_NONE;
|
BYTE* OutputBuffer = NULL;
|
||||||
SERIAL_TTY* tty = serial->tty;
|
DWORD BytesReturned = 0;
|
||||||
|
|
||||||
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||||
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
|
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
|
||||||
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
|
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
|
||||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||||
|
|
||||||
if (!tty)
|
OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));
|
||||||
|
if (OutputBuffer == NULL)
|
||||||
{
|
{
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_NO_MEMORY;
|
||||||
OutputBufferLength = 0;
|
goto error_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputBuffer = (BYTE*)calloc(InputBufferLength, sizeof(BYTE));
|
||||||
|
if (InputBuffer == NULL)
|
||||||
|
{
|
||||||
|
irp->IoStatus = STATUS_NO_MEMORY;
|
||||||
|
goto error_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_Read(irp->input, InputBuffer, InputBufferLength);
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode));
|
||||||
|
|
||||||
|
/* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */
|
||||||
|
if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL))
|
||||||
|
{
|
||||||
|
/* WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s done", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); */
|
||||||
|
|
||||||
|
irp->IoStatus = STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abortIo);
|
WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl failure: IoControlCode=[0x%X] %s, last-error: 0x%lX",
|
||||||
|
IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError());
|
||||||
|
|
||||||
|
irp->IoStatus = _GetLastErrorToIoStatus(serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
irp->Complete(irp);
|
error_handle:
|
||||||
|
|
||||||
|
/* FIXME: find out whether it's required or not to get
|
||||||
|
* BytesReturned == OutputBufferLength when
|
||||||
|
* CommDeviceIoControl returns FALSE */
|
||||||
|
assert(OutputBufferLength == BytesReturned);
|
||||||
|
|
||||||
|
Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */
|
||||||
|
|
||||||
|
if (BytesReturned > 0)
|
||||||
|
{
|
||||||
|
Stream_EnsureRemainingCapacity(irp->output, BytesReturned);
|
||||||
|
Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */
|
||||||
|
}
|
||||||
|
/* FIXME: Why at least Windows 2008R2 gets lost with this
|
||||||
|
* extra byte and likely on a IOCTL_SERIAL_SET_BAUD_RATE? The
|
||||||
|
* extra byte is well required according MS-RDPEFS
|
||||||
|
* 2.2.1.5.5 */
|
||||||
|
/* else */
|
||||||
|
/* { */
|
||||||
|
/* Stream_Write_UINT8(irp->output, 0); /\* Padding (1 byte) *\/ */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
if (InputBuffer != NULL)
|
||||||
|
free(InputBuffer);
|
||||||
|
|
||||||
|
if (OutputBuffer != NULL)
|
||||||
|
free(OutputBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
|
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
|
||||||
irp->MajorFunction, irp->MinorFunction);
|
irp->MajorFunction, irp->MinorFunction);
|
||||||
|
|
||||||
switch (irp->MajorFunction)
|
switch (irp->MajorFunction)
|
||||||
{
|
{
|
||||||
@ -277,92 +425,362 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||||
irp->Complete(irp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void* irp_thread_func(void* arg)
|
||||||
|
{
|
||||||
|
IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg;
|
||||||
|
|
||||||
|
/* blocks until the end of the request */
|
||||||
|
serial_process_irp(data->serial, data->irp);
|
||||||
|
|
||||||
|
EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
|
||||||
|
data->serial->IrpThreadToBeTerminatedCount++;
|
||||||
|
|
||||||
|
data->irp->Complete(data->irp);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&data->serial->TerminatingIrpThreadsLock);
|
||||||
|
|
||||||
|
/* NB: At this point, the server might already being reusing
|
||||||
|
* the CompletionId whereas the thread is not yet
|
||||||
|
* terminated */
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
ExitThread(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp)
|
||||||
|
{
|
||||||
|
IRP_THREAD_DATA *data = NULL;
|
||||||
|
HANDLE irpThread = INVALID_HANDLE_VALUE;
|
||||||
|
HANDLE previousIrpThread;
|
||||||
|
uintptr_t key;
|
||||||
|
|
||||||
|
/* for a test/debug purpose, uncomment the code below to get a
|
||||||
|
* single thread for all IRPs. NB: two IRPs could not be
|
||||||
|
* processed at the same time, typically two concurent
|
||||||
|
* Read/Write operations could block each other. */
|
||||||
|
/* serial_process_irp(serial, irp); */
|
||||||
|
/* irp->Complete(irp); */
|
||||||
|
/* return; */
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: for good or bad, this implementation relies on the
|
||||||
|
* server to avoid a flooding of requests. see also _purge().
|
||||||
|
*/
|
||||||
|
|
||||||
|
EnterCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||||
|
while (serial->IrpThreadToBeTerminatedCount > 0)
|
||||||
|
{
|
||||||
|
/* Cleaning up termitating and pending irp
|
||||||
|
* threads. See also: irp_thread_func() */
|
||||||
|
|
||||||
|
HANDLE irpThread;
|
||||||
|
ULONG_PTR *ids;
|
||||||
|
int i, nbIds;
|
||||||
|
|
||||||
|
nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
|
||||||
|
for (i=0; i<nbIds; i++)
|
||||||
|
{
|
||||||
|
/* Checking if ids[i] is terminating or pending */
|
||||||
|
|
||||||
|
DWORD waitResult;
|
||||||
|
ULONG_PTR id = ids[i];
|
||||||
|
|
||||||
|
irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
|
||||||
|
|
||||||
|
/* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */
|
||||||
|
waitResult = WaitForSingleObject(irpThread, 0);
|
||||||
|
if (waitResult == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
/* terminating thread */
|
||||||
|
|
||||||
|
/* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%d naturally died", id); */
|
||||||
|
|
||||||
|
CloseHandle(irpThread);
|
||||||
|
ListDictionary_Remove(serial->IrpThreads, (void*)id);
|
||||||
|
|
||||||
|
serial->IrpThreadToBeTerminatedCount--;
|
||||||
|
}
|
||||||
|
else if (waitResult != WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
/* unexpected thread state */
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_WARN, "WaitForSingleObject, got an unexpected result=0x%lX\n", waitResult);
|
||||||
|
assert(FALSE);
|
||||||
|
}
|
||||||
|
/* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (serial->IrpThreadToBeTerminatedCount > 0)
|
||||||
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "%d IRP thread(s) not yet terminated", serial->IrpThreadToBeTerminatedCount);
|
||||||
|
Sleep(1); /* 1 ms */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||||
|
|
||||||
|
/* NB: At this point and thanks to the synchronization we're
|
||||||
|
* sure that the incoming IRP uses well a recycled
|
||||||
|
* CompletionId or the server sent again an IRP already posted
|
||||||
|
* which didn't get yet a response (this later server behavior
|
||||||
|
* at least observed with IOCTL_SERIAL_WAIT_ON_MASK and
|
||||||
|
* mstsc.exe).
|
||||||
|
*
|
||||||
|
* FIXME: behavior documented somewhere? behavior not yet
|
||||||
|
* observed with FreeRDP).
|
||||||
|
*/
|
||||||
|
|
||||||
|
key = irp->CompletionId;
|
||||||
|
previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key);
|
||||||
|
if (previousIrpThread)
|
||||||
|
{
|
||||||
|
/* Thread still alived <=> Request still pending */
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "IRP recall: IRP with the CompletionId=%d not yet completed!", irp->CompletionId);
|
||||||
|
|
||||||
|
assert(FALSE); /* unimplemented */
|
||||||
|
|
||||||
|
/* TODO: asserts that previousIrpThread handles well
|
||||||
|
* the same request by checking more details. Need an
|
||||||
|
* access to the IRP object used by previousIrpThread
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: taking over the pending IRP or sending a kind
|
||||||
|
* of wake up signal to accelerate the pending
|
||||||
|
* request
|
||||||
|
*
|
||||||
|
* To be considered:
|
||||||
|
* if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) {
|
||||||
|
* pComm->PendingEvents |= SERIAL_EV_FREERDP_*;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
irp->Discard(irp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS)
|
||||||
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_WARN, "Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads));
|
||||||
|
|
||||||
|
assert(FALSE); /* unimplemented */
|
||||||
|
|
||||||
|
/* TODO: MAX_IRP_THREADS has been thought to avoid a
|
||||||
|
* flooding of pending requests. Use
|
||||||
|
* WaitForMultipleObjects() when available in winpr
|
||||||
|
* for threads.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* error_handle to be used ... */
|
||||||
|
|
||||||
|
data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA));
|
||||||
|
if (data == NULL)
|
||||||
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP_THREAD_DATA.");
|
||||||
|
goto error_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->serial = serial;
|
||||||
|
data->irp = irp;
|
||||||
|
|
||||||
|
/* data freed by irp_thread_func */
|
||||||
|
|
||||||
|
irpThread = CreateThread(NULL,
|
||||||
|
0,
|
||||||
|
(LPTHREAD_START_ROUTINE)irp_thread_func,
|
||||||
|
(void*)data,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (irpThread == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP thread.");
|
||||||
|
goto error_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
key = irp->CompletionId;
|
||||||
|
ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error_handle:
|
||||||
|
|
||||||
|
irp->IoStatus = STATUS_NO_MEMORY;
|
||||||
|
irp->Complete(irp);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void terminate_pending_irp_threads(SERIAL_DEVICE *serial)
|
||||||
|
{
|
||||||
|
ULONG_PTR *ids;
|
||||||
|
int i, nbIds;
|
||||||
|
|
||||||
|
nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "Terminating %d IRP thread(s)", nbIds);
|
||||||
|
|
||||||
|
for (i=0; i<nbIds; i++)
|
||||||
|
{
|
||||||
|
HANDLE irpThread;
|
||||||
|
ULONG_PTR id = ids[i];
|
||||||
|
|
||||||
|
irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
|
||||||
|
|
||||||
|
TerminateThread(irpThread, 0);
|
||||||
|
|
||||||
|
WaitForSingleObject(irpThread, INFINITE);
|
||||||
|
|
||||||
|
CloseHandle(irpThread);
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %d", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDictionary_Clear(serial->IrpThreads);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void* serial_thread_func(void* arg)
|
static void* serial_thread_func(void* arg)
|
||||||
{
|
{
|
||||||
IRP* irp;
|
IRP* irp;
|
||||||
wMessage message;
|
wMessage message;
|
||||||
SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg;
|
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!MessageQueue_Wait(drive->IrpQueue))
|
if (!MessageQueue_Wait(serial->MainIrpQueue))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
|
if (!MessageQueue_Peek(serial->MainIrpQueue, &message, TRUE))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (message.id == WMQ_QUIT)
|
if (message.id == WMQ_QUIT)
|
||||||
|
{
|
||||||
|
terminate_pending_irp_threads(serial);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
irp = (IRP*) message.wParam;
|
irp = (IRP*) message.wParam;
|
||||||
|
|
||||||
if (irp)
|
if (irp)
|
||||||
serial_process_irp(drive, irp);
|
create_irp_thread(serial, irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitThread(0);
|
ExitThread(0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void serial_irp_request(DEVICE* device, IRP* irp)
|
static void serial_irp_request(DEVICE* device, IRP* irp)
|
||||||
{
|
{
|
||||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
||||||
MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL);
|
|
||||||
|
assert(irp != NULL);
|
||||||
|
|
||||||
|
if (irp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
|
||||||
|
* allows the server to send multiple simultaneous read or
|
||||||
|
* write requests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void serial_free(DEVICE* device)
|
static void serial_free(DEVICE* device)
|
||||||
{
|
{
|
||||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
||||||
|
|
||||||
WLog_Print(serial->log, WLOG_DEBUG, "freeing");
|
WLog_Print(serial->log, WLOG_DEBUG, "freeing");
|
||||||
|
|
||||||
MessageQueue_PostQuit(serial->IrpQueue, 0);
|
MessageQueue_PostQuit(serial->MainIrpQueue, 0);
|
||||||
WaitForSingleObject(serial->thread, INFINITE);
|
WaitForSingleObject(serial->MainThread, INFINITE);
|
||||||
CloseHandle(serial->thread);
|
CloseHandle(serial->MainThread);
|
||||||
|
|
||||||
serial_tty_free(serial->tty);
|
if (serial->hComm)
|
||||||
|
CloseHandle(serial->hComm);
|
||||||
|
|
||||||
/* Clean up resources */
|
/* Clean up resources */
|
||||||
Stream_Free(serial->device.data, TRUE);
|
Stream_Free(serial->device.data, TRUE);
|
||||||
MessageQueue_Free(serial->IrpQueue);
|
MessageQueue_Free(serial->MainIrpQueue);
|
||||||
|
ListDictionary_Free(serial->IrpThreads);
|
||||||
|
DeleteCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||||
|
|
||||||
free(serial);
|
free(serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
#ifdef STATIC_CHANNELS
|
#ifdef STATIC_CHANNELS
|
||||||
#define DeviceServiceEntry serial_DeviceServiceEntry
|
#define DeviceServiceEntry serial_DeviceServiceEntry
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||||
{
|
{
|
||||||
int i, len;
|
|
||||||
char* name;
|
char* name;
|
||||||
char* path;
|
char* path;
|
||||||
|
char* driver;
|
||||||
RDPDR_SERIAL* device;
|
RDPDR_SERIAL* device;
|
||||||
|
#if defined __linux__ && !defined ANDROID
|
||||||
|
int i, len;
|
||||||
SERIAL_DEVICE* serial;
|
SERIAL_DEVICE* serial;
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
device = (RDPDR_SERIAL*) pEntryPoints->device;
|
device = (RDPDR_SERIAL*) pEntryPoints->device;
|
||||||
name = device->Name;
|
name = device->Name;
|
||||||
path = device->Path;
|
path = device->Path;
|
||||||
|
driver = device->Driver;
|
||||||
|
|
||||||
if (!name || (name[0] == '*'))
|
if (!name || (name[0] == '*'))
|
||||||
{
|
{
|
||||||
/* TODO: implement auto detection of parallel ports */
|
/* TODO: implement auto detection of serial ports */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((name && name[0]) && (path && path[0]))
|
if ((name && name[0]) && (path && path[0]))
|
||||||
{
|
{
|
||||||
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
|
wLog* log;
|
||||||
|
|
||||||
|
WLog_Init();
|
||||||
|
log = WLog_Get("com.freerdp.channel.serial.client");
|
||||||
|
WLog_Print(log, WLOG_DEBUG, "initializing");
|
||||||
|
|
||||||
|
#ifndef __linux__ /* to be removed */
|
||||||
|
|
||||||
|
WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#else /* __linux __ */
|
||||||
|
|
||||||
|
WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path);
|
||||||
|
|
||||||
|
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
|
||||||
if (!serial)
|
if (!serial)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
serial->log = log;
|
||||||
|
|
||||||
serial->device.type = RDPDR_DTYP_SERIAL;
|
serial->device.type = RDPDR_DTYP_SERIAL;
|
||||||
serial->device.name = name;
|
serial->device.name = name;
|
||||||
serial->device.IRPRequest = serial_irp_request;
|
serial->device.IRPRequest = serial_irp_request;
|
||||||
@ -374,17 +792,62 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
for (i = 0; i <= len; i++)
|
for (i = 0; i <= len; i++)
|
||||||
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
|
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
|
||||||
|
|
||||||
serial->path = path;
|
if (driver != NULL)
|
||||||
serial->IrpQueue = MessageQueue_New(NULL);
|
{
|
||||||
|
if (_stricmp(driver, "Serial") == 0)
|
||||||
|
serial->ServerSerialDriverId = SerialDriverSerialSys;
|
||||||
|
else if (_stricmp(driver, "SerCx") == 0)
|
||||||
|
serial->ServerSerialDriverId = SerialDriverSerCxSys;
|
||||||
|
else if (_stricmp(driver, "SerCx2") == 0)
|
||||||
|
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(FALSE);
|
||||||
|
|
||||||
WLog_Init();
|
WLog_Print(serial->log, WLOG_DEBUG, "Unknown server's serial driver: %s. SerCx2 will be used", driver);
|
||||||
serial->log = WLog_Get("com.freerdp.channel.serial.client");
|
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
|
||||||
WLog_Print(serial->log, WLOG_DEBUG, "initializing");
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* default driver */
|
||||||
|
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (device->Permissive != NULL)
|
||||||
|
{
|
||||||
|
if (_stricmp(device->Permissive, "permissive") == 0)
|
||||||
|
{
|
||||||
|
serial->permissive = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "Unknown flag: %s", device->Permissive);
|
||||||
|
assert(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver, serial->ServerSerialDriverId);
|
||||||
|
/* TODO: implement auto detection of the server's serial driver */
|
||||||
|
|
||||||
|
serial->MainIrpQueue = MessageQueue_New(NULL);
|
||||||
|
|
||||||
|
/* IrpThreads content only modified by create_irp_thread() */
|
||||||
|
serial->IrpThreads = ListDictionary_New(FALSE);
|
||||||
|
serial->IrpThreadToBeTerminatedCount = 0;
|
||||||
|
InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||||
|
|
||||||
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
|
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
|
||||||
|
|
||||||
serial->thread = CreateThread(NULL, 0,
|
serial->MainThread = CreateThread(NULL,
|
||||||
(LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL);
|
0,
|
||||||
|
(LPTHREAD_START_ROUTINE) serial_thread_func,
|
||||||
|
(void*) serial,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
#endif /* __linux __ */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user