mirror of https://github.com/FreeRDP/FreeRDP
Merge remote-tracking branch 'upstream/master' into httpproxy
Conflicts: libfreerdp/core/settings.c libfreerdp/core/tcp.c libfreerdp/core/transport.c
This commit is contained in:
commit
33320a2e02
|
@ -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
|
||||||
|
|
|
@ -44,7 +44,6 @@ include(CheckCmakeCompat)
|
||||||
include(CheckIncludeFiles)
|
include(CheckIncludeFiles)
|
||||||
include(CheckLibraryExists)
|
include(CheckLibraryExists)
|
||||||
include(CheckStructHasMember)
|
include(CheckStructHasMember)
|
||||||
include(CMakeDetermineSystem)
|
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
include(TestBigEndian)
|
include(TestBigEndian)
|
||||||
|
|
||||||
|
@ -59,10 +58,15 @@ include(GNUInstallDirsWrapper)
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
# Soname versioning
|
# Soname versioning
|
||||||
|
set(BUILD_NUMBER 0)
|
||||||
|
if ($ENV{BUILD_NUMBER})
|
||||||
|
set(BUILD_NUMBER $ENV{BUILD_NUMBER})
|
||||||
|
endif()
|
||||||
|
set(WITH_LIBRARY_VERSIONING "ON")
|
||||||
set(FREERDP_VERSION_MAJOR "1")
|
set(FREERDP_VERSION_MAJOR "1")
|
||||||
set(FREERDP_VERSION_MINOR "2")
|
set(FREERDP_VERSION_MINOR "2")
|
||||||
set(FREERDP_VERSION_REVISION "0")
|
set(FREERDP_VERSION_REVISION "0")
|
||||||
set(FREERDP_VERSION_SUFFIX "beta1")
|
set(FREERDP_VERSION_SUFFIX "dev")
|
||||||
set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}")
|
set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}")
|
||||||
set(FREERDP_VERSION "${FREERDP_API_VERSION}.${FREERDP_VERSION_REVISION}")
|
set(FREERDP_VERSION "${FREERDP_API_VERSION}.${FREERDP_VERSION_REVISION}")
|
||||||
if (FREERDP_VERSION_SUFFIX)
|
if (FREERDP_VERSION_SUFFIX)
|
||||||
|
@ -76,11 +80,14 @@ if(ANDROID OR IOS)
|
||||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
|
||||||
endif(ANDROID OR IOS)
|
endif(ANDROID OR IOS)
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
|
git_get_exact_tag(GIT_REVISION --tags --always)
|
||||||
|
if (${GIT_REVISION} STREQUAL "n/a")
|
||||||
|
git_rev_parse(GIT_REVISION --short)
|
||||||
|
endif()
|
||||||
if(ANDROID OR IOS)
|
if(ANDROID OR IOS)
|
||||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||||
endif(ANDROID OR IOS)
|
endif(ANDROID OR IOS)
|
||||||
|
|
||||||
git_describe(GIT_REVISION --match "[0-9]*" --abbrev=4 --tags --always)
|
|
||||||
message(STATUS "Git Revision ${GIT_REVISION}")
|
message(STATUS "Git Revision ${GIT_REVISION}")
|
||||||
|
|
||||||
# Turn on solution folders (2.8.4+)
|
# Turn on solution folders (2.8.4+)
|
||||||
|
@ -232,9 +239,35 @@ 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")
|
||||||
|
|
||||||
|
# Set product and vendor for dll and exe version information.
|
||||||
|
set(RC_VERSION_VENDOR "FreeRDP")
|
||||||
|
set(RC_VERSION_PRODUCT "FreeRDP")
|
||||||
|
set(RC_VERSION_PATCH ${BUILD_NUMBER})
|
||||||
|
set(RC_VERSION_DESCRIPTION ${GIT_REVISION})
|
||||||
|
|
||||||
|
string(TIMESTAMP RC_VERSION_YEAR "%Y")
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_WINDOWS_VERSION)
|
||||||
|
set(CMAKE_WINDOWS_VERSION "WINXP")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_WINDOWS_VERSION STREQUAL "WINXP")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0501 -DWIN32_WINNT=0x0501")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0501 -DWIN32_WINNT=0x0501")
|
||||||
|
elseif(CMAKE_WINDOWS_VERSION STREQUAL "WIN7")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0601 -DWIN32_WINNT=0x0601")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0601 -DWIN32_WINNT=0x0601")
|
||||||
|
elseif(CMAKE_WINDOWS_VERSION STREQUAL "WIN8")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINVER=0x0602 -DWIN32_WINNT=0x0602")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWINVER=0x0602 -DWIN32_WINNT=0x0602")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (FREERDP_EXTERNAL_SSL_PATH)
|
||||||
|
set(OPENSSL_ROOT_DIR ${FREERDP_EXTERNAL_SSL_PATH})
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
|
@ -248,6 +281,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 +335,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 +405,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 +420,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")
|
||||||
|
@ -417,9 +459,13 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED")
|
||||||
set(FFMPEG_FEATURE_PURPOSE "multimedia")
|
set(FFMPEG_FEATURE_PURPOSE "multimedia")
|
||||||
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||||
|
|
||||||
set(GSTREAMER_FEATURE_TYPE "RECOMMENDED")
|
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||||
set(GSTREAMER_FEATURE_PURPOSE "multimedia")
|
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
|
||||||
set(GSTREAMER_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
|
||||||
|
|
||||||
|
set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED")
|
||||||
|
set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia")
|
||||||
|
set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||||
|
|
||||||
set(IPP_FEATURE_TYPE "OPTIONAL")
|
set(IPP_FEATURE_TYPE "OPTIONAL")
|
||||||
set(IPP_FEATURE_PURPOSE "performance")
|
set(IPP_FEATURE_PURPOSE "performance")
|
||||||
|
@ -429,12 +475,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")
|
||||||
|
@ -442,40 +493,46 @@ if(WIN32)
|
||||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||||
|
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||||
set(GSTREAMER_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")
|
||||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||||
|
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||||
endif()
|
endif()
|
||||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||||
endif()
|
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")
|
||||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||||
|
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||||
set(OPENSLES_FEATURE_TYPE "REQUIRED")
|
set(OPENSLES_FEATURE_TYPE "REQUIRED")
|
||||||
endif()
|
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")
|
||||||
|
@ -492,9 +549,12 @@ find_feature(Cups ${CUPS_FEATURE_TYPE} ${CUPS_FEATURE_PURPOSE} ${CUPS_FEATURE_DE
|
||||||
find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION})
|
find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION})
|
||||||
|
|
||||||
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
|
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
|
||||||
find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION})
|
|
||||||
|
find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION})
|
||||||
|
find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION})
|
||||||
|
|
||||||
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
|
find_feature(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")
|
||||||
|
@ -568,11 +628,6 @@ include_directories("${CMAKE_BINARY_DIR}/winpr/include")
|
||||||
|
|
||||||
add_subdirectory(winpr)
|
add_subdirectory(winpr)
|
||||||
|
|
||||||
if(WITH_CUNIT)
|
|
||||||
message(FATAL_ERROR "cunit (WITH_CUNIT) is deprecated please use BUILD_TESTING to build ctest tests.
|
|
||||||
The cunit directory contains the old tests and is kept until all tests are converted.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Sub-directories
|
# Sub-directories
|
||||||
|
|
||||||
if(WITH_THIRD_PARTY)
|
if(WITH_THIRD_PARTY)
|
||||||
|
@ -599,6 +654,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()
|
||||||
|
@ -616,7 +677,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}
|
||||||
|
@ -648,27 +711,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)
|
||||||
|
|
|
@ -158,7 +158,25 @@ macro(add_channel_client_library _module_prefix _module_name _channel_name _dyna
|
||||||
if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS))
|
if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS))
|
||||||
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
|
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${_dynamic} AND (NOT STATIC_CHANNELS))
|
if(${_dynamic} AND (NOT STATIC_CHANNELS))
|
||||||
|
# On windows create dll version information.
|
||||||
|
# Vendor, product and year are already set in top level CMakeLists.txt
|
||||||
|
if (WIN32)
|
||||||
|
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
|
||||||
|
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
|
||||||
|
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
|
||||||
|
set (RC_VERSION_PATCH 0)
|
||||||
|
set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${_module_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/version.rc
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(${_module_name} ${${_module_prefix}_SRCS})
|
add_library(${_module_name} ${${_module_prefix}_SRCS})
|
||||||
else()
|
else()
|
||||||
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
|
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
|
||||||
|
@ -174,6 +192,23 @@ macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_
|
||||||
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
|
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
|
||||||
endif()
|
endif()
|
||||||
if(${_dynamic} AND (NOT STATIC_CHANNELS))
|
if(${_dynamic} AND (NOT STATIC_CHANNELS))
|
||||||
|
# On windows create dll version information.
|
||||||
|
# Vendor, product and year are already set in top level CMakeLists.txt
|
||||||
|
if (WIN32)
|
||||||
|
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
|
||||||
|
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
|
||||||
|
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
|
||||||
|
set (RC_VERSION_PATCH 0)
|
||||||
|
set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${_module_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/version.rc
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(${_module_name} ${${_module_prefix}_SRCS})
|
add_library(${_module_name} ${${_module_prefix}_SRCS})
|
||||||
else()
|
else()
|
||||||
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
|
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
|
||||||
|
@ -188,6 +223,22 @@ macro(add_channel_server_library _module_prefix _module_name _channel_name _dyna
|
||||||
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
|
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
|
||||||
endif()
|
endif()
|
||||||
if(${_dynamic} AND (NOT STATIC_CHANNELS))
|
if(${_dynamic} AND (NOT STATIC_CHANNELS))
|
||||||
|
# On windows create dll version information.
|
||||||
|
# Vendor, product and year are already set in top level CMakeLists.txt
|
||||||
|
if (WIN32)
|
||||||
|
set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
|
||||||
|
set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
|
||||||
|
set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
|
||||||
|
set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${_module_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/version.rc
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(${_module_name} ${${_module_prefix}_SRCS})
|
add_library(${_module_name} ${${_module_prefix}_SRCS})
|
||||||
else()
|
else()
|
||||||
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
|
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
|
||||||
|
@ -202,8 +253,8 @@ set(FILENAME "ChannelOptions.cmake")
|
||||||
file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
|
file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
|
||||||
|
|
||||||
foreach(FILEPATH ${FILEPATHS})
|
foreach(FILEPATH ${FILEPATHS})
|
||||||
if(${FILEPATH} MATCHES "^([^/]*)//${FILENAME}")
|
if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}")
|
||||||
string(REGEX REPLACE "^([^/]*)//${FILENAME}" "\\1" DIR ${FILEPATH})
|
string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" DIR ${FILEPATH})
|
||||||
set(CHANNEL_OPTION)
|
set(CHANNEL_OPTION)
|
||||||
include(${FILEPATH})
|
include(${FILEPATH})
|
||||||
if(${CHANNEL_OPTION})
|
if(${CHANNEL_OPTION})
|
||||||
|
|
|
@ -25,14 +25,9 @@ include_directories(..)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
|
|
@ -25,14 +25,9 @@ include_directories(${ALSA_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})
|
set(${MODULE_PREFIX}_LIBS freerdp ${ALSA_LIBRARIES})
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,17 +354,22 @@ static void audin_alsa_close(IAudinDevice* device)
|
||||||
|
|
||||||
DEBUG_DVC("");
|
DEBUG_DVC("");
|
||||||
|
|
||||||
SetEvent(alsa->stopEvent);
|
if (alsa->stopEvent)
|
||||||
WaitForSingleObject(alsa->thread, INFINITE);
|
{
|
||||||
CloseHandle(alsa->stopEvent);
|
SetEvent(alsa->stopEvent);
|
||||||
CloseHandle(alsa->thread);
|
WaitForSingleObject(alsa->thread, INFINITE);
|
||||||
|
|
||||||
|
CloseHandle(alsa->stopEvent);
|
||||||
|
alsa->stopEvent = NULL;
|
||||||
|
|
||||||
|
CloseHandle(alsa->thread);
|
||||||
|
alsa->thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (alsa->buffer)
|
if (alsa->buffer)
|
||||||
free(alsa->buffer);
|
free(alsa->buffer);
|
||||||
alsa->buffer = NULL;
|
alsa->buffer = NULL;
|
||||||
|
|
||||||
alsa->stopEvent = NULL;
|
|
||||||
alsa->thread = NULL;
|
|
||||||
alsa->receive = NULL;
|
alsa->receive = NULL;
|
||||||
alsa->user_data = NULL;
|
alsa->user_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||||
out = Stream_New(NULL, 5);
|
out = Stream_New(NULL, 5);
|
||||||
Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
|
Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
|
||||||
Stream_Write_UINT32(out, Version);
|
Stream_Write_UINT32(out, Version);
|
||||||
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(s), Stream_Buffer(s), NULL);
|
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), Stream_Buffer(out), NULL);
|
||||||
Stream_Free(out, TRUE);
|
Stream_Free(out, TRUE);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,44 +312,39 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
wStream* s;
|
|
||||||
BYTE MessageId;
|
BYTE MessageId;
|
||||||
|
|
||||||
s = Stream_New(pBuffer, cbSize);
|
Stream_Read_UINT8(data, MessageId);
|
||||||
|
|
||||||
Stream_Read_UINT8(s, MessageId);
|
|
||||||
|
|
||||||
DEBUG_DVC("MessageId=0x%x", MessageId);
|
DEBUG_DVC("MessageId=0x%x", MessageId);
|
||||||
|
|
||||||
switch (MessageId)
|
switch (MessageId)
|
||||||
{
|
{
|
||||||
case MSG_SNDIN_VERSION:
|
case MSG_SNDIN_VERSION:
|
||||||
error = audin_process_version(pChannelCallback, s);
|
error = audin_process_version(pChannelCallback, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_SNDIN_FORMATS:
|
case MSG_SNDIN_FORMATS:
|
||||||
error = audin_process_formats(pChannelCallback, s);
|
error = audin_process_formats(pChannelCallback, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_SNDIN_OPEN:
|
case MSG_SNDIN_OPEN:
|
||||||
error = audin_process_open(pChannelCallback, s);
|
error = audin_process_open(pChannelCallback, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_SNDIN_FORMATCHANGE:
|
case MSG_SNDIN_FORMATCHANGE:
|
||||||
error = audin_process_format_change(pChannelCallback, s);
|
error = audin_process_format_change(pChannelCallback, data);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Free(s, FALSE);
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +417,12 @@ static int audin_plugin_terminated(IWTSPlugin* pPlugin)
|
||||||
audin->device = NULL;
|
audin->device = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(audin->subsystem);
|
||||||
|
audin->subsystem = NULL;
|
||||||
|
|
||||||
|
free(audin->device_name);
|
||||||
|
audin->device_name = NULL;
|
||||||
|
|
||||||
free(audin->listener_callback);
|
free(audin->listener_callback);
|
||||||
free(audin);
|
free(audin);
|
||||||
|
|
||||||
|
@ -434,7 +435,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,7 +460,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,7 +619,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 */
|
||||||
|
|
|
@ -26,16 +26,9 @@ include_directories(${OPENSLES_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils
|
|
||||||
${OPENSLES_LIBRARIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES})
|
set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES})
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,14 +25,9 @@ include_directories(${PULSE_INCLUDE_DIR})
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY})
|
set(${MODULE_PREFIX}_LIBS freerdp ${PULSE_LIBRARY})
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,14 +24,9 @@ include_directories(..)
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib)
|
set(${MODULE_PREFIX}_LIBS freerdp winmm.lib)
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
|
|
@ -22,14 +22,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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
|
||||||
|
@ -77,9 +79,11 @@ static void audin_server_select_format(audin_server_context* context, int client
|
||||||
|
|
||||||
static void audin_server_send_version(audin_server* audin, wStream* s)
|
static void audin_server_send_version(audin_server* audin, wStream* s)
|
||||||
{
|
{
|
||||||
|
ULONG written;
|
||||||
|
|
||||||
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
|
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
|
||||||
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
|
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
|
||||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
||||||
|
@ -101,6 +105,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
UINT32 nAvgBytesPerSec;
|
UINT32 nAvgBytesPerSec;
|
||||||
|
ULONG written;
|
||||||
|
|
||||||
Stream_SetPosition(s, 0);
|
Stream_SetPosition(s, 0);
|
||||||
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
|
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
|
||||||
|
@ -131,7 +136,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
||||||
|
@ -181,6 +186,8 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
|
||||||
|
|
||||||
static void audin_server_send_open(audin_server* audin, wStream* s)
|
static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||||
{
|
{
|
||||||
|
ULONG written;
|
||||||
|
|
||||||
if (audin->context.selected_client_format < 0)
|
if (audin->context.selected_client_format < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -203,7 +210,7 @@ static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||||
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
|
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
|
||||||
Stream_Write_UINT16(s, 0); /* cbSize */
|
Stream_Write_UINT16(s, 0); /* cbSize */
|
||||||
|
|
||||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
||||||
|
@ -340,24 +347,16 @@ static void* audin_server_thread_func(void* arg)
|
||||||
|
|
||||||
Stream_SetPosition(s, 0);
|
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--;
|
||||||
|
|
||||||
|
@ -388,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/addin.c
|
${CMAKE_CURRENT_SOURCE_DIR}/addin.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/addin.h)
|
${CMAKE_CURRENT_SOURCE_DIR}/addin.h)
|
||||||
|
|
||||||
|
if(CHANNEL_STATIC_CLIENT_ENTRIES)
|
||||||
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
|
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
|
||||||
|
endif()
|
||||||
|
|
||||||
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
|
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
|
||||||
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
|
||||||
|
@ -96,15 +98,7 @@ set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NUL
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c)
|
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)
|
||||||
|
|
|
@ -156,19 +156,23 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
|
||||||
|
|
||||||
if (pszName && pszSubsystem && pszType)
|
if (pszName && pszSubsystem && pszType)
|
||||||
{
|
{
|
||||||
sprintf_s(pszPattern, cchPattern, "%s-client-%s-%s.%s", pszName, pszSubsystem, pszType, pszExtension);
|
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s",
|
||||||
|
pszName, pszSubsystem, pszType, pszExtension);
|
||||||
}
|
}
|
||||||
else if (pszName && pszType)
|
else if (pszName && pszType)
|
||||||
{
|
{
|
||||||
sprintf_s(pszPattern, cchPattern, "%s-client-?-%s.%s", pszName, pszType, pszExtension);
|
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s",
|
||||||
|
pszName, pszType, pszExtension);
|
||||||
}
|
}
|
||||||
else if (pszName)
|
else if (pszName)
|
||||||
{
|
{
|
||||||
sprintf_s(pszPattern, cchPattern, "%s-client*.%s", pszName, pszExtension);
|
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client*.%s",
|
||||||
|
pszName, pszExtension);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf_s(pszPattern, cchPattern, "?-client*.%s", pszExtension);
|
sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"?-client*.%s",
|
||||||
|
pszExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
cchPattern = strlen(pszPattern);
|
cchPattern = strlen(pszPattern);
|
||||||
|
|
|
@ -25,17 +25,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
set(${MODULE_PREFIX}_LIBS freerdp winpr)
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -22,484 +22,233 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/print.h>
|
#include <winpr/print.h>
|
||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <freerdp/client/cliprdr.h>
|
#include <freerdp/client/cliprdr.h>
|
||||||
|
|
||||||
#include "cliprdr_main.h"
|
#include "cliprdr_main.h"
|
||||||
#include "cliprdr_format.h"
|
#include "cliprdr_format.h"
|
||||||
|
|
||||||
#define CFSTR_HTML "H\0T\0M\0L\0 \0F\0o\0r\0m\0a\0t\0\0"
|
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
||||||
#define CFSTR_PNG "P\0N\0G\0\0"
|
|
||||||
#define CFSTR_JPEG "J\0F\0I\0F\0\0"
|
|
||||||
#define CFSTR_GIF "G\0I\0F\0\0"
|
|
||||||
|
|
||||||
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event)
|
|
||||||
{
|
{
|
||||||
int i;
|
UINT32 index;
|
||||||
wStream* s;
|
UINT32 position;
|
||||||
|
BOOL asciiNames;
|
||||||
|
int formatNameLength;
|
||||||
|
char* szFormatName;
|
||||||
|
WCHAR* wszFormatName;
|
||||||
|
CLIPRDR_FORMAT* formats = NULL;
|
||||||
|
CLIPRDR_FORMAT_LIST formatList;
|
||||||
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending Clipboard Format List");
|
if (!context->custom)
|
||||||
|
return;
|
||||||
|
|
||||||
|
asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE;
|
||||||
|
|
||||||
|
formatList.msgType = CB_FORMAT_LIST;
|
||||||
|
formatList.msgFlags = msgFlags;
|
||||||
|
formatList.dataLen = dataLen;
|
||||||
|
|
||||||
if (cb_event->raw_format_data)
|
index = 0;
|
||||||
|
formatList.numFormats = 0;
|
||||||
|
position = Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if (!formatList.dataLen)
|
||||||
{
|
{
|
||||||
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, cb_event->raw_format_data_size);
|
/* empty format list */
|
||||||
Stream_Write(s, cb_event->raw_format_data, cb_event->raw_format_data_size);
|
formatList.formats = NULL;
|
||||||
|
formatList.numFormats = 0;
|
||||||
}
|
}
|
||||||
else
|
else if (!cliprdr->useLongFormatNames)
|
||||||
{
|
{
|
||||||
wStream* body = Stream_New(NULL, 64);
|
formatList.numFormats = (dataLen / 36);
|
||||||
|
|
||||||
for (i = 0; i < cb_event->num_formats; i++)
|
if ((formatList.numFormats * 36) != dataLen)
|
||||||
{
|
{
|
||||||
const char* name;
|
WLog_ERR(TAG, "Invalid short format list length: %d", dataLen);
|
||||||
int name_length, short_name_length = 32, x;
|
return;
|
||||||
|
}
|
||||||
switch (cb_event->formats[i])
|
|
||||||
{
|
if (formatList.numFormats)
|
||||||
case CB_FORMAT_HTML:
|
formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT));
|
||||||
name = CFSTR_HTML;
|
|
||||||
name_length = sizeof(CFSTR_HTML);
|
if (!formats)
|
||||||
break;
|
return;
|
||||||
case CB_FORMAT_PNG:
|
|
||||||
name = CFSTR_PNG;
|
formatList.formats = formats;
|
||||||
name_length = sizeof(CFSTR_PNG);
|
|
||||||
break;
|
while (dataLen)
|
||||||
case CB_FORMAT_JPEG:
|
{
|
||||||
name = CFSTR_JPEG;
|
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
|
||||||
name_length = sizeof(CFSTR_JPEG);
|
dataLen -= 4;
|
||||||
break;
|
|
||||||
case CB_FORMAT_GIF:
|
|
||||||
name = CFSTR_GIF;
|
|
||||||
name_length = sizeof(CFSTR_GIF);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = "\0\0";
|
|
||||||
name_length = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cliprdr->use_long_format_names)
|
formats[index].formatName = NULL;
|
||||||
{
|
|
||||||
x = (name_length > short_name_length) ?
|
if (asciiNames)
|
||||||
name_length : short_name_length;
|
{
|
||||||
|
szFormatName = (char*) Stream_Pointer(s);
|
||||||
Stream_EnsureRemainingCapacity(body, 4 + short_name_length);
|
|
||||||
Stream_Write_UINT32(body, cb_event->formats[i]);
|
if (szFormatName[0])
|
||||||
Stream_Write(body, name, x);
|
{
|
||||||
|
formats[index].formatName = (char*) malloc(32 + 1);
|
||||||
while (x++ < short_name_length)
|
CopyMemory(formats[index].formatName, szFormatName, 32);
|
||||||
Stream_Write(body, "\0", 1);
|
formats[index].formatName[32] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Stream_EnsureRemainingCapacity(body, 4 + name_length);
|
wszFormatName = (WCHAR*) Stream_Pointer(s);
|
||||||
Stream_Write_UINT32(body, cb_event->formats[i]);
|
|
||||||
Stream_Write(body, name, name_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream_SealLength(body);
|
if (wszFormatName[0])
|
||||||
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, Stream_Length(body));
|
{
|
||||||
Stream_Write(s, Stream_Buffer(body), Stream_Length(body));
|
ConvertFromUnicode(CP_UTF8, 0, wszFormatName,
|
||||||
Stream_Free(body, TRUE);
|
16, &(formats[index].formatName), 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cliprdr_packet_send(cliprdr, s);
|
|
||||||
}
|
Stream_Seek(s, 32);
|
||||||
|
dataLen -= 32;
|
||||||
static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr)
|
index++;
|
||||||
{
|
|
||||||
wStream* s;
|
|
||||||
DEBUG_CLIPRDR("Sending Clipboard Format List Response");
|
|
||||||
s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0);
|
|
||||||
cliprdr_packet_send(cliprdr, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
BOOL ascii;
|
|
||||||
int num_formats;
|
|
||||||
CLIPRDR_FORMAT_NAME* format_name;
|
|
||||||
|
|
||||||
num_formats = length / 36;
|
|
||||||
|
|
||||||
if (num_formats <= 0)
|
|
||||||
{
|
|
||||||
cliprdr->format_names = NULL;
|
|
||||||
cliprdr->num_format_names = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_formats * 36 != length)
|
|
||||||
DEBUG_WARN("dataLen %d not divided by 36!", length);
|
|
||||||
|
|
||||||
ascii = (flags & CB_ASCII_NAMES) ? TRUE : FALSE;
|
|
||||||
|
|
||||||
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats);
|
|
||||||
cliprdr->num_format_names = num_formats;
|
|
||||||
|
|
||||||
for (i = 0; i < num_formats; i++)
|
|
||||||
{
|
|
||||||
format_name = &cliprdr->format_names[i];
|
|
||||||
|
|
||||||
Stream_Read_UINT32(s, format_name->id);
|
|
||||||
|
|
||||||
if (ascii)
|
|
||||||
{
|
|
||||||
format_name->name = _strdup((char*) s->pointer);
|
|
||||||
format_name->length = strlen(format_name->name);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
format_name->name = NULL;
|
|
||||||
format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) s->pointer, 32 / 2, &format_name->name, 0, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream_Seek(s, 32);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags)
|
|
||||||
{
|
|
||||||
int allocated_formats = 8;
|
|
||||||
BYTE* end_mark;
|
|
||||||
CLIPRDR_FORMAT_NAME* format_name;
|
|
||||||
|
|
||||||
Stream_GetPointer(s, end_mark);
|
|
||||||
end_mark += length;
|
|
||||||
|
|
||||||
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) malloc(sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
|
|
||||||
cliprdr->num_format_names = 0;
|
|
||||||
|
|
||||||
while (Stream_GetRemainingLength(s) >= 6)
|
|
||||||
{
|
{
|
||||||
BYTE* p;
|
|
||||||
int name_len;
|
|
||||||
|
|
||||||
if (cliprdr->num_format_names >= allocated_formats)
|
|
||||||
{
|
|
||||||
allocated_formats *= 2;
|
|
||||||
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) realloc(cliprdr->format_names,
|
|
||||||
sizeof(CLIPRDR_FORMAT_NAME) * allocated_formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
format_name = &cliprdr->format_names[cliprdr->num_format_names++];
|
|
||||||
Stream_Read_UINT32(s, format_name->id);
|
|
||||||
|
|
||||||
format_name->name = NULL;
|
|
||||||
format_name->length = 0;
|
|
||||||
|
|
||||||
for (p = Stream_Pointer(s), name_len = 0; p + 1 < end_mark; p += 2, name_len += 2)
|
|
||||||
{
|
|
||||||
if (*((unsigned short*) p) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), name_len / 2, &format_name->name, 0, NULL, NULL);
|
|
||||||
|
|
||||||
Stream_Seek(s, name_len + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
|
||||||
{
|
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
|
||||||
|
|
||||||
if (context->custom)
|
|
||||||
{
|
|
||||||
UINT32 index;
|
|
||||||
int formatNameLength;
|
|
||||||
CLIPRDR_FORMAT* formats;
|
|
||||||
CLIPRDR_FORMAT_LIST formatList;
|
|
||||||
|
|
||||||
formatList.msgType = CB_FORMAT_LIST;
|
|
||||||
formatList.msgFlags = msgFlags;
|
|
||||||
formatList.dataLen = dataLen;
|
|
||||||
|
|
||||||
formatList.cFormats = 0;
|
|
||||||
|
|
||||||
while (dataLen)
|
while (dataLen)
|
||||||
{
|
{
|
||||||
Stream_Seek(s, 4); /* formatId */
|
Stream_Seek(s, 4); /* formatId (4 bytes) */
|
||||||
dataLen -= 4;
|
dataLen -= 4;
|
||||||
|
|
||||||
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
|
wszFormatName = (WCHAR*) Stream_Pointer(s);
|
||||||
|
|
||||||
|
if (!wszFormatName[0])
|
||||||
|
formatNameLength = 0;
|
||||||
|
else
|
||||||
|
formatNameLength = _wcslen(wszFormatName);
|
||||||
|
|
||||||
Stream_Seek(s, (formatNameLength + 1) * 2);
|
Stream_Seek(s, (formatNameLength + 1) * 2);
|
||||||
dataLen -= ((formatNameLength + 1) * 2);
|
dataLen -= ((formatNameLength + 1) * 2);
|
||||||
formatList.cFormats++;
|
|
||||||
|
formatList.numFormats++;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = 0;
|
|
||||||
dataLen = formatList.dataLen;
|
dataLen = formatList.dataLen;
|
||||||
Stream_Rewind(s, dataLen);
|
Stream_SetPosition(s, position);
|
||||||
|
|
||||||
|
if (formatList.numFormats)
|
||||||
|
formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT));
|
||||||
|
|
||||||
|
if (!formats)
|
||||||
|
return;
|
||||||
|
|
||||||
formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.cFormats);
|
|
||||||
formatList.formats = formats;
|
formatList.formats = formats;
|
||||||
|
|
||||||
while (dataLen)
|
while (dataLen)
|
||||||
{
|
{
|
||||||
Stream_Read_UINT32(s, formats[index].formatId); /* formatId */
|
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
|
||||||
dataLen -= 4;
|
dataLen -= 4;
|
||||||
|
|
||||||
formats[index].formatName = NULL;
|
formats[index].formatName = NULL;
|
||||||
formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s));
|
|
||||||
|
wszFormatName = (WCHAR*) Stream_Pointer(s);
|
||||||
|
|
||||||
|
if (!wszFormatName[0])
|
||||||
|
formatNameLength = 0;
|
||||||
|
else
|
||||||
|
formatNameLength = _wcslen(wszFormatName);
|
||||||
|
|
||||||
if (formatNameLength)
|
if (formatNameLength)
|
||||||
{
|
{
|
||||||
formatNameLength = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
ConvertFromUnicode(CP_UTF8, 0, wszFormatName,
|
||||||
-1, &(formats[index].formatName), 0, NULL, NULL);
|
-1, &(formats[index].formatName), 0, NULL, NULL);
|
||||||
|
|
||||||
Stream_Seek(s, formatNameLength * 2);
|
|
||||||
dataLen -= (formatNameLength * 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Stream_Seek(s, 2);
|
|
||||||
dataLen -= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream_Seek(s, (formatNameLength + 1) * 2);
|
||||||
|
dataLen -= ((formatNameLength + 1) * 2);
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->ServerFormatList)
|
|
||||||
context->ServerFormatList(context, &formatList);
|
|
||||||
|
|
||||||
for (index = 0; index < formatList.cFormats; index++)
|
|
||||||
free(formats[index].formatName);
|
|
||||||
|
|
||||||
free(formats);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d",
|
||||||
|
formatList.numFormats);
|
||||||
|
|
||||||
|
if (context->ServerFormatList)
|
||||||
|
context->ServerFormatList(context, &formatList);
|
||||||
|
|
||||||
|
for (index = 0; index < formatList.numFormats; index++)
|
||||||
{
|
{
|
||||||
int i;
|
if (formats[index].formatName)
|
||||||
UINT32 format;
|
free(formats[index].formatName);
|
||||||
BOOL supported;
|
|
||||||
CLIPRDR_FORMAT_NAME* format_name;
|
|
||||||
RDP_CB_FORMAT_LIST_EVENT* cb_event;
|
|
||||||
|
|
||||||
cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
|
||||||
CliprdrChannel_FormatList, NULL, NULL);
|
|
||||||
|
|
||||||
if (dataLen > 0)
|
|
||||||
{
|
|
||||||
cb_event->raw_format_data = (BYTE*) malloc(dataLen);
|
|
||||||
memcpy(cb_event->raw_format_data, Stream_Pointer(s), dataLen);
|
|
||||||
cb_event->raw_format_data_size = dataLen;
|
|
||||||
cb_event->raw_format_unicode = (msgFlags & CB_ASCII_NAMES) ? FALSE : TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cliprdr->use_long_format_names)
|
|
||||||
cliprdr_process_long_format_names(cliprdr, s, dataLen, msgFlags);
|
|
||||||
else
|
|
||||||
cliprdr_process_short_format_names(cliprdr, s, dataLen, msgFlags);
|
|
||||||
|
|
||||||
if (cliprdr->num_format_names > 0)
|
|
||||||
cb_event->formats = (UINT32*) malloc(sizeof(UINT32) * cliprdr->num_format_names);
|
|
||||||
|
|
||||||
cb_event->num_formats = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < cliprdr->num_format_names; i++)
|
|
||||||
{
|
|
||||||
supported = TRUE;
|
|
||||||
format_name = &cliprdr->format_names[i];
|
|
||||||
format = format_name->id;
|
|
||||||
|
|
||||||
switch (format)
|
|
||||||
{
|
|
||||||
case CB_FORMAT_TEXT:
|
|
||||||
case CB_FORMAT_DIB:
|
|
||||||
case CB_FORMAT_UNICODETEXT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
|
|
||||||
if (format_name->length > 0)
|
|
||||||
{
|
|
||||||
DEBUG_CLIPRDR("format: %s", format_name->name);
|
|
||||||
|
|
||||||
if (strcmp(format_name->name, "HTML Format") == 0)
|
|
||||||
{
|
|
||||||
format = CB_FORMAT_HTML;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strcmp(format_name->name, "PNG") == 0)
|
|
||||||
{
|
|
||||||
format = CB_FORMAT_PNG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strcmp(format_name->name, "JFIF") == 0)
|
|
||||||
{
|
|
||||||
format = CB_FORMAT_JPEG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strcmp(format_name->name, "GIF") == 0)
|
|
||||||
{
|
|
||||||
format = CB_FORMAT_GIF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
supported = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supported)
|
|
||||||
cb_event->formats[cb_event->num_formats++] = format;
|
|
||||||
|
|
||||||
if (format_name->length > 0)
|
|
||||||
free(format_name->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(cliprdr->format_names);
|
|
||||||
cliprdr->format_names = NULL;
|
|
||||||
|
|
||||||
cliprdr->num_format_names = 0;
|
|
||||||
|
|
||||||
cliprdr_send_format_list_response(cliprdr);
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
||||||
{
|
{
|
||||||
|
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
/* http://msdn.microsoft.com/en-us/library/hh872154.aspx */
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse");
|
||||||
|
|
||||||
if (context->custom)
|
if (!context->custom)
|
||||||
{
|
return;
|
||||||
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
|
|
||||||
|
|
||||||
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
|
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
|
||||||
formatListResponse.msgFlags = msgFlags;
|
formatListResponse.msgFlags = msgFlags;
|
||||||
formatListResponse.dataLen = dataLen;
|
formatListResponse.dataLen = dataLen;
|
||||||
|
|
||||||
if (context->ServerFormatListResponse)
|
if (context->ServerFormatListResponse)
|
||||||
context->ServerFormatListResponse(context, &formatListResponse);
|
context->ServerFormatListResponse(context, &formatListResponse);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((msgFlags & CB_RESPONSE_FAIL) != 0)
|
|
||||||
{
|
|
||||||
/* In case of an error the clipboard will not be synchronized with the server.
|
|
||||||
* Post this event to restart format negotiation and data transfer. */
|
|
||||||
|
|
||||||
wMessage* event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
||||||
{
|
{
|
||||||
|
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
if (context->custom)
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest");
|
||||||
{
|
|
||||||
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
|
|
||||||
|
|
||||||
formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST;
|
if (!context->custom)
|
||||||
formatDataRequest.msgFlags = msgFlags;
|
return;
|
||||||
formatDataRequest.dataLen = dataLen;
|
|
||||||
|
|
||||||
Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */
|
formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST;
|
||||||
|
formatDataRequest.msgFlags = msgFlags;
|
||||||
|
formatDataRequest.dataLen = dataLen;
|
||||||
|
|
||||||
if (context->ServerFormatDataRequest)
|
Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */
|
||||||
context->ServerFormatDataRequest(context, &formatDataRequest);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RDP_CB_DATA_REQUEST_EVENT* cb_event;
|
|
||||||
|
|
||||||
cb_event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
if (context->ServerFormatDataRequest)
|
||||||
CliprdrChannel_DataRequest, NULL, NULL);
|
context->ServerFormatDataRequest(context, &formatDataRequest);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, cb_event->format);
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event)
|
|
||||||
{
|
|
||||||
wStream* s;
|
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending Format Data Response");
|
|
||||||
|
|
||||||
if (cb_event->size > 0)
|
|
||||||
{
|
|
||||||
s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_OK, cb_event->size);
|
|
||||||
Stream_Write(s, cb_event->data, cb_event->size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_FAIL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
cliprdr_packet_send(cliprdr, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event)
|
|
||||||
{
|
|
||||||
wStream* s;
|
|
||||||
|
|
||||||
DEBUG_CLIPRDR("Sending Format Data Request");
|
|
||||||
|
|
||||||
s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
|
|
||||||
Stream_Write_UINT32(s, cb_event->format);
|
|
||||||
cliprdr_packet_send(cliprdr, s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
||||||
{
|
{
|
||||||
|
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
|
||||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||||
|
|
||||||
if (context->custom)
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse");
|
||||||
{
|
|
||||||
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
|
|
||||||
|
|
||||||
formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
|
|
||||||
formatDataResponse.msgFlags = msgFlags;
|
|
||||||
formatDataResponse.dataLen = dataLen;
|
|
||||||
formatDataResponse.requestedFormatData = NULL;
|
|
||||||
|
|
||||||
if (dataLen)
|
|
||||||
{
|
|
||||||
formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen);
|
|
||||||
Stream_Read(s, formatDataResponse.requestedFormatData, dataLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->ServerFormatDataResponse)
|
|
||||||
context->ServerFormatDataResponse(context, &formatDataResponse);
|
|
||||||
|
|
||||||
free(formatDataResponse.requestedFormatData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RDP_CB_DATA_RESPONSE_EVENT* cb_event;
|
|
||||||
|
|
||||||
cb_event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class,
|
if (!context->custom)
|
||||||
CliprdrChannel_DataResponse, NULL, NULL);
|
return;
|
||||||
|
|
||||||
|
formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
|
||||||
|
formatDataResponse.msgFlags = msgFlags;
|
||||||
|
formatDataResponse.dataLen = dataLen;
|
||||||
|
formatDataResponse.requestedFormatData = NULL;
|
||||||
|
|
||||||
if (dataLen > 0)
|
if (dataLen)
|
||||||
{
|
{
|
||||||
cb_event->size = dataLen;
|
formatDataResponse.requestedFormatData = (BYTE*) malloc(dataLen);
|
||||||
cb_event->data = (BYTE*) malloc(dataLen);
|
Stream_Read(s, formatDataResponse.requestedFormatData, dataLen);
|
||||||
CopyMemory(cb_event->data, Stream_Pointer(s), dataLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context->ServerFormatDataResponse)
|
||||||
|
context->ServerFormatDataResponse(context, &formatDataResponse);
|
||||||
|
|
||||||
|
free(formatDataResponse.requestedFormatData);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,9 @@
|
||||||
#ifndef __CLIPRDR_FORMAT_H
|
#ifndef __CLIPRDR_FORMAT_H
|
||||||
#define __CLIPRDR_FORMAT_H
|
#define __CLIPRDR_FORMAT_H
|
||||||
|
|
||||||
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event);
|
|
||||||
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
||||||
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
||||||
|
|
||||||
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
||||||
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event);
|
|
||||||
|
|
||||||
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event);
|
|
||||||
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
|
||||||
|
|
||||||
#endif /* __CLIPRDR_FORMAT_H */
|
#endif /* __CLIPRDR_FORMAT_H */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,18 +23,31 @@
|
||||||
|
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
#include <freerdp/utils/debug.h>
|
#include <freerdp/svc.h>
|
||||||
|
#include <freerdp/addin.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("cliprdr.client")
|
||||||
|
|
||||||
struct cliprdr_plugin
|
struct cliprdr_plugin
|
||||||
{
|
{
|
||||||
rdpSvcPlugin plugin;
|
CHANNEL_DEF channelDef;
|
||||||
BOOL received_caps;
|
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
|
||||||
BOOL use_long_format_names;
|
|
||||||
BOOL stream_fileclip_enabled;
|
CliprdrClientContext* context;
|
||||||
BOOL fileclip_no_file_paths;
|
|
||||||
BOOL can_lock_clipdata;
|
wLog* log;
|
||||||
CLIPRDR_FORMAT_NAME* format_names;
|
HANDLE thread;
|
||||||
int num_format_names;
|
wStream* data_in;
|
||||||
|
void* InitHandle;
|
||||||
|
DWORD OpenHandle;
|
||||||
|
wMessageQueue* queue;
|
||||||
|
|
||||||
|
BOOL capabilitiesReceived;
|
||||||
|
BOOL useLongFormatNames;
|
||||||
|
BOOL streamFileClipEnabled;
|
||||||
|
BOOL fileClipNoFilePaths;
|
||||||
|
BOOL canLockClipData;
|
||||||
};
|
};
|
||||||
typedef struct cliprdr_plugin cliprdrPlugin;
|
typedef struct cliprdr_plugin cliprdrPlugin;
|
||||||
|
|
||||||
|
@ -44,9 +57,9 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* data_out);
|
||||||
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
|
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 */
|
||||||
|
|
|
@ -23,14 +23,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,27 +22,32 @@
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/synch.h>
|
#include <winpr/synch.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
#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
|
||||||
{
|
{
|
||||||
|
HANDLE vcm;
|
||||||
HANDLE Thread;
|
HANDLE Thread;
|
||||||
HANDLE StopEvent;
|
HANDLE StopEvent;
|
||||||
void* ChannelHandle;
|
void* ChannelHandle;
|
||||||
|
HANDLE ChannelEvent;
|
||||||
|
|
||||||
BOOL UseLongFormatNames;
|
BOOL useLongFormatNames;
|
||||||
BOOL StreamFileClipEnabled;
|
BOOL streamFileClipEnabled;
|
||||||
BOOL FileClipNoFilePaths;
|
BOOL fileClipNoFilePaths;
|
||||||
BOOL CanLockClipData;
|
BOOL canLockClipData;
|
||||||
|
|
||||||
UINT32 ClientFormatNameCount;
|
wStream* s;
|
||||||
CLIPRDR_FORMAT_NAME* ClientFormatNames;
|
char* temporaryDirectory;
|
||||||
|
|
||||||
char* ClientTemporaryDirectory;
|
|
||||||
};
|
};
|
||||||
|
typedef struct _cliprdr_server_private CliprdrServerPrivate;
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */
|
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */
|
||||||
|
|
|
@ -25,17 +25,9 @@ include_directories(..)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
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;
|
||||||
|
|
||||||
|
@ -83,11 +83,7 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
||||||
|
|
||||||
disp = (DISP_PLUGIN*) callback->plugin;
|
disp = (DISP_PLUGIN*) callback->plugin;
|
||||||
|
|
||||||
#ifdef DISP_PREVIEW
|
|
||||||
MonitorLayoutSize = 32;
|
|
||||||
#else
|
|
||||||
MonitorLayoutSize = 40;
|
MonitorLayoutSize = 40;
|
||||||
#endif
|
|
||||||
|
|
||||||
length = 8 + 8 + (NumMonitors * MonitorLayoutSize);
|
length = 8 + 8 + (NumMonitors * MonitorLayoutSize);
|
||||||
|
|
||||||
|
@ -101,15 +97,11 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
||||||
if (NumMonitors > disp->MaxNumMonitors)
|
if (NumMonitors > disp->MaxNumMonitors)
|
||||||
NumMonitors = disp->MaxNumMonitors;
|
NumMonitors = disp->MaxNumMonitors;
|
||||||
|
|
||||||
#ifdef DISP_PREVIEW
|
|
||||||
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
|
|
||||||
#else
|
|
||||||
Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
|
Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
|
||||||
#endif
|
|
||||||
|
|
||||||
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++)
|
||||||
{
|
{
|
||||||
|
@ -118,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) */
|
||||||
|
@ -135,21 +130,18 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
||||||
Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */
|
Stream_Write_UINT32(s, Monitors[index].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
|
|
||||||
|
|
||||||
#ifndef DISP_PREVIEW
|
|
||||||
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,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;
|
||||||
|
@ -183,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)
|
||||||
{
|
{
|
||||||
|
@ -201,17 +198,12 @@ int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||||
{
|
{
|
||||||
wStream* s;
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback;
|
DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback;
|
||||||
|
|
||||||
s = Stream_New(pBuffer, cbSize);
|
status = disp_recv_pdu(callback, data);
|
||||||
|
|
||||||
status = disp_recv_pdu(callback, s);
|
|
||||||
|
|
||||||
Stream_Free(s, FALSE);
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -235,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;
|
||||||
|
@ -255,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;
|
||||||
|
@ -308,33 +304,37 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
|
|
||||||
disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp");
|
disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp");
|
||||||
|
|
||||||
if (disp == NULL)
|
if (!disp)
|
||||||
{
|
{
|
||||||
disp = (DISP_PLUGIN*) malloc(sizeof(DISP_PLUGIN));
|
disp = (DISP_PLUGIN*) calloc(1, sizeof(DISP_PLUGIN));
|
||||||
|
|
||||||
if (disp)
|
if (!disp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
disp->iface.Initialize = disp_plugin_initialize;
|
||||||
|
disp->iface.Connected = NULL;
|
||||||
|
disp->iface.Disconnected = NULL;
|
||||||
|
disp->iface.Terminated = disp_plugin_terminated;
|
||||||
|
|
||||||
|
context = (DispClientContext*) calloc(1, sizeof(DispClientContext));
|
||||||
|
|
||||||
|
if (!context)
|
||||||
{
|
{
|
||||||
ZeroMemory(disp, sizeof(DISP_PLUGIN));
|
free(disp);
|
||||||
|
return -1;
|
||||||
disp->iface.Initialize = disp_plugin_initialize;
|
|
||||||
disp->iface.Connected = NULL;
|
|
||||||
disp->iface.Disconnected = NULL;
|
|
||||||
disp->iface.Terminated = disp_plugin_terminated;
|
|
||||||
|
|
||||||
context = (DispClientContext*) malloc(sizeof(DispClientContext));
|
|
||||||
|
|
||||||
context->handle = (void*) disp;
|
|
||||||
|
|
||||||
context->SendMonitorLayout = disp_send_monitor_layout;
|
|
||||||
|
|
||||||
disp->iface.pInterface = (void*) context;
|
|
||||||
|
|
||||||
disp->MaxNumMonitors = 16;
|
|
||||||
disp->MaxMonitorWidth = 8192;
|
|
||||||
disp->MaxMonitorHeight = 8192;
|
|
||||||
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context->handle = (void*) disp;
|
||||||
|
|
||||||
|
context->SendMonitorLayout = disp_send_monitor_layout;
|
||||||
|
|
||||||
|
disp->iface.pInterface = (void*) context;
|
||||||
|
|
||||||
|
disp->MaxNumMonitors = 16;
|
||||||
|
disp->MaxMonitorAreaFactorA = 8192;
|
||||||
|
disp->MaxMonitorAreaFactorB = 8192;
|
||||||
|
|
||||||
|
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -27,14 +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
|
|
||||||
|
|
||||||
#define DISP_PREVIEW 1
|
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */
|
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */
|
||||||
|
|
||||||
|
|
|
@ -19,25 +19,10 @@ define_channel_client("drdynvc")
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_SRCS
|
set(${MODULE_PREFIX}_SRCS
|
||||||
drdynvc_main.c
|
drdynvc_main.c
|
||||||
drdynvc_main.h
|
drdynvc_main.h)
|
||||||
drdynvc_types.h
|
|
||||||
dvcman.c
|
|
||||||
dvcman.h)
|
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-synch)
|
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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")
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,11 +20,88 @@
|
||||||
#ifndef __DRDYNVC_MAIN_H
|
#ifndef __DRDYNVC_MAIN_H
|
||||||
#define __DRDYNVC_MAIN_H
|
#define __DRDYNVC_MAIN_H
|
||||||
|
|
||||||
|
#include <winpr/wlog.h>
|
||||||
|
#include <winpr/synch.h>
|
||||||
|
#include <freerdp/settings.h>
|
||||||
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
#include <freerdp/api.h>
|
#include <freerdp/api.h>
|
||||||
#include <freerdp/svc.h>
|
#include <freerdp/svc.h>
|
||||||
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
#include <freerdp/client/drdynvc.h>
|
#include <freerdp/client/drdynvc.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
|
typedef struct drdynvc_plugin drdynvcPlugin;
|
||||||
|
|
||||||
|
#define MAX_PLUGINS 32
|
||||||
|
|
||||||
|
struct _DVCMAN
|
||||||
|
{
|
||||||
|
IWTSVirtualChannelManager iface;
|
||||||
|
|
||||||
|
drdynvcPlugin* drdynvc;
|
||||||
|
|
||||||
|
int num_plugins;
|
||||||
|
const char* plugin_names[MAX_PLUGINS];
|
||||||
|
IWTSPlugin* plugins[MAX_PLUGINS];
|
||||||
|
|
||||||
|
int num_listeners;
|
||||||
|
IWTSListener* listeners[MAX_PLUGINS];
|
||||||
|
|
||||||
|
wArrayList* channels;
|
||||||
|
wStreamPool* pool;
|
||||||
|
};
|
||||||
|
typedef struct _DVCMAN DVCMAN;
|
||||||
|
|
||||||
|
struct _DVCMAN_LISTENER
|
||||||
|
{
|
||||||
|
IWTSListener iface;
|
||||||
|
|
||||||
|
DVCMAN* dvcman;
|
||||||
|
char* channel_name;
|
||||||
|
UINT32 flags;
|
||||||
|
IWTSListenerCallback* listener_callback;
|
||||||
|
};
|
||||||
|
typedef struct _DVCMAN_LISTENER DVCMAN_LISTENER;
|
||||||
|
|
||||||
|
struct _DVCMAN_ENTRY_POINTS
|
||||||
|
{
|
||||||
|
IDRDYNVC_ENTRY_POINTS iface;
|
||||||
|
|
||||||
|
DVCMAN* dvcman;
|
||||||
|
ADDIN_ARGV* args;
|
||||||
|
rdpSettings* settings;
|
||||||
|
};
|
||||||
|
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
|
||||||
|
|
||||||
|
struct _DVCMAN_CHANNEL
|
||||||
|
{
|
||||||
|
IWTSVirtualChannel iface;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
DVCMAN* dvcman;
|
||||||
|
void* pInterface;
|
||||||
|
UINT32 channel_id;
|
||||||
|
char* channel_name;
|
||||||
|
IWTSVirtualChannelCallback* channel_callback;
|
||||||
|
|
||||||
|
wStream* dvc_data;
|
||||||
|
UINT32 dvc_data_length;
|
||||||
|
CRITICAL_SECTION lock;
|
||||||
|
};
|
||||||
|
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
|
||||||
|
|
||||||
|
enum _DRDYNVC_STATE
|
||||||
|
{
|
||||||
|
DRDYNVC_STATE_INITIAL,
|
||||||
|
DRDYNVC_STATE_CAPABILITIES,
|
||||||
|
DRDYNVC_STATE_READY,
|
||||||
|
DRDYNVC_STATE_OPENING_CHANNEL,
|
||||||
|
DRDYNVC_STATE_SEND_RECEIVE,
|
||||||
|
DRDYNVC_STATE_FINAL
|
||||||
|
};
|
||||||
|
typedef enum _DRDYNVC_STATE DRDYNVC_STATE;
|
||||||
|
|
||||||
#define CREATE_REQUEST_PDU 0x01
|
#define CREATE_REQUEST_PDU 0x01
|
||||||
#define DATA_FIRST_PDU 0x02
|
#define DATA_FIRST_PDU 0x02
|
||||||
|
@ -32,12 +109,19 @@
|
||||||
#define CLOSE_REQUEST_PDU 0x04
|
#define CLOSE_REQUEST_PDU 0x04
|
||||||
#define CAPABILITY_REQUEST_PDU 0x05
|
#define CAPABILITY_REQUEST_PDU 0x05
|
||||||
|
|
||||||
typedef struct drdynvc_plugin drdynvcPlugin;
|
|
||||||
|
|
||||||
struct drdynvc_plugin
|
struct drdynvc_plugin
|
||||||
{
|
{
|
||||||
rdpSvcPlugin plugin;
|
CHANNEL_DEF channelDef;
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
|
||||||
|
|
||||||
|
wLog* log;
|
||||||
|
HANDLE thread;
|
||||||
|
wStream* data_in;
|
||||||
|
void* InitHandle;
|
||||||
|
DWORD OpenHandle;
|
||||||
|
wMessageQueue* queue;
|
||||||
|
|
||||||
|
DRDYNVC_STATE state;
|
||||||
DrdynvcClientContext* context;
|
DrdynvcClientContext* context;
|
||||||
|
|
||||||
int version;
|
int version;
|
||||||
|
@ -51,6 +135,5 @@ struct drdynvc_plugin
|
||||||
};
|
};
|
||||||
|
|
||||||
int drdynvc_write_data(drdynvcPlugin* plugin, UINT32 ChannelId, BYTE* data, UINT32 data_size);
|
int drdynvc_write_data(drdynvcPlugin* plugin, UINT32 ChannelId, BYTE* data, UINT32 data_size);
|
||||||
int drdynvc_push_event(drdynvcPlugin* plugin, wMessage* event);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,485 +0,0 @@
|
||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* Dynamic Virtual Channel Manager
|
|
||||||
*
|
|
||||||
* Copyright 2010-2011 Vic Lee
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
|
||||||
#include <winpr/synch.h>
|
|
||||||
#include <winpr/stream.h>
|
|
||||||
|
|
||||||
#include <freerdp/addin.h>
|
|
||||||
|
|
||||||
#include "drdynvc_types.h"
|
|
||||||
#include "dvcman.h"
|
|
||||||
|
|
||||||
static int dvcman_get_configuration(IWTSListener* pListener, void** ppPropertyBag)
|
|
||||||
{
|
|
||||||
*ppPropertyBag = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr,
|
|
||||||
const char* pszChannelName, UINT32 ulFlags,
|
|
||||||
IWTSListenerCallback* pListenerCallback, IWTSListener** ppListener)
|
|
||||||
{
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
DVCMAN_LISTENER* listener;
|
|
||||||
|
|
||||||
if (dvcman->num_listeners < MAX_PLUGINS)
|
|
||||||
{
|
|
||||||
DEBUG_DVC("%d.%s.", dvcman->num_listeners, pszChannelName);
|
|
||||||
|
|
||||||
listener = (DVCMAN_LISTENER*) malloc(sizeof(DVCMAN_LISTENER));
|
|
||||||
ZeroMemory(listener, sizeof(DVCMAN_LISTENER));
|
|
||||||
|
|
||||||
listener->iface.GetConfiguration = dvcman_get_configuration;
|
|
||||||
listener->iface.pInterface = NULL;
|
|
||||||
|
|
||||||
listener->dvcman = dvcman;
|
|
||||||
listener->channel_name = _strdup(pszChannelName);
|
|
||||||
listener->flags = ulFlags;
|
|
||||||
listener->listener_callback = pListenerCallback;
|
|
||||||
|
|
||||||
if (ppListener)
|
|
||||||
*ppListener = (IWTSListener*) listener;
|
|
||||||
|
|
||||||
dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*) listener;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_WARN("Maximum DVC listener number reached.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dvcman_push_event(IWTSVirtualChannelManager* pChannelMgr, wMessage* pEvent)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
status = drdynvc_push_event(dvcman->drdynvc, pEvent);
|
|
||||||
|
|
||||||
if (status == 0)
|
|
||||||
{
|
|
||||||
DEBUG_DVC("event_type %d pushed.", GetMessageType(pEvent->id));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_WARN("event_type %d push failed.", GetMessageType(pEvent->id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name, IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman;
|
|
||||||
|
|
||||||
if (dvcman->num_plugins < MAX_PLUGINS)
|
|
||||||
{
|
|
||||||
DEBUG_DVC("num_plugins %d", dvcman->num_plugins);
|
|
||||||
dvcman->plugin_names[dvcman->num_plugins] = name;
|
|
||||||
dvcman->plugins[dvcman->num_plugins++] = pPlugin;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_WARN("Maximum DVC plugin number reached.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman;
|
|
||||||
|
|
||||||
for (i = 0; i < dvcman->num_plugins; i++)
|
|
||||||
{
|
|
||||||
if (dvcman->plugin_names[i] == name ||
|
|
||||||
strcmp(dvcman->plugin_names[i], name) == 0)
|
|
||||||
{
|
|
||||||
return dvcman->plugins[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
|
||||||
{
|
|
||||||
return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT32 dvcman_get_channel_id(IWTSVirtualChannel * channel)
|
|
||||||
{
|
|
||||||
return ((DVCMAN_CHANNEL*) channel)->channel_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
BOOL found = FALSE;
|
|
||||||
DVCMAN_CHANNEL* channel;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
ArrayList_Lock(dvcman->channels);
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++);
|
|
||||||
|
|
||||||
while (channel)
|
|
||||||
{
|
|
||||||
if (channel->channel_id == ChannelId)
|
|
||||||
{
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList_Unlock(dvcman->channels);
|
|
||||||
|
|
||||||
return (found) ? ((IWTSVirtualChannel*) channel) : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
BOOL found = FALSE;
|
|
||||||
void* pInterface = NULL;
|
|
||||||
DVCMAN_LISTENER* listener;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
for (i = 0; i < dvcman->num_listeners; i++)
|
|
||||||
{
|
|
||||||
listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
|
|
||||||
|
|
||||||
if (strcmp(listener->channel_name, ChannelName) == 0)
|
|
||||||
{
|
|
||||||
pInterface = listener->iface.pInterface;
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (found) ? pInterface : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
|
||||||
{
|
|
||||||
DVCMAN* dvcman;
|
|
||||||
|
|
||||||
dvcman = (DVCMAN*) malloc(sizeof(DVCMAN));
|
|
||||||
ZeroMemory(dvcman, sizeof(DVCMAN));
|
|
||||||
|
|
||||||
dvcman->iface.CreateListener = dvcman_create_listener;
|
|
||||||
dvcman->iface.PushEvent = dvcman_push_event;
|
|
||||||
dvcman->iface.FindChannelById = dvcman_find_channel_by_id;
|
|
||||||
dvcman->iface.GetChannelId = dvcman_get_channel_id;
|
|
||||||
dvcman->drdynvc = plugin;
|
|
||||||
dvcman->channels = ArrayList_New(TRUE);
|
|
||||||
|
|
||||||
return (IWTSVirtualChannelManager*) dvcman;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args)
|
|
||||||
{
|
|
||||||
DVCMAN_ENTRY_POINTS entryPoints;
|
|
||||||
PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
|
|
||||||
|
|
||||||
fprintf(stderr, "Loading Dynamic Virtual Channel %s\n", args->argv[0]);
|
|
||||||
|
|
||||||
pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(args->argv[0],
|
|
||||||
NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC);
|
|
||||||
|
|
||||||
if (pDVCPluginEntry)
|
|
||||||
{
|
|
||||||
entryPoints.iface.RegisterPlugin = dvcman_register_plugin;
|
|
||||||
entryPoints.iface.GetPlugin = dvcman_get_plugin;
|
|
||||||
entryPoints.iface.GetPluginData = dvcman_get_plugin_data;
|
|
||||||
entryPoints.dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
entryPoints.args = args;
|
|
||||||
|
|
||||||
pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dvcman_channel_free(DVCMAN_CHANNEL* channel)
|
|
||||||
{
|
|
||||||
if (channel->channel_callback)
|
|
||||||
channel->channel_callback->OnClose(channel->channel_callback);
|
|
||||||
|
|
||||||
free(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int count;
|
|
||||||
IWTSPlugin* pPlugin;
|
|
||||||
DVCMAN_LISTENER* listener;
|
|
||||||
DVCMAN_CHANNEL* channel;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
ArrayList_Lock(dvcman->channels);
|
|
||||||
|
|
||||||
count = ArrayList_Count(dvcman->channels);
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, i);
|
|
||||||
dvcman_channel_free(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList_Unlock(dvcman->channels);
|
|
||||||
|
|
||||||
ArrayList_Free(dvcman->channels);
|
|
||||||
|
|
||||||
for (i = 0; i < dvcman->num_listeners; i++)
|
|
||||||
{
|
|
||||||
listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
|
|
||||||
free(listener->channel_name);
|
|
||||||
free(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dvcman->num_plugins; i++)
|
|
||||||
{
|
|
||||||
pPlugin = dvcman->plugins[i];
|
|
||||||
|
|
||||||
if (pPlugin->Terminated)
|
|
||||||
pPlugin->Terminated(pPlugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(dvcman);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
IWTSPlugin* pPlugin;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
for (i = 0; i < dvcman->num_plugins; i++)
|
|
||||||
{
|
|
||||||
pPlugin = dvcman->plugins[i];
|
|
||||||
|
|
||||||
if (pPlugin->Initialize)
|
|
||||||
pPlugin->Initialize(pPlugin, pChannelMgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dvcman_write_channel(IWTSVirtualChannel* pChannel, UINT32 cbSize, BYTE* pBuffer, void* pReserved)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
|
|
||||||
|
|
||||||
WaitForSingleObject(channel->dvc_chan_mutex, INFINITE);
|
|
||||||
status = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize);
|
|
||||||
ReleaseMutex(channel->dvc_chan_mutex);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dvcman_close_channel_iface(IWTSVirtualChannel* pChannel)
|
|
||||||
{
|
|
||||||
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
|
|
||||||
DVCMAN* dvcman = channel->dvcman;
|
|
||||||
|
|
||||||
DEBUG_DVC("id=%d", channel->channel_id);
|
|
||||||
|
|
||||||
ArrayList_Remove(dvcman->channels, channel);
|
|
||||||
|
|
||||||
dvcman_channel_free(channel);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int bAccept;
|
|
||||||
DVCMAN_LISTENER* listener;
|
|
||||||
DVCMAN_CHANNEL* channel;
|
|
||||||
DrdynvcClientContext* context;
|
|
||||||
IWTSVirtualChannelCallback* pCallback;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
channel = (DVCMAN_CHANNEL*) malloc(sizeof(DVCMAN_CHANNEL));
|
|
||||||
ZeroMemory(channel, sizeof(DVCMAN_CHANNEL));
|
|
||||||
|
|
||||||
channel->dvcman = dvcman;
|
|
||||||
channel->channel_id = ChannelId;
|
|
||||||
channel->channel_name = _strdup(ChannelName);
|
|
||||||
|
|
||||||
for (i = 0; i < dvcman->num_listeners; i++)
|
|
||||||
{
|
|
||||||
listener = (DVCMAN_LISTENER*) dvcman->listeners[i];
|
|
||||||
|
|
||||||
if (strcmp(listener->channel_name, ChannelName) == 0)
|
|
||||||
{
|
|
||||||
channel->iface.Write = dvcman_write_channel;
|
|
||||||
channel->iface.Close = dvcman_close_channel_iface;
|
|
||||||
channel->dvc_chan_mutex = CreateMutex(NULL, FALSE, NULL);
|
|
||||||
|
|
||||||
bAccept = 1;
|
|
||||||
pCallback = NULL;
|
|
||||||
|
|
||||||
if (listener->listener_callback->OnNewChannelConnection(listener->listener_callback,
|
|
||||||
(IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback) == 0 && bAccept == 1)
|
|
||||||
{
|
|
||||||
DEBUG_DVC("listener %s created new channel %d",
|
|
||||||
listener->channel_name, channel->channel_id);
|
|
||||||
|
|
||||||
channel->status = 0;
|
|
||||||
channel->channel_callback = pCallback;
|
|
||||||
channel->pInterface = listener->iface.pInterface;
|
|
||||||
|
|
||||||
ArrayList_Add(dvcman->channels, channel);
|
|
||||||
|
|
||||||
context = dvcman->drdynvc->context;
|
|
||||||
IFCALL(context->OnChannelConnected, context, ChannelName, listener->iface.pInterface);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_WARN("channel rejected by plugin");
|
|
||||||
|
|
||||||
free(channel);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(channel);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId)
|
|
||||||
{
|
|
||||||
DVCMAN_CHANNEL* channel;
|
|
||||||
IWTSVirtualChannel* ichannel;
|
|
||||||
DrdynvcClientContext* context;
|
|
||||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
|
||||||
|
|
||||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
|
||||||
|
|
||||||
if (!channel)
|
|
||||||
{
|
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel->dvc_data)
|
|
||||||
{
|
|
||||||
Stream_Free(channel->dvc_data, TRUE);
|
|
||||||
channel->dvc_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel->status == 0)
|
|
||||||
{
|
|
||||||
context = dvcman->drdynvc->context;
|
|
||||||
|
|
||||||
IFCALL(context->OnChannelDisconnected, context, channel->channel_name, channel->pInterface);
|
|
||||||
|
|
||||||
free(channel->channel_name);
|
|
||||||
|
|
||||||
DEBUG_DVC("dvcman_close_channel: channel %d closed", ChannelId);
|
|
||||||
ichannel = (IWTSVirtualChannel*) channel;
|
|
||||||
ichannel->Close(ichannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length)
|
|
||||||
{
|
|
||||||
DVCMAN_CHANNEL* channel;
|
|
||||||
|
|
||||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
|
||||||
|
|
||||||
if (!channel)
|
|
||||||
{
|
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel->dvc_data)
|
|
||||||
Stream_Free(channel->dvc_data, TRUE);
|
|
||||||
|
|
||||||
channel->dvc_data = Stream_New(NULL, length);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
DVCMAN_CHANNEL* channel;
|
|
||||||
|
|
||||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
|
||||||
|
|
||||||
if (!channel)
|
|
||||||
{
|
|
||||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel->dvc_data)
|
|
||||||
{
|
|
||||||
/* Fragmented data */
|
|
||||||
if (Stream_GetPosition(channel->dvc_data) + data_size > (UINT32) Stream_Capacity(channel->dvc_data))
|
|
||||||
{
|
|
||||||
DEBUG_WARN("data exceeding declared length!");
|
|
||||||
Stream_Free(channel->dvc_data, TRUE);
|
|
||||||
channel->dvc_data = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream_Write(channel->dvc_data, data, data_size);
|
|
||||||
|
|
||||||
if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data))
|
|
||||||
{
|
|
||||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback,
|
|
||||||
Stream_Capacity(channel->dvc_data), Stream_Buffer(channel->dvc_data));
|
|
||||||
Stream_Free(channel->dvc_data, TRUE);
|
|
||||||
channel->dvc_data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback, data_size, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
/**
|
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
||||||
* Dynamic Virtual Channel Manager
|
|
||||||
*
|
|
||||||
* Copyright 2010-2011 Vic Lee
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __DVCMAN_H
|
|
||||||
#define __DVCMAN_H
|
|
||||||
|
|
||||||
#include <freerdp/dvc.h>
|
|
||||||
#include <freerdp/addin.h>
|
|
||||||
|
|
||||||
#include <winpr/collections.h>
|
|
||||||
|
|
||||||
#include "drdynvc_main.h"
|
|
||||||
|
|
||||||
#define MAX_PLUGINS 32
|
|
||||||
|
|
||||||
struct _DVCMAN
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager iface;
|
|
||||||
|
|
||||||
drdynvcPlugin* drdynvc;
|
|
||||||
|
|
||||||
const char* plugin_names[MAX_PLUGINS];
|
|
||||||
IWTSPlugin* plugins[MAX_PLUGINS];
|
|
||||||
int num_plugins;
|
|
||||||
|
|
||||||
IWTSListener* listeners[MAX_PLUGINS];
|
|
||||||
int num_listeners;
|
|
||||||
|
|
||||||
wArrayList* channels;
|
|
||||||
};
|
|
||||||
typedef struct _DVCMAN DVCMAN;
|
|
||||||
|
|
||||||
struct _DVCMAN_LISTENER
|
|
||||||
{
|
|
||||||
IWTSListener iface;
|
|
||||||
|
|
||||||
DVCMAN* dvcman;
|
|
||||||
char* channel_name;
|
|
||||||
UINT32 flags;
|
|
||||||
IWTSListenerCallback* listener_callback;
|
|
||||||
};
|
|
||||||
typedef struct _DVCMAN_LISTENER DVCMAN_LISTENER;
|
|
||||||
|
|
||||||
struct _DVCMAN_ENTRY_POINTS
|
|
||||||
{
|
|
||||||
IDRDYNVC_ENTRY_POINTS iface;
|
|
||||||
|
|
||||||
DVCMAN* dvcman;
|
|
||||||
ADDIN_ARGV* args;
|
|
||||||
};
|
|
||||||
typedef struct _DVCMAN_ENTRY_POINTS DVCMAN_ENTRY_POINTS;
|
|
||||||
|
|
||||||
struct _DVCMAN_CHANNEL
|
|
||||||
{
|
|
||||||
IWTSVirtualChannel iface;
|
|
||||||
|
|
||||||
int status;
|
|
||||||
DVCMAN* dvcman;
|
|
||||||
void* pInterface;
|
|
||||||
UINT32 channel_id;
|
|
||||||
char* channel_name;
|
|
||||||
IWTSVirtualChannelCallback* channel_callback;
|
|
||||||
|
|
||||||
wStream* dvc_data;
|
|
||||||
HANDLE dvc_chan_mutex;
|
|
||||||
};
|
|
||||||
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
|
|
||||||
|
|
||||||
IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin);
|
|
||||||
int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args);
|
|
||||||
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
|
|
||||||
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
|
|
||||||
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName);
|
|
||||||
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId);
|
|
||||||
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length);
|
|
||||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size);
|
|
||||||
|
|
||||||
void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -23,14 +23,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,19 +31,9 @@ endif()
|
||||||
|
|
||||||
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_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-crt winpr-file winpr-synch winpr-thread winpr-interlocked)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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 && 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);
|
||||||
|
@ -617,6 +620,9 @@ static void drive_free(DEVICE* device)
|
||||||
CloseHandle(drive->thread);
|
CloseHandle(drive->thread);
|
||||||
|
|
||||||
ListDictionary_Free(drive->files);
|
ListDictionary_Free(drive->files);
|
||||||
|
MessageQueue_Free(drive->IrpQueue);
|
||||||
|
|
||||||
|
Stream_Free(drive->device.data, TRUE);
|
||||||
|
|
||||||
free(drive);
|
free(drive);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -25,14 +25,9 @@ include_directories(..)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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;
|
||||||
|
@ -61,47 +60,23 @@ struct _ECHO_PLUGIN
|
||||||
ECHO_LISTENER_CALLBACK* listener_callback;
|
ECHO_LISTENER_CALLBACK* listener_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||||
{
|
{
|
||||||
int error;
|
int status;
|
||||||
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
||||||
|
BYTE* pBuffer = Stream_Pointer(data);
|
||||||
#ifdef WITH_DEBUG_DVC
|
UINT32 cbSize = Stream_GetRemainingLength(data);
|
||||||
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;
|
||||||
|
@ -114,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;
|
||||||
|
@ -134,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;
|
||||||
|
@ -151,9 +126,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -164,23 +140,25 @@ static int echo_plugin_terminated(IWTSPlugin* pPlugin)
|
||||||
|
|
||||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
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 */
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
# FreeRDP cmake build script
|
||||||
|
#
|
||||||
|
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
define_channel_server("echo")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_SRCS
|
||||||
|
echo_main.c)
|
||||||
|
|
||||||
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
|
@ -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);
|
||||||
|
}
|
|
@ -15,9 +15,12 @@
|
||||||
# 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.
|
||||||
|
|
||||||
define_channel("sample")
|
define_channel("encomsp")
|
||||||
|
|
||||||
if(WITH_CLIENT_CHANNELS)
|
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()
|
|
@ -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})
|
||||||
|
|
|
@ -15,21 +15,20 @@
|
||||||
# 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.
|
||||||
|
|
||||||
define_channel_client("sample")
|
define_channel_client("encomsp")
|
||||||
|
|
||||||
|
include_directories(..)
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_SRCS
|
set(${MODULE_PREFIX}_SRCS
|
||||||
sample_main.c
|
encomsp_main.c
|
||||||
sample_main.h)
|
encomsp_main.h)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
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")
|
|
@ -0,0 +1,957 @@
|
||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Multiparty Virtual Channel
|
||||||
|
*
|
||||||
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/print.h>
|
||||||
|
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
#include <freerdp/client/encomsp.h>
|
||||||
|
|
||||||
|
#include "encomsp_main.h"
|
||||||
|
|
||||||
|
static int encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
|
||||||
|
Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */
|
||||||
|
Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str)
|
||||||
|
{
|
||||||
|
ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */
|
||||||
|
|
||||||
|
if (str->cchString > 1024)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) (str->cchString * 2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp)
|
||||||
|
{
|
||||||
|
EncomspClientContext* pInterface;
|
||||||
|
pInterface = (EncomspClientContext*) encomsp->channelEntryPoints.pInterface;
|
||||||
|
return pInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
int encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s)
|
||||||
|
{
|
||||||
|
UINT32 status = 0;
|
||||||
|
|
||||||
|
if (!encomsp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
WLog_INFO(TAG, "EncomspWrite (%d)", Stream_Length(s));
|
||||||
|
winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status = encomsp->channelEntryPoints.pVirtualChannelWrite(encomsp->OpenHandle,
|
||||||
|
Stream_Buffer(s), (UINT32) Stream_Length(s), s);
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "encomsp_virtual_channel_write: VirtualChannelWrite failed %d", status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_FILTER_UPDATED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->FilterUpdated)
|
||||||
|
{
|
||||||
|
return context->FilterUpdated(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_APPLICATION_CREATED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 6)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
|
||||||
|
|
||||||
|
if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->ApplicationCreated)
|
||||||
|
{
|
||||||
|
return context->ApplicationCreated(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_APPLICATION_REMOVED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->ApplicationRemoved)
|
||||||
|
{
|
||||||
|
return context->ApplicationRemoved(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_WINDOW_CREATED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 10)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
|
||||||
|
|
||||||
|
if (encomsp_read_unicode_string(s, &(pdu.Name)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->WindowCreated)
|
||||||
|
{
|
||||||
|
return context->WindowCreated(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_WINDOW_REMOVED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->WindowRemoved)
|
||||||
|
{
|
||||||
|
return context->WindowRemoved(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_SHOW_WINDOW_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->ShowWindow)
|
||||||
|
{
|
||||||
|
return context->ShowWindow(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_PARTICIPANT_CREATED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 10)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */
|
||||||
|
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
|
||||||
|
|
||||||
|
if (encomsp_read_unicode_string(s, &(pdu.FriendlyName)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->ParticipantCreated)
|
||||||
|
{
|
||||||
|
return context->ParticipantCreated(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_PARTICIPANT_REMOVED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 12)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->ParticipantRemoved)
|
||||||
|
{
|
||||||
|
return context->ParticipantRemoved(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 6)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
|
||||||
|
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->ChangeParticipantControlLevel)
|
||||||
|
{
|
||||||
|
return context->ChangeParticipantControlLevel(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_send_change_participant_control_level_pdu(EncomspClientContext* context, ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu)
|
||||||
|
{
|
||||||
|
wStream* s;
|
||||||
|
encomspPlugin* encomsp;
|
||||||
|
|
||||||
|
encomsp = (encomspPlugin*) context->handle;
|
||||||
|
|
||||||
|
pdu->Type = ODTYPE_PARTICIPANT_CTRL_CHANGED;
|
||||||
|
pdu->Length = ENCOMSP_ORDER_HEADER_SIZE + 6;
|
||||||
|
|
||||||
|
s = Stream_New(NULL, pdu->Length);
|
||||||
|
|
||||||
|
encomsp_write_header(s, (ENCOMSP_ORDER_HEADER*) pdu);
|
||||||
|
|
||||||
|
Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */
|
||||||
|
Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
|
||||||
|
encomsp_virtual_channel_write(encomsp, s);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->GraphicsStreamPaused)
|
||||||
|
{
|
||||||
|
return context->GraphicsStreamPaused(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header)
|
||||||
|
{
|
||||||
|
int beg, end;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU pdu;
|
||||||
|
|
||||||
|
context = encomsp_get_client_interface(encomsp);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
|
||||||
|
|
||||||
|
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
|
||||||
|
|
||||||
|
end = (int) Stream_GetPosition(s);
|
||||||
|
|
||||||
|
if ((beg + header->Length) < end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((beg + header->Length) > end)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < (size_t) ((beg + header->Length) - end))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_SetPosition(s, (beg + header->Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->GraphicsStreamResumed)
|
||||||
|
{
|
||||||
|
return context->GraphicsStreamResumed(context, &pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encomsp_process_receive(encomspPlugin* encomsp, wStream* s)
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
ENCOMSP_ORDER_HEADER header;
|
||||||
|
|
||||||
|
while (Stream_GetRemainingLength(s) > 0)
|
||||||
|
{
|
||||||
|
if (encomsp_read_header(s, &header) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
//WLog_DBG(TAG, "EncomspReceive: Type: %d Length: %d", header.Type, header.Length);
|
||||||
|
|
||||||
|
switch (header.Type)
|
||||||
|
{
|
||||||
|
case ODTYPE_FILTER_STATE_UPDATED:
|
||||||
|
status = encomsp_recv_filter_updated_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_APP_REMOVED:
|
||||||
|
status = encomsp_recv_application_removed_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_APP_CREATED:
|
||||||
|
status = encomsp_recv_application_created_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_WND_REMOVED:
|
||||||
|
status = encomsp_recv_window_removed_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_WND_CREATED:
|
||||||
|
status = encomsp_recv_window_created_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_WND_SHOW:
|
||||||
|
status = encomsp_recv_show_window_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_PARTICIPANT_REMOVED:
|
||||||
|
status = encomsp_recv_participant_removed_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_PARTICIPANT_CREATED:
|
||||||
|
status = encomsp_recv_participant_created_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_PARTICIPANT_CTRL_CHANGED:
|
||||||
|
status = encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_GRAPHICS_STREAM_PAUSED:
|
||||||
|
status = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ODTYPE_GRAPHICS_STREAM_RESUMED:
|
||||||
|
status = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encomsp_process_connect(encomspPlugin* encomsp)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
static wListDictionary* g_InitHandles;
|
||||||
|
static wListDictionary* g_OpenHandles;
|
||||||
|
|
||||||
|
void encomsp_add_init_handle_data(void* pInitHandle, void* pUserData)
|
||||||
|
{
|
||||||
|
if (!g_InitHandles)
|
||||||
|
g_InitHandles = ListDictionary_New(TRUE);
|
||||||
|
|
||||||
|
ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* encomsp_get_init_handle_data(void* pInitHandle)
|
||||||
|
{
|
||||||
|
void* pUserData = NULL;
|
||||||
|
pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
|
||||||
|
return pUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void encomsp_remove_init_handle_data(void* pInitHandle)
|
||||||
|
{
|
||||||
|
ListDictionary_Remove(g_InitHandles, pInitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void encomsp_add_open_handle_data(DWORD openHandle, void* pUserData)
|
||||||
|
{
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
|
||||||
|
if (!g_OpenHandles)
|
||||||
|
g_OpenHandles = ListDictionary_New(TRUE);
|
||||||
|
|
||||||
|
ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* encomsp_get_open_handle_data(DWORD openHandle)
|
||||||
|
{
|
||||||
|
void* pUserData = NULL;
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
|
||||||
|
return pUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void encomsp_remove_open_handle_data(DWORD openHandle)
|
||||||
|
{
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
ListDictionary_Remove(g_OpenHandles, pOpenHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int encomsp_send(encomspPlugin* encomsp, wStream* s)
|
||||||
|
{
|
||||||
|
UINT32 status = 0;
|
||||||
|
encomspPlugin* plugin = (encomspPlugin*) encomsp;
|
||||||
|
|
||||||
|
if (!plugin)
|
||||||
|
{
|
||||||
|
status = CHANNEL_RC_BAD_INIT_HANDLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle,
|
||||||
|
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
Stream_Free(s, TRUE);
|
||||||
|
WLog_ERR(TAG, "encomsp_send: VirtualChannelWrite failed %d", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp,
|
||||||
|
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
|
||||||
|
{
|
||||||
|
wStream* data_in;
|
||||||
|
|
||||||
|
if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataFlags & CHANNEL_FLAG_FIRST)
|
||||||
|
{
|
||||||
|
if (encomsp->data_in)
|
||||||
|
Stream_Free(encomsp->data_in, TRUE);
|
||||||
|
|
||||||
|
encomsp->data_in = Stream_New(NULL, totalLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_in = encomsp->data_in;
|
||||||
|
Stream_EnsureRemainingCapacity(data_in, (int) dataLength);
|
||||||
|
Stream_Write(data_in, pData, dataLength);
|
||||||
|
|
||||||
|
if (dataFlags & CHANNEL_FLAG_LAST)
|
||||||
|
{
|
||||||
|
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "encomsp_plugin_process_received: read error");
|
||||||
|
}
|
||||||
|
|
||||||
|
encomsp->data_in = NULL;
|
||||||
|
Stream_SealLength(data_in);
|
||||||
|
Stream_SetPosition(data_in, 0);
|
||||||
|
|
||||||
|
MessageQueue_Post(encomsp->queue, NULL, 0, (void*) data_in, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID VCAPITYPE encomsp_virtual_channel_open_event(DWORD openHandle, UINT event,
|
||||||
|
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
|
||||||
|
{
|
||||||
|
encomspPlugin* encomsp;
|
||||||
|
|
||||||
|
encomsp = (encomspPlugin*) encomsp_get_open_handle_data(openHandle);
|
||||||
|
|
||||||
|
if (!encomsp)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "encomsp_virtual_channel_open_event: error no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case CHANNEL_EVENT_DATA_RECEIVED:
|
||||||
|
encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength, totalLength, dataFlags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_WRITE_COMPLETE:
|
||||||
|
Stream_Free((wStream*) pData, TRUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* encomsp_virtual_channel_client_thread(void* arg)
|
||||||
|
{
|
||||||
|
wStream* data;
|
||||||
|
wMessage message;
|
||||||
|
encomspPlugin* encomsp = (encomspPlugin*) arg;
|
||||||
|
|
||||||
|
encomsp_process_connect(encomsp);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!MessageQueue_Wait(encomsp->queue))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (MessageQueue_Peek(encomsp->queue, &message, TRUE))
|
||||||
|
{
|
||||||
|
if (message.id == WMQ_QUIT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (message.id == 0)
|
||||||
|
{
|
||||||
|
data = (wStream*) message.wParam;
|
||||||
|
encomsp_process_receive(encomsp, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitThread(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, LPVOID pData, UINT32 dataLength)
|
||||||
|
{
|
||||||
|
UINT32 status;
|
||||||
|
|
||||||
|
status = encomsp->channelEntryPoints.pVirtualChannelOpen(encomsp->InitHandle,
|
||||||
|
&encomsp->OpenHandle, encomsp->channelDef.name, encomsp_virtual_channel_open_event);
|
||||||
|
|
||||||
|
encomsp_add_open_handle_data(encomsp->OpenHandle, encomsp);
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "encomsp_virtual_channel_event_connected: open failed: status: %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
encomsp->queue = MessageQueue_New(NULL);
|
||||||
|
|
||||||
|
encomsp->thread = CreateThread(NULL, 0,
|
||||||
|
(LPTHREAD_START_ROUTINE) encomsp_virtual_channel_client_thread, (void*) encomsp, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp)
|
||||||
|
{
|
||||||
|
if (encomsp->queue)
|
||||||
|
{
|
||||||
|
MessageQueue_PostQuit(encomsp->queue, 0);
|
||||||
|
WaitForSingleObject(encomsp->thread, INFINITE);
|
||||||
|
|
||||||
|
MessageQueue_Free(encomsp->queue);
|
||||||
|
encomsp->queue = NULL;
|
||||||
|
|
||||||
|
CloseHandle(encomsp->thread);
|
||||||
|
encomsp->thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
encomsp->channelEntryPoints.pVirtualChannelClose(encomsp->OpenHandle);
|
||||||
|
|
||||||
|
if (encomsp->data_in)
|
||||||
|
{
|
||||||
|
Stream_Free(encomsp->data_in, TRUE);
|
||||||
|
encomsp->data_in = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
encomsp_remove_open_handle_data(encomsp->OpenHandle);
|
||||||
|
encomsp_remove_init_handle_data(encomsp->InitHandle);
|
||||||
|
|
||||||
|
free(encomsp->context);
|
||||||
|
|
||||||
|
free(encomsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID VCAPITYPE encomsp_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
|
||||||
|
{
|
||||||
|
encomspPlugin* encomsp;
|
||||||
|
|
||||||
|
encomsp = (encomspPlugin*) encomsp_get_init_handle_data(pInitHandle);
|
||||||
|
|
||||||
|
if (!encomsp)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "encomsp_virtual_channel_init_event: error no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case CHANNEL_EVENT_CONNECTED:
|
||||||
|
encomsp_virtual_channel_event_connected(encomsp, pData, dataLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_DISCONNECTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_TERMINATED:
|
||||||
|
encomsp_virtual_channel_event_terminated(encomsp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encomsp is always built-in */
|
||||||
|
#define VirtualChannelEntry encomsp_VirtualChannelEntry
|
||||||
|
|
||||||
|
BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||||
|
{
|
||||||
|
encomspPlugin* encomsp;
|
||||||
|
EncomspClientContext* context;
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
|
||||||
|
|
||||||
|
encomsp = (encomspPlugin*) calloc(1, sizeof(encomspPlugin));
|
||||||
|
|
||||||
|
encomsp->channelDef.options =
|
||||||
|
CHANNEL_OPTION_INITIALIZED |
|
||||||
|
CHANNEL_OPTION_ENCRYPT_RDP |
|
||||||
|
CHANNEL_OPTION_COMPRESS_RDP |
|
||||||
|
CHANNEL_OPTION_SHOW_PROTOCOL;
|
||||||
|
|
||||||
|
strcpy(encomsp->channelDef.name, "encomsp");
|
||||||
|
|
||||||
|
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
|
||||||
|
|
||||||
|
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
|
||||||
|
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
||||||
|
{
|
||||||
|
context = (EncomspClientContext*) calloc(1, sizeof(EncomspClientContext));
|
||||||
|
|
||||||
|
context->handle = (void*) encomsp;
|
||||||
|
|
||||||
|
context->FilterUpdated = NULL;
|
||||||
|
context->ApplicationCreated = NULL;
|
||||||
|
context->ApplicationRemoved = NULL;
|
||||||
|
context->WindowCreated = NULL;
|
||||||
|
context->WindowRemoved = NULL;
|
||||||
|
context->ShowWindow = NULL;
|
||||||
|
context->ParticipantCreated = NULL;
|
||||||
|
context->ParticipantRemoved = NULL;
|
||||||
|
context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu;
|
||||||
|
context->GraphicsStreamPaused = NULL;
|
||||||
|
context->GraphicsStreamResumed = NULL;
|
||||||
|
|
||||||
|
*(pEntryPointsEx->ppInterface) = (void*) context;
|
||||||
|
encomsp->context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
|
||||||
|
|
||||||
|
encomsp->channelEntryPoints.pVirtualChannelInit(&encomsp->InitHandle,
|
||||||
|
&encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, encomsp_virtual_channel_init_event);
|
||||||
|
|
||||||
|
encomsp->channelEntryPoints.pInterface = *(encomsp->channelEntryPoints.ppInterface);
|
||||||
|
encomsp->channelEntryPoints.ppInterface = &(encomsp->channelEntryPoints.pInterface);
|
||||||
|
|
||||||
|
encomsp_add_init_handle_data(encomsp->InitHandle, (void*) encomsp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Multiparty Virtual Channel
|
||||||
|
*
|
||||||
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H
|
||||||
|
#define FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H
|
||||||
|
|
||||||
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/synch.h>
|
||||||
|
#include <winpr/thread.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
#include <winpr/collections.h>
|
||||||
|
|
||||||
|
#include <freerdp/api.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
#include <freerdp/svc.h>
|
||||||
|
#include <freerdp/addin.h>
|
||||||
|
|
||||||
|
#include <freerdp/client/encomsp.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("encomsp.client")
|
||||||
|
|
||||||
|
struct encomsp_plugin
|
||||||
|
{
|
||||||
|
CHANNEL_DEF channelDef;
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
|
||||||
|
|
||||||
|
EncomspClientContext* context;
|
||||||
|
|
||||||
|
HANDLE thread;
|
||||||
|
wStream* data_in;
|
||||||
|
void* InitHandle;
|
||||||
|
DWORD OpenHandle;
|
||||||
|
wMessageQueue* queue;
|
||||||
|
};
|
||||||
|
typedef struct encomsp_plugin encomspPlugin;
|
||||||
|
|
||||||
|
#endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */
|
|
@ -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(${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")
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 */
|
|
@ -22,19 +22,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
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_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-interlocked)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp winpr)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,12 @@
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/synch.h>
|
#include <winpr/synch.h>
|
||||||
#include <winpr/thread.h>
|
#include <winpr/thread.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
#include <winpr/collections.h>
|
#include <winpr/collections.h>
|
||||||
#include <winpr/interlocked.h>
|
#include <winpr/interlocked.h>
|
||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <winpr/stream.h>
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
|
|
||||||
struct _PARALLEL_DEVICE
|
struct _PARALLEL_DEVICE
|
||||||
|
@ -93,16 +92,14 @@ static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
{
|
{
|
||||||
irp->IoStatus = STATUS_ACCESS_DENIED;
|
irp->IoStatus = STATUS_ACCESS_DENIED;
|
||||||
parallel->id = 0;
|
parallel->id = 0;
|
||||||
|
|
||||||
DEBUG_WARN("failed to create %s: %s", parallel->path, strerror(errno));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* all read and write operations should be non-blocking */
|
/* all read and write operations should be non-blocking */
|
||||||
if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
|
if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
|
||||||
DEBUG_WARN("%s fcntl %s", path, strerror(errno));
|
{
|
||||||
|
|
||||||
DEBUG_SVC("%s(%d) created", parallel->path, parallel->file);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, parallel->id);
|
Stream_Write_UINT32(irp->output, parallel->id);
|
||||||
|
@ -116,9 +113,13 @@ static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
static void parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
|
static void parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
{
|
{
|
||||||
if (close(parallel->file) < 0)
|
if (close(parallel->file) < 0)
|
||||||
DEBUG_SVC("failed to close %s(%d)", parallel->path, parallel->id);
|
{
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
DEBUG_SVC("%s(%d) closed", parallel->path, parallel->id);
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Stream_Zero(irp->output, 5); /* Padding(5) */
|
Stream_Zero(irp->output, 5); /* Padding(5) */
|
||||||
|
|
||||||
|
@ -145,12 +146,10 @@ static void parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
Length = 0;
|
Length = 0;
|
||||||
|
|
||||||
DEBUG_WARN("read %s(%d) failed", parallel->path, parallel->id);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, parallel->id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length);
|
Stream_Write_UINT32(irp->output, Length);
|
||||||
|
@ -177,8 +176,6 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
Stream_Read_UINT64(irp->input, Offset);
|
Stream_Read_UINT64(irp->input, Offset);
|
||||||
Stream_Seek(irp->input, 20); /* Padding */
|
Stream_Seek(irp->input, 20); /* Padding */
|
||||||
|
|
||||||
DEBUG_SVC("Length %u Offset %llu", Length, Offset);
|
|
||||||
|
|
||||||
len = Length;
|
len = Length;
|
||||||
|
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
|
@ -189,8 +186,6 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
{
|
{
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||||
Length = 0;
|
Length = 0;
|
||||||
|
|
||||||
DEBUG_WARN("write %s(%d) failed.", parallel->path, parallel->id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,15 +201,12 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
|
|
||||||
static void parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
|
static void parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
{
|
{
|
||||||
DEBUG_SVC("in");
|
|
||||||
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
|
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
|
||||||
irp->Complete(irp);
|
irp->Complete(irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
{
|
{
|
||||||
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
|
|
||||||
|
|
||||||
switch (irp->MajorFunction)
|
switch (irp->MajorFunction)
|
||||||
{
|
{
|
||||||
case IRP_MJ_CREATE:
|
case IRP_MJ_CREATE:
|
||||||
|
@ -238,7 +230,6 @@ static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
|
|
||||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||||
irp->Complete(irp);
|
irp->Complete(irp);
|
||||||
break;
|
break;
|
||||||
|
@ -281,8 +272,6 @@ static void parallel_free(DEVICE* device)
|
||||||
{
|
{
|
||||||
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
|
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
|
||||||
|
|
||||||
DEBUG_SVC("freeing device");
|
|
||||||
|
|
||||||
MessageQueue_PostQuit(parallel->queue, 0);
|
MessageQueue_PostQuit(parallel->queue, 0);
|
||||||
WaitForSingleObject(parallel->thread, INFINITE);
|
WaitForSingleObject(parallel->thread, INFINITE);
|
||||||
CloseHandle(parallel->thread);
|
CloseHandle(parallel->thread);
|
||||||
|
|
|
@ -38,17 +38,9 @@ endif()
|
||||||
|
|
||||||
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_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
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})
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
|
|
||||||
#include "printer_main.h"
|
#include "printer_main.h"
|
||||||
|
@ -87,15 +86,12 @@ static void printer_cups_write_printjob(rdpPrintJob* printjob, BYTE* data, int s
|
||||||
|
|
||||||
fp = fopen((const char*) cups_printjob->printjob_object, "a+b");
|
fp = fopen((const char*) cups_printjob->printjob_object, "a+b");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (!fp)
|
||||||
{
|
|
||||||
DEBUG_WARN("failed to open file %s", (char*) cups_printjob->printjob_object);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (fwrite(data, 1, size, fp) < size)
|
if (fwrite(data, 1, size, fp) < size)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("failed to write file %s", (char*) cups_printjob->printjob_object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
@ -121,7 +117,7 @@ static void printer_cups_close_printjob(rdpPrintJob* printjob)
|
||||||
|
|
||||||
if (cupsPrintFile(printjob->printer->name, (const char*) cups_printjob->printjob_object, buf, 0, NULL) == 0)
|
if (cupsPrintFile(printjob->printer->name, (const char*) cups_printjob->printjob_object, buf, 0, NULL) == 0)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("cupsPrintFile: %s", cupsLastErrorString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(cups_printjob->printjob_object);
|
unlink(cups_printjob->printjob_object);
|
||||||
|
@ -167,20 +163,19 @@ static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||||
|
|
||||||
cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
|
cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
|
||||||
|
|
||||||
if (cups_printjob->printjob_object == NULL)
|
if (!cups_printjob->printjob_object)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("httpConnectEncrypt: %s", cupsLastErrorString());
|
|
||||||
free(cups_printjob);
|
free(cups_printjob);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
printer_cups_get_printjob_name(buf, sizeof(buf));
|
printer_cups_get_printjob_name(buf, sizeof(buf));
|
||||||
|
|
||||||
cups_printjob->printjob_id = cupsCreateJob((http_t*) cups_printjob->printjob_object,
|
cups_printjob->printjob_id = cupsCreateJob((http_t*) cups_printjob->printjob_object,
|
||||||
printer->name, buf, 0, NULL);
|
printer->name, buf, 0, NULL);
|
||||||
|
|
||||||
if (cups_printjob->printjob_id == 0)
|
if (!cups_printjob->printjob_id)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("cupsCreateJob: %s", cupsLastErrorString());
|
|
||||||
httpClose((http_t*) cups_printjob->printjob_object);
|
httpClose((http_t*) cups_printjob->printjob_object);
|
||||||
free(cups_printjob);
|
free(cups_printjob);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -281,19 +276,15 @@ rdpPrinterDriver* printer_cups_get_driver(void)
|
||||||
{
|
{
|
||||||
if (cups_driver == NULL)
|
if (cups_driver == NULL)
|
||||||
{
|
{
|
||||||
cups_driver = (rdpCupsPrinterDriver*) malloc(sizeof(rdpCupsPrinterDriver));
|
cups_driver = (rdpCupsPrinterDriver*) calloc(1, sizeof(rdpCupsPrinterDriver));
|
||||||
ZeroMemory(cups_driver, sizeof(rdpCupsPrinterDriver));
|
|
||||||
|
if (!cups_driver)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
|
cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
|
||||||
cups_driver->driver.GetPrinter = printer_cups_get_printer;
|
cups_driver->driver.GetPrinter = printer_cups_get_printer;
|
||||||
|
|
||||||
cups_driver->id_sequence = 1;
|
cups_driver->id_sequence = 1;
|
||||||
|
|
||||||
#ifdef _CUPS_API_1_4
|
|
||||||
DEBUG_SVC("using CUPS API 1.4");
|
|
||||||
#else
|
|
||||||
DEBUG_SVC("using CUPS API 1.2");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (rdpPrinterDriver*) cups_driver;
|
return (rdpPrinterDriver*) cups_driver;
|
||||||
|
|
|
@ -28,11 +28,10 @@
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/synch.h>
|
#include <winpr/synch.h>
|
||||||
#include <winpr/thread.h>
|
#include <winpr/thread.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
#include <winpr/interlocked.h>
|
#include <winpr/interlocked.h>
|
||||||
|
|
||||||
#include <winpr/stream.h>
|
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
|
|
||||||
#ifdef WITH_CUPS
|
#ifdef WITH_CUPS
|
||||||
#include "printer_cups.h"
|
#include "printer_cups.h"
|
||||||
|
@ -69,15 +68,11 @@ static void printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||||
if (printjob)
|
if (printjob)
|
||||||
{
|
{
|
||||||
Stream_Write_UINT32(irp->output, printjob->id); /* FileId */
|
Stream_Write_UINT32(irp->output, printjob->id); /* FileId */
|
||||||
|
|
||||||
DEBUG_SVC("printjob id: %d", printjob->id);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Stream_Write_UINT32(irp->output, 0); /* FileId */
|
Stream_Write_UINT32(irp->output, 0); /* FileId */
|
||||||
irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
|
irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
|
||||||
|
|
||||||
DEBUG_WARN("error creating print job.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irp->Complete(irp);
|
irp->Complete(irp);
|
||||||
|
@ -87,20 +82,16 @@ static void printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||||
{
|
{
|
||||||
rdpPrintJob* printjob = NULL;
|
rdpPrintJob* printjob = NULL;
|
||||||
|
|
||||||
if (printer_dev->printer != NULL)
|
if (printer_dev->printer)
|
||||||
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
|
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
|
||||||
|
|
||||||
if (!printjob)
|
if (!printjob)
|
||||||
{
|
{
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
DEBUG_WARN("printjob id %d not found.", irp->FileId);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printjob->Close(printjob);
|
printjob->Close(printjob);
|
||||||
|
|
||||||
DEBUG_SVC("printjob id %d closed.", irp->FileId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Zero(irp->output, 4); /* Padding(4) */
|
Stream_Zero(irp->output, 4); /* Padding(4) */
|
||||||
|
@ -125,14 +116,10 @@ static void printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||||
{
|
{
|
||||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||||
Length = 0;
|
Length = 0;
|
||||||
|
|
||||||
DEBUG_WARN("printjob id %d not found.", irp->FileId);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printjob->Write(printjob, Stream_Pointer(irp->input), Length);
|
printjob->Write(printjob, Stream_Pointer(irp->input), Length);
|
||||||
|
|
||||||
DEBUG_SVC("printjob id %d written %d bytes.", irp->FileId, Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Write_UINT32(irp->output, Length);
|
Stream_Write_UINT32(irp->output, Length);
|
||||||
|
@ -168,7 +155,6 @@ static void printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
|
|
||||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||||
irp->Complete(irp);
|
irp->Complete(irp);
|
||||||
break;
|
break;
|
||||||
|
@ -267,8 +253,6 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri
|
||||||
CachedFieldsLen = 0;
|
CachedFieldsLen = 0;
|
||||||
CachedPrinterConfigData = NULL;
|
CachedPrinterConfigData = NULL;
|
||||||
|
|
||||||
DEBUG_SVC("Printer %s registered", printer->name);
|
|
||||||
|
|
||||||
Flags = 0;
|
Flags = 0;
|
||||||
|
|
||||||
if (printer->is_default)
|
if (printer->is_default)
|
||||||
|
@ -332,9 +316,8 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||||
driver = printer_win_get_driver();
|
driver = printer_win_get_driver();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (driver == NULL)
|
if (!driver)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("no driver");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,10 +330,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||||
printer = driver->GetPrinter(driver, name);
|
printer = driver->GetPrinter(driver, name);
|
||||||
|
|
||||||
if (!printer)
|
if (!printer)
|
||||||
{
|
|
||||||
DEBUG_WARN("printer %s not found.", name);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (driver_name && driver_name[0])
|
if (driver_name && driver_name[0])
|
||||||
printer->driver = driver_name;
|
printer->driver = driver_name;
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <winspool.h>
|
#include <winspool.h>
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
|
|
||||||
#include "printer_main.h"
|
#include "printer_main.h"
|
||||||
|
|
||||||
#include "printer_win.h"
|
#include "printer_win.h"
|
||||||
|
@ -69,45 +67,44 @@ static void printer_win_get_printjob_name(char* buf, int size)
|
||||||
time_t tt;
|
time_t tt;
|
||||||
struct tm* t;
|
struct tm* t;
|
||||||
|
|
||||||
DEBUG_WINPR("");
|
|
||||||
|
|
||||||
tt = time(NULL);
|
tt = time(NULL);
|
||||||
t = localtime(&tt);
|
t = localtime(&tt);
|
||||||
snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
|
snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
|
||||||
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||||
t->tm_hour, t->tm_min, t->tm_sec);
|
t->tm_hour, t->tm_min, t->tm_sec);
|
||||||
|
|
||||||
DEBUG_WINPR("buf: %s", buf);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
|
static void printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
|
||||||
{
|
{
|
||||||
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
|
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
|
||||||
|
|
||||||
LPVOID pBuf = data;
|
LPVOID pBuf = data;
|
||||||
DWORD cbBuf = size;
|
DWORD cbBuf = size;
|
||||||
DWORD pcWritten;
|
DWORD pcWritten;
|
||||||
|
|
||||||
if( ! WritePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten ) )
|
if(!WritePrinter(((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten))
|
||||||
DEBUG_WINPR("WritePrinter failed");
|
{
|
||||||
;
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printer_win_close_printjob(rdpPrintJob* printjob)
|
static void printer_win_close_printjob(rdpPrintJob* printjob)
|
||||||
{
|
{
|
||||||
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
|
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
|
||||||
|
|
||||||
DEBUG_WINPR("");
|
if (!EndPagePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
|
||||||
|
{
|
||||||
|
|
||||||
if ( ! EndPagePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
|
}
|
||||||
DEBUG_WINPR("EndPagePrinter failed");;
|
|
||||||
if ( ! ClosePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
|
|
||||||
DEBUG_WINPR("ClosePrinter failed");;
|
|
||||||
|
|
||||||
((rdpWinPrinter*)printjob->printer)->printjob = NULL;
|
if (!ClosePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
|
||||||
free(win_printjob) ;
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
((rdpWinPrinter*) printjob->printer)->printjob = NULL;
|
||||||
|
|
||||||
|
free(win_printjob);
|
||||||
}
|
}
|
||||||
|
|
||||||
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||||
|
@ -115,13 +112,10 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||||
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
|
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
|
||||||
rdpWinPrintJob* win_printjob;
|
rdpWinPrintJob* win_printjob;
|
||||||
|
|
||||||
DEBUG_WINPR("");
|
|
||||||
|
|
||||||
if (win_printer->printjob != NULL)
|
if (win_printer->printjob != NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
win_printjob = (rdpWinPrintJob*) malloc(sizeof(rdpWinPrintJob));
|
win_printjob = (rdpWinPrintJob*) calloc(1, sizeof(rdpWinPrintJob));
|
||||||
ZeroMemory(win_printjob, sizeof(rdpWinPrintJob));
|
|
||||||
|
|
||||||
win_printjob->printjob.id = id;
|
win_printjob->printjob.id = id;
|
||||||
win_printjob->printjob.printer = printer;
|
win_printjob->printjob.printer = printer;
|
||||||
|
@ -132,10 +126,14 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||||
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) &(win_printjob->di));
|
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) &(win_printjob->di));
|
||||||
|
|
||||||
if (!win_printjob->handle)
|
if (!win_printjob->handle)
|
||||||
DEBUG_WINPR("StartDocPrinter failed");
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!StartPagePrinter(win_printer->hPrinter))
|
if (!StartPagePrinter(win_printer->hPrinter))
|
||||||
DEBUG_WINPR("ClosePrinter failed");
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
win_printjob->printjob.Write = printer_win_write_printjob;
|
win_printjob->printjob.Write = printer_win_write_printjob;
|
||||||
win_printjob->printjob.Close = printer_win_close_printjob;
|
win_printjob->printjob.Close = printer_win_close_printjob;
|
||||||
|
@ -149,9 +147,7 @@ static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
|
||||||
{
|
{
|
||||||
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
|
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
|
||||||
|
|
||||||
DEBUG_WINPR("");
|
if (!win_printer->printjob)
|
||||||
|
|
||||||
if (win_printer->printjob == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (win_printer->printjob->printjob.id != id)
|
if (win_printer->printjob->printjob.id != id)
|
||||||
|
@ -164,8 +160,6 @@ static void printer_win_free_printer(rdpPrinter* printer)
|
||||||
{
|
{
|
||||||
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
|
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
|
||||||
|
|
||||||
DEBUG_WINPR("");
|
|
||||||
|
|
||||||
if (win_printer->printjob)
|
if (win_printer->printjob)
|
||||||
win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob);
|
win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob);
|
||||||
|
|
||||||
|
@ -180,10 +174,8 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons
|
||||||
DWORD needed;
|
DWORD needed;
|
||||||
PRINTER_INFO_2 *prninfo=NULL;
|
PRINTER_INFO_2 *prninfo=NULL;
|
||||||
size_t charsConverted;
|
size_t charsConverted;
|
||||||
DEBUG_WINPR("");
|
|
||||||
|
|
||||||
win_printer = (rdpWinPrinter*) malloc(sizeof(rdpWinPrinter));
|
win_printer = (rdpWinPrinter*) calloc(1, sizeof(rdpWinPrinter));
|
||||||
ZeroMemory(win_printer, sizeof(rdpWinPrinter));
|
|
||||||
|
|
||||||
win_printer->printer.id = win_driver->id_sequence++;
|
win_printer->printer.id = win_driver->id_sequence++;
|
||||||
win_printer->printer.name = _strdup(name);
|
win_printer->printer.name = _strdup(name);
|
||||||
|
@ -195,7 +187,6 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons
|
||||||
|
|
||||||
swprintf(wname, 256, L"%hs", name);
|
swprintf(wname, 256, L"%hs", name);
|
||||||
OpenPrinter(wname, &(win_printer->hPrinter), NULL);
|
OpenPrinter(wname, &(win_printer->hPrinter), NULL);
|
||||||
DEBUG_WINPR("handle: 0x%08X", win_printer->hPrinter);
|
|
||||||
|
|
||||||
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
|
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
|
||||||
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
|
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
|
||||||
|
@ -216,8 +207,6 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
|
||||||
size_t charsConverted;
|
size_t charsConverted;
|
||||||
PRINTER_INFO_2* prninfo = NULL;
|
PRINTER_INFO_2* prninfo = NULL;
|
||||||
DWORD needed, returned;
|
DWORD needed, returned;
|
||||||
|
|
||||||
DEBUG_WINPR("");
|
|
||||||
|
|
||||||
/* find required size for the buffer */
|
/* find required size for the buffer */
|
||||||
EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
|
EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
|
||||||
|
@ -227,19 +216,16 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
|
||||||
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
|
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
|
||||||
|
|
||||||
/* call again */
|
/* call again */
|
||||||
if ( !EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned) )
|
if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned))
|
||||||
{
|
{
|
||||||
DEBUG_WINPR("EnumPrinters failed");
|
|
||||||
} ; /* ERROR... */
|
|
||||||
|
|
||||||
DEBUG_WINPR("printers found: %d", returned);
|
}
|
||||||
|
|
||||||
printers = (rdpPrinter**) malloc(sizeof(rdpPrinter*) * (returned + 1));
|
printers = (rdpPrinter**) calloc((returned + 1), sizeof(rdpPrinter*));
|
||||||
ZeroMemory(printers, sizeof(rdpPrinter*) * (returned + 1));
|
|
||||||
|
|
||||||
num_printers = 0;
|
num_printers = 0;
|
||||||
|
|
||||||
for (i = 0; i < (int)returned; i++)
|
for (i = 0; i < (int) returned; i++)
|
||||||
{
|
{
|
||||||
wcstombs_s(&charsConverted, pname, 1000, prninfo[i].pPrinterName, _TRUNCATE);
|
wcstombs_s(&charsConverted, pname, 1000, prninfo[i].pPrinterName, _TRUNCATE);
|
||||||
printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
|
printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
|
||||||
|
@ -254,8 +240,6 @@ static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char*
|
||||||
{
|
{
|
||||||
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
|
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
|
||||||
rdpPrinter *myPrinter = NULL;
|
rdpPrinter *myPrinter = NULL;
|
||||||
|
|
||||||
DEBUG_WINPR("printer %s", name);
|
|
||||||
|
|
||||||
myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? TRUE : FALSE);
|
myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? TRUE : FALSE);
|
||||||
|
|
||||||
|
@ -266,12 +250,9 @@ static rdpWinPrinterDriver* win_driver = NULL;
|
||||||
|
|
||||||
rdpPrinterDriver* printer_win_get_driver(void)
|
rdpPrinterDriver* printer_win_get_driver(void)
|
||||||
{
|
{
|
||||||
DEBUG_WINPR("");
|
if (!win_driver)
|
||||||
|
|
||||||
if (win_driver == NULL)
|
|
||||||
{
|
{
|
||||||
win_driver = (rdpWinPrinterDriver*) malloc(sizeof(rdpWinPrinterDriver));
|
win_driver = (rdpWinPrinterDriver*) calloc(1, sizeof(rdpWinPrinterDriver));
|
||||||
ZeroMemory(win_driver, sizeof(rdpWinPrinterDriver));
|
|
||||||
|
|
||||||
win_driver->driver.EnumPrinters = printer_win_enum_printers;
|
win_driver->driver.EnumPrinters = printer_win_enum_printers;
|
||||||
win_driver->driver.GetPrinter = printer_win_get_printer;
|
win_driver->driver.GetPrinter = printer_win_get_printer;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
|
|
@ -23,238 +23,52 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
#include <freerdp/utils/rail.h>
|
|
||||||
#include <freerdp/rail.h>
|
|
||||||
|
|
||||||
#include "rail_orders.h"
|
#include "rail_orders.h"
|
||||||
#include "rail_main.h"
|
#include "rail_main.h"
|
||||||
|
|
||||||
RailClientContext* rail_get_client_interface(void* railObject)
|
RailClientContext* rail_get_client_interface(railPlugin* rail)
|
||||||
{
|
{
|
||||||
RailClientContext* pInterface;
|
RailClientContext* pInterface;
|
||||||
rdpSvcPlugin* plugin = (rdpSvcPlugin*) railObject;
|
pInterface = (RailClientContext*) rail->channelEntryPoints.pInterface;
|
||||||
pInterface = (RailClientContext*) plugin->channel_entry_points.pInterface;
|
|
||||||
return pInterface;
|
return pInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rail_send_channel_data(void* railObject, void* data, size_t length)
|
int rail_send(railPlugin* rail, wStream* s)
|
||||||
|
{
|
||||||
|
UINT32 status = 0;
|
||||||
|
|
||||||
|
if (!rail)
|
||||||
|
{
|
||||||
|
status = CHANNEL_RC_BAD_INIT_HANDLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = rail->channelEntryPoints.pVirtualChannelWrite(rail->OpenHandle,
|
||||||
|
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
Stream_Free(s, TRUE);
|
||||||
|
WLog_ERR(TAG, "rail_send: VirtualChannelWrite failed %d", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rail_send_channel_data(railPlugin* rail, void* data, size_t length)
|
||||||
{
|
{
|
||||||
wStream* s = NULL;
|
wStream* s = NULL;
|
||||||
railPlugin* plugin = (railPlugin*) railObject;
|
|
||||||
|
|
||||||
s = Stream_New(NULL, length);
|
s = Stream_New(NULL, length);
|
||||||
Stream_Write(s, data, length);
|
Stream_Write(s, data, length);
|
||||||
|
|
||||||
svc_plugin_send((rdpSvcPlugin*) plugin, s);
|
rail_send(rail, s);
|
||||||
}
|
|
||||||
|
|
||||||
static void on_free_rail_channel_event(wMessage* event)
|
|
||||||
{
|
|
||||||
rail_free_cloned_order(GetMessageType(event->id), event->wParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rail_send_channel_event(void* railObject, UINT16 eventType, void* param)
|
|
||||||
{
|
|
||||||
void* payload = NULL;
|
|
||||||
wMessage* out_event = NULL;
|
|
||||||
railPlugin* plugin = (railPlugin*) railObject;
|
|
||||||
|
|
||||||
payload = rail_clone_order(eventType, param);
|
|
||||||
|
|
||||||
if (payload)
|
|
||||||
{
|
|
||||||
out_event = freerdp_event_new(RailChannel_Class, eventType,
|
|
||||||
on_free_rail_channel_event, payload);
|
|
||||||
|
|
||||||
svc_plugin_send_event((rdpSvcPlugin*) plugin, out_event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_process_connect(rdpSvcPlugin* plugin)
|
|
||||||
{
|
|
||||||
railPlugin* rail = (railPlugin*) plugin;
|
|
||||||
|
|
||||||
rail->rail_order = rail_order_new();
|
|
||||||
rail->rail_order->settings = (rdpSettings*) plugin->channel_entry_points.pExtendedData;
|
|
||||||
rail->rail_order->plugin = rail;
|
|
||||||
|
|
||||||
WLog_Print(rail->log, WLOG_DEBUG, "Connect");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_process_terminate(rdpSvcPlugin* plugin)
|
|
||||||
{
|
|
||||||
railPlugin* rail = (railPlugin*) plugin;
|
|
||||||
|
|
||||||
WLog_Print(rail->log, WLOG_DEBUG, "Terminate");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
|
||||||
{
|
|
||||||
railPlugin* rail = (railPlugin*) plugin;
|
|
||||||
rail_order_recv(rail, s);
|
|
||||||
Stream_Free(s, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_process_addin_args(rdpRailOrder* railOrder, rdpSettings* settings)
|
|
||||||
{
|
|
||||||
char* exeOrFile;
|
|
||||||
|
|
||||||
exeOrFile = settings->RemoteApplicationProgram;
|
|
||||||
|
|
||||||
if (strlen(exeOrFile) >= 2)
|
|
||||||
{
|
|
||||||
if (strncmp(exeOrFile, "||", 2) != 0)
|
|
||||||
railOrder->exec.flags |= RAIL_EXEC_FLAG_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
rail_string_to_unicode_string(settings->RemoteApplicationProgram, &railOrder->exec.exeOrFile);
|
|
||||||
rail_string_to_unicode_string(settings->ShellWorkingDirectory, &railOrder->exec.workingDir);
|
|
||||||
rail_string_to_unicode_string(settings->RemoteApplicationCmdLine, &railOrder->exec.arguments);
|
|
||||||
|
|
||||||
rail_send_client_exec_order((railPlugin*) railOrder->plugin, &railOrder->exec);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_set_sysparams_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_SYSPARAM_ORDER* sysparam;
|
|
||||||
|
|
||||||
/* Send System Parameters */
|
|
||||||
|
|
||||||
sysparam = (RAIL_SYSPARAM_ORDER*) event->wParam;
|
|
||||||
memmove(&railOrder->sysparam, sysparam, sizeof(RAIL_SYSPARAM_ORDER));
|
|
||||||
|
|
||||||
rail_send_client_sysparams_order((railPlugin*) railOrder->plugin, &railOrder->sysparam);
|
|
||||||
|
|
||||||
/* execute */
|
|
||||||
|
|
||||||
railOrder->exec.flags = RAIL_EXEC_FLAG_EXPAND_ARGUMENTS;
|
|
||||||
|
|
||||||
rail_process_addin_args(railOrder, railOrder->settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_exec_remote_app_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* TODO: replace event system by an API to allow the execution
|
|
||||||
* of multiple remote apps over the same connection. RAIL is
|
|
||||||
* always built-in, so clients can safely link to it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//rail_process_addin_args((railPlugin*) railOrder->plugin, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_activate_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_ACTIVATE_ORDER* activate = (RAIL_ACTIVATE_ORDER*) event->wParam;
|
|
||||||
|
|
||||||
CopyMemory(&railOrder->activate, activate, sizeof(RAIL_ACTIVATE_ORDER));
|
|
||||||
rail_send_client_activate_order((railPlugin*) railOrder->plugin, &railOrder->activate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_sysmenu_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_SYSMENU_ORDER* sysmenu = (RAIL_SYSMENU_ORDER*) event->wParam;
|
|
||||||
|
|
||||||
CopyMemory(&railOrder->sysmenu, sysmenu, sizeof(RAIL_SYSMENU_ORDER));
|
|
||||||
rail_send_client_sysmenu_order((railPlugin*) railOrder->plugin, &railOrder->sysmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_syscommand_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_SYSCOMMAND_ORDER* syscommand = (RAIL_SYSCOMMAND_ORDER*) event->wParam;
|
|
||||||
|
|
||||||
CopyMemory(&railOrder->syscommand, syscommand, sizeof(RAIL_SYSCOMMAND_ORDER));
|
|
||||||
rail_send_client_syscommand_order((railPlugin*) railOrder->plugin, &railOrder->syscommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_notify_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_NOTIFY_EVENT_ORDER* notify = (RAIL_NOTIFY_EVENT_ORDER*) event->wParam;
|
|
||||||
|
|
||||||
CopyMemory(&railOrder->notify_event, notify, sizeof(RAIL_NOTIFY_EVENT_ORDER));
|
|
||||||
rail_send_client_notify_event_order((railPlugin*) railOrder->plugin, &railOrder->notify_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_window_move_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_WINDOW_MOVE_ORDER* window_move = (RAIL_WINDOW_MOVE_ORDER*) event->wParam;
|
|
||||||
CopyMemory(&railOrder->window_move, window_move, sizeof(RAIL_WINDOW_MOVE_ORDER));
|
|
||||||
rail_send_client_window_move_order((railPlugin*) railOrder->plugin, &railOrder->window_move);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_app_req_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_GET_APPID_REQ_ORDER* get_appid_req = (RAIL_GET_APPID_REQ_ORDER*) event->wParam;
|
|
||||||
|
|
||||||
CopyMemory(&railOrder->get_appid_req, get_appid_req, sizeof(RAIL_GET_APPID_REQ_ORDER));
|
|
||||||
rail_send_client_get_appid_req_order((railPlugin*) railOrder->plugin, &railOrder->get_appid_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_recv_langbarinfo_event(rdpRailOrder* railOrder, wMessage* event)
|
|
||||||
{
|
|
||||||
RAIL_LANGBAR_INFO_ORDER* langbar_info = (RAIL_LANGBAR_INFO_ORDER*) event->wParam;
|
|
||||||
|
|
||||||
CopyMemory(&railOrder->langbar_info, langbar_info, sizeof(RAIL_LANGBAR_INFO_ORDER));
|
|
||||||
rail_send_client_langbar_info_order((railPlugin*) railOrder->plugin, &railOrder->langbar_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rail_process_event(rdpSvcPlugin* plugin, wMessage* event)
|
|
||||||
{
|
|
||||||
railPlugin* rail = NULL;
|
|
||||||
rail = (railPlugin*) plugin;
|
|
||||||
|
|
||||||
switch (GetMessageType(event->id))
|
|
||||||
{
|
|
||||||
case RailChannel_ClientSystemParam:
|
|
||||||
rail_recv_set_sysparams_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientExecute:
|
|
||||||
rail_recv_exec_remote_app_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientActivate:
|
|
||||||
rail_recv_activate_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientSystemMenu:
|
|
||||||
rail_recv_sysmenu_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientSystemCommand:
|
|
||||||
rail_recv_syscommand_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientNotifyEvent:
|
|
||||||
rail_recv_notify_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientWindowMove:
|
|
||||||
rail_recv_window_move_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientGetAppIdRequest:
|
|
||||||
rail_recv_app_req_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RailChannel_ClientLanguageBarInfo:
|
|
||||||
rail_recv_langbarinfo_event(rail->rail_order, event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
freerdp_event_free(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,9 +77,8 @@ static void rail_process_event(rdpSvcPlugin* plugin, wMessage* event)
|
||||||
|
|
||||||
int rail_client_execute(RailClientContext* context, RAIL_EXEC_ORDER* exec)
|
int rail_client_execute(RailClientContext* context, RAIL_EXEC_ORDER* exec)
|
||||||
{
|
{
|
||||||
railPlugin* rail = (railPlugin*) context->handle;
|
|
||||||
|
|
||||||
char* exeOrFile;
|
char* exeOrFile;
|
||||||
|
railPlugin* rail = (railPlugin*) context->handle;
|
||||||
|
|
||||||
exeOrFile = exec->RemoteApplicationProgram;
|
exeOrFile = exec->RemoteApplicationProgram;
|
||||||
|
|
||||||
|
@ -498,6 +311,223 @@ int rail_server_get_appid_response(RailClientContext* context, RAIL_GET_APPID_RE
|
||||||
return 0; /* stub - should be registered by client */
|
return 0; /* stub - should be registered by client */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
static wListDictionary* g_InitHandles;
|
||||||
|
static wListDictionary* g_OpenHandles;
|
||||||
|
|
||||||
|
void rail_add_init_handle_data(void* pInitHandle, void* pUserData)
|
||||||
|
{
|
||||||
|
if (!g_InitHandles)
|
||||||
|
g_InitHandles = ListDictionary_New(TRUE);
|
||||||
|
|
||||||
|
ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* rail_get_init_handle_data(void* pInitHandle)
|
||||||
|
{
|
||||||
|
void* pUserData = NULL;
|
||||||
|
pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
|
||||||
|
return pUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rail_remove_init_handle_data(void* pInitHandle)
|
||||||
|
{
|
||||||
|
ListDictionary_Remove(g_InitHandles, pInitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rail_add_open_handle_data(DWORD openHandle, void* pUserData)
|
||||||
|
{
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
|
||||||
|
if (!g_OpenHandles)
|
||||||
|
g_OpenHandles = ListDictionary_New(TRUE);
|
||||||
|
|
||||||
|
ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* rail_get_open_handle_data(DWORD openHandle)
|
||||||
|
{
|
||||||
|
void* pUserData = NULL;
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
|
||||||
|
return pUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rail_remove_open_handle_data(DWORD openHandle)
|
||||||
|
{
|
||||||
|
void* pOpenHandle = (void*) (size_t) openHandle;
|
||||||
|
ListDictionary_Remove(g_OpenHandles, pOpenHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rail_virtual_channel_event_data_received(railPlugin* rail,
|
||||||
|
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
|
||||||
|
{
|
||||||
|
wStream* data_in;
|
||||||
|
|
||||||
|
if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataFlags & CHANNEL_FLAG_FIRST)
|
||||||
|
{
|
||||||
|
if (rail->data_in)
|
||||||
|
Stream_Free(rail->data_in, TRUE);
|
||||||
|
|
||||||
|
rail->data_in = Stream_New(NULL, totalLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_in = rail->data_in;
|
||||||
|
Stream_EnsureRemainingCapacity(data_in, (int) dataLength);
|
||||||
|
Stream_Write(data_in, pData, dataLength);
|
||||||
|
|
||||||
|
if (dataFlags & CHANNEL_FLAG_LAST)
|
||||||
|
{
|
||||||
|
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "rail_plugin_process_received: read error");
|
||||||
|
}
|
||||||
|
|
||||||
|
rail->data_in = NULL;
|
||||||
|
Stream_SealLength(data_in);
|
||||||
|
Stream_SetPosition(data_in, 0);
|
||||||
|
|
||||||
|
MessageQueue_Post(rail->queue, NULL, 0, (void*) data_in, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID VCAPITYPE rail_virtual_channel_open_event(DWORD openHandle, UINT event,
|
||||||
|
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
|
||||||
|
{
|
||||||
|
railPlugin* rail;
|
||||||
|
|
||||||
|
rail = (railPlugin*) rail_get_open_handle_data(openHandle);
|
||||||
|
|
||||||
|
if (!rail)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "rail_virtual_channel_open_event: error no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case CHANNEL_EVENT_DATA_RECEIVED:
|
||||||
|
rail_virtual_channel_event_data_received(rail, pData, dataLength, totalLength, dataFlags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_WRITE_COMPLETE:
|
||||||
|
Stream_Free((wStream*) pData, TRUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* rail_virtual_channel_client_thread(void* arg)
|
||||||
|
{
|
||||||
|
wStream* data;
|
||||||
|
wMessage message;
|
||||||
|
railPlugin* rail = (railPlugin*) arg;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!MessageQueue_Wait(rail->queue))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (MessageQueue_Peek(rail->queue, &message, TRUE))
|
||||||
|
{
|
||||||
|
if (message.id == WMQ_QUIT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (message.id == 0)
|
||||||
|
{
|
||||||
|
data = (wStream*) message.wParam;
|
||||||
|
rail_order_recv(rail, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitThread(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength)
|
||||||
|
{
|
||||||
|
UINT32 status;
|
||||||
|
|
||||||
|
status = rail->channelEntryPoints.pVirtualChannelOpen(rail->InitHandle,
|
||||||
|
&rail->OpenHandle, rail->channelDef.name, rail_virtual_channel_open_event);
|
||||||
|
|
||||||
|
rail_add_open_handle_data(rail->OpenHandle, rail);
|
||||||
|
|
||||||
|
if (status != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "rail_virtual_channel_event_connected: open failed: status: %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rail->queue = MessageQueue_New(NULL);
|
||||||
|
|
||||||
|
rail->thread = CreateThread(NULL, 0,
|
||||||
|
(LPTHREAD_START_ROUTINE) rail_virtual_channel_client_thread, (void*) rail, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rail_virtual_channel_event_terminated(railPlugin* rail)
|
||||||
|
{
|
||||||
|
if (rail->queue)
|
||||||
|
{
|
||||||
|
MessageQueue_PostQuit(rail->queue, 0);
|
||||||
|
WaitForSingleObject(rail->thread, INFINITE);
|
||||||
|
|
||||||
|
MessageQueue_Free(rail->queue);
|
||||||
|
rail->queue = NULL;
|
||||||
|
|
||||||
|
CloseHandle(rail->thread);
|
||||||
|
rail->thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rail->channelEntryPoints.pVirtualChannelClose(rail->OpenHandle);
|
||||||
|
|
||||||
|
if (rail->data_in)
|
||||||
|
{
|
||||||
|
Stream_Free(rail->data_in, TRUE);
|
||||||
|
rail->data_in = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rail_remove_open_handle_data(rail->OpenHandle);
|
||||||
|
rail_remove_init_handle_data(rail->InitHandle);
|
||||||
|
|
||||||
|
free(rail->context);
|
||||||
|
|
||||||
|
free(rail);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID VCAPITYPE rail_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
|
||||||
|
{
|
||||||
|
railPlugin* rail;
|
||||||
|
|
||||||
|
rail = (railPlugin*) rail_get_init_handle_data(pInitHandle);
|
||||||
|
|
||||||
|
if (!rail)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "rail_virtual_channel_init_event: error no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case CHANNEL_EVENT_CONNECTED:
|
||||||
|
rail_virtual_channel_event_connected(rail, pData, dataLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_DISCONNECTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHANNEL_EVENT_TERMINATED:
|
||||||
|
rail_virtual_channel_event_terminated(rail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* rail is always built-in */
|
/* rail is always built-in */
|
||||||
#define VirtualChannelEntry rail_VirtualChannelEntry
|
#define VirtualChannelEntry rail_VirtualChannelEntry
|
||||||
|
|
||||||
|
@ -507,30 +537,25 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||||
RailClientContext* context;
|
RailClientContext* context;
|
||||||
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
|
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
|
||||||
|
|
||||||
rail = (railPlugin*) malloc(sizeof(railPlugin));
|
rail = (railPlugin*) calloc(1, sizeof(railPlugin));
|
||||||
ZeroMemory(rail, sizeof(railPlugin));
|
|
||||||
|
|
||||||
rail->plugin.channel_def.options =
|
rail->channelDef.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(rail->plugin.channel_def.name, "rail");
|
strcpy(rail->channelDef.name, "rail");
|
||||||
|
|
||||||
rail->plugin.connect_callback = rail_process_connect;
|
|
||||||
rail->plugin.receive_callback = rail_process_receive;
|
|
||||||
rail->plugin.event_callback = rail_process_event;
|
|
||||||
rail->plugin.terminate_callback = rail_process_terminate;
|
|
||||||
|
|
||||||
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
|
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
|
||||||
|
|
||||||
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
|
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
|
||||||
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
||||||
{
|
{
|
||||||
context = (RailClientContext*) malloc(sizeof(RailClientContext));
|
context = (RailClientContext*) calloc(1, sizeof(RailClientContext));
|
||||||
|
|
||||||
context->handle = (void*) rail;
|
context->handle = (void*) rail;
|
||||||
|
context->custom = NULL;
|
||||||
|
|
||||||
context->ClientExecute = rail_client_execute;
|
context->ClientExecute = rail_client_execute;
|
||||||
context->ClientActivate = rail_client_activate;
|
context->ClientActivate = rail_client_activate;
|
||||||
|
@ -554,6 +579,7 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||||
context->ServerGetAppIdResponse = rail_server_get_appid_response;
|
context->ServerGetAppIdResponse = rail_server_get_appid_response;
|
||||||
|
|
||||||
*(pEntryPointsEx->ppInterface) = (void*) context;
|
*(pEntryPointsEx->ppInterface) = (void*) context;
|
||||||
|
rail->context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
WLog_Init();
|
WLog_Init();
|
||||||
|
@ -561,7 +587,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||||
|
|
||||||
WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntry");
|
WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntry");
|
||||||
|
|
||||||
svc_plugin_init((rdpSvcPlugin*) rail, pEntryPoints);
|
CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
|
||||||
|
|
||||||
|
rail->channelEntryPoints.pVirtualChannelInit(&rail->InitHandle,
|
||||||
|
&rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rail_virtual_channel_init_event);
|
||||||
|
|
||||||
|
rail->channelEntryPoints.pInterface = *(rail->channelEntryPoints.ppInterface);
|
||||||
|
rail->channelEntryPoints.ppInterface = &(rail->channelEntryPoints.pInterface);
|
||||||
|
|
||||||
|
rail_add_init_handle_data(rail->InitHandle, (void*) rail);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
#define FREERDP_CHANNEL_CLIENT_RAIL_MAIN_H
|
#define FREERDP_CHANNEL_CLIENT_RAIL_MAIN_H
|
||||||
|
|
||||||
#include <freerdp/rail.h>
|
#include <freerdp/rail.h>
|
||||||
|
#include <freerdp/svc.h>
|
||||||
|
#include <freerdp/addin.h>
|
||||||
#include <freerdp/settings.h>
|
#include <freerdp/settings.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
|
|
||||||
#include <freerdp/client/rail.h>
|
#include <freerdp/client/rail.h>
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
@ -36,16 +36,21 @@
|
||||||
|
|
||||||
struct rail_plugin
|
struct rail_plugin
|
||||||
{
|
{
|
||||||
rdpSvcPlugin plugin;
|
CHANNEL_DEF channelDef;
|
||||||
|
CHANNEL_ENTRY_POINTS_FREERDP channelEntryPoints;
|
||||||
|
|
||||||
|
RailClientContext* context;
|
||||||
|
|
||||||
wLog* log;
|
wLog* log;
|
||||||
rdpRailOrder* rail_order;
|
HANDLE thread;
|
||||||
|
wStream* data_in;
|
||||||
|
void* InitHandle;
|
||||||
|
DWORD OpenHandle;
|
||||||
|
wMessageQueue* queue;
|
||||||
};
|
};
|
||||||
typedef struct rail_plugin railPlugin;
|
typedef struct rail_plugin railPlugin;
|
||||||
|
|
||||||
RailClientContext* rail_get_client_interface(void* railObject);
|
RailClientContext* rail_get_client_interface(railPlugin* rail);
|
||||||
|
void rail_send_channel_data(railPlugin* rail, void* data, size_t length);
|
||||||
void rail_send_channel_event(void* rail_object, UINT16 event_type, void* param);
|
|
||||||
void rail_send_channel_data(void* rail_object, void* data, size_t length);
|
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_CLIENT_RAIL_MAIN_H */
|
#endif /* FREERDP_CHANNEL_CLIENT_RAIL_MAIN_H */
|
||||||
|
|
|
@ -22,15 +22,48 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
|
||||||
#include <freerdp/utils/rail.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#include "rail_orders.h"
|
#include "rail_orders.h"
|
||||||
|
|
||||||
|
static BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < 2)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < unicode_string->length)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!unicode_string->string)
|
||||||
|
unicode_string->string = (BYTE*) malloc(unicode_string->length);
|
||||||
|
else
|
||||||
|
unicode_string->string = (BYTE*) realloc(unicode_string->string, unicode_string->length);
|
||||||
|
|
||||||
|
Stream_Read(s, unicode_string->string, unicode_string->length);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rail_write_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
|
||||||
|
{
|
||||||
|
Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length);
|
||||||
|
Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
|
||||||
|
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rail_write_unicode_string_value(wStream* s, RAIL_UNICODE_STRING* unicode_string)
|
||||||
|
{
|
||||||
|
if (unicode_string->length > 0)
|
||||||
|
{
|
||||||
|
Stream_EnsureRemainingCapacity(s, unicode_string->length);
|
||||||
|
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
|
void rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
|
||||||
{
|
{
|
||||||
UINT16 orderLength;
|
UINT16 orderLength;
|
||||||
|
@ -275,8 +308,6 @@ void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarI
|
||||||
|
|
||||||
BOOL rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake, wStream* s)
|
BOOL rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake, wStream* s)
|
||||||
{
|
{
|
||||||
RAIL_SYSPARAM_ORDER sysparam;
|
|
||||||
RAIL_CLIENT_STATUS_ORDER clientStatus;
|
|
||||||
RailClientContext* context = rail_get_client_interface(rail);
|
RailClientContext* context = rail_get_client_interface(rail);
|
||||||
|
|
||||||
if (!rail_read_handshake_order(s, handshake))
|
if (!rail_read_handshake_order(s, handshake))
|
||||||
|
@ -288,44 +319,6 @@ BOOL rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
handshake->buildNumber = 0x00001DB0;
|
|
||||||
rail_send_handshake_order(rail, handshake);
|
|
||||||
|
|
||||||
ZeroMemory(&clientStatus, sizeof(RAIL_CLIENT_STATUS_ORDER));
|
|
||||||
clientStatus.flags = RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE;
|
|
||||||
rail_send_client_status_order(rail, &clientStatus);
|
|
||||||
|
|
||||||
/* sysparam update */
|
|
||||||
|
|
||||||
ZeroMemory(&sysparam, sizeof(RAIL_SYSPARAM_ORDER));
|
|
||||||
|
|
||||||
sysparam.params = 0;
|
|
||||||
|
|
||||||
sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST;
|
|
||||||
sysparam.highContrast.colorScheme.string = NULL;
|
|
||||||
sysparam.highContrast.colorScheme.length = 0;
|
|
||||||
sysparam.highContrast.flags = 0x7E;
|
|
||||||
|
|
||||||
sysparam.params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
|
|
||||||
sysparam.mouseButtonSwap = FALSE;
|
|
||||||
|
|
||||||
sysparam.params |= SPI_MASK_SET_KEYBOARD_PREF;
|
|
||||||
sysparam.keyboardPref = FALSE;
|
|
||||||
|
|
||||||
sysparam.params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
|
|
||||||
sysparam.dragFullWindows = FALSE;
|
|
||||||
|
|
||||||
sysparam.params |= SPI_MASK_SET_KEYBOARD_CUES;
|
|
||||||
sysparam.keyboardCues = FALSE;
|
|
||||||
|
|
||||||
sysparam.params |= SPI_MASK_SET_WORK_AREA;
|
|
||||||
sysparam.workArea.left = 0;
|
|
||||||
sysparam.workArea.top = 0;
|
|
||||||
sysparam.workArea.right = 1024;
|
|
||||||
sysparam.workArea.bottom = 768;
|
|
||||||
|
|
||||||
rail_send_channel_event(rail, RailChannel_GetSystemParam, &sysparam);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,10 +350,6 @@ BOOL rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER* execR
|
||||||
{
|
{
|
||||||
IFCALL(context->ServerExecuteResult, context, execResult);
|
IFCALL(context->ServerExecuteResult, context, execResult);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rail_send_channel_event(rail, RailChannel_ServerExecuteResult, execResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -376,10 +365,6 @@ BOOL rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysp
|
||||||
{
|
{
|
||||||
IFCALL(context->ServerSystemParam, context, sysparam);
|
IFCALL(context->ServerSystemParam, context, sysparam);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rail_send_channel_event(rail, RailChannel_ServerSystemParam, sysparam);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -395,10 +380,6 @@ BOOL rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ORDER*
|
||||||
{
|
{
|
||||||
IFCALL(context->ServerMinMaxInfo, context, minMaxInfo);
|
IFCALL(context->ServerMinMaxInfo, context, minMaxInfo);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rail_send_channel_event(rail, RailChannel_ServerMinMaxInfo, minMaxInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -414,10 +395,6 @@ BOOL rail_recv_server_localmovesize_order(railPlugin* rail, RAIL_LOCALMOVESIZE_O
|
||||||
{
|
{
|
||||||
IFCALL(context->ServerLocalMoveSize, context, localMoveSize);
|
IFCALL(context->ServerLocalMoveSize, context, localMoveSize);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rail_send_channel_event(rail, RailChannel_ServerLocalMoveSize, localMoveSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -433,10 +410,6 @@ BOOL rail_recv_server_get_appid_resp_order(railPlugin* rail, RAIL_GET_APPID_RESP
|
||||||
{
|
{
|
||||||
IFCALL(context->ServerGetAppIdResponse, context, getAppIdResp);
|
IFCALL(context->ServerGetAppIdResponse, context, getAppIdResp);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rail_send_channel_event(rail, RailChannel_ServerGetAppIdResponse, getAppIdResp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -452,10 +425,6 @@ BOOL rail_recv_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* lan
|
||||||
{
|
{
|
||||||
IFCALL(context->ServerLanguageBarInfo, context, langBarInfo);
|
IFCALL(context->ServerLanguageBarInfo, context, langBarInfo);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rail_send_channel_event(rail, RailChannel_ServerLanguageBarInfo, langBarInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +491,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,25 +681,3 @@ void rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORD
|
||||||
rail_send_pdu(rail, s, RDP_RAIL_ORDER_LANGBARINFO);
|
rail_send_pdu(rail, s, RDP_RAIL_ORDER_LANGBARINFO);
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpRailOrder* rail_order_new()
|
|
||||||
{
|
|
||||||
rdpRailOrder* railOrder;
|
|
||||||
|
|
||||||
railOrder = (rdpRailOrder*) malloc(sizeof(rdpRailOrder));
|
|
||||||
|
|
||||||
if (railOrder)
|
|
||||||
{
|
|
||||||
ZeroMemory(railOrder, sizeof(rdpRailOrder));
|
|
||||||
}
|
|
||||||
|
|
||||||
return railOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rail_order_free(rdpRailOrder* railOrder)
|
|
||||||
{
|
|
||||||
if (railOrder)
|
|
||||||
{
|
|
||||||
free(railOrder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,8 +21,12 @@
|
||||||
#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);
|
||||||
|
@ -42,7 +46,6 @@ void rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER*
|
||||||
void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbar_info);
|
void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbar_info);
|
||||||
|
|
||||||
BOOL rail_order_recv(railPlugin* rail, wStream* s);
|
BOOL rail_order_recv(railPlugin* rail, wStream* s);
|
||||||
|
|
||||||
void rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType);
|
void rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType);
|
||||||
|
|
||||||
void rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake);
|
void rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake);
|
||||||
|
@ -59,7 +62,4 @@ void rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER
|
||||||
void rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_ORDER* getAppIdReq);
|
void rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_ORDER* getAppIdReq);
|
||||||
void rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo);
|
void rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo);
|
||||||
|
|
||||||
rdpRailOrder* rail_order_new(void);
|
|
||||||
void rail_order_free(rdpRailOrder* railOrder);
|
|
||||||
|
|
||||||
#endif /* __RAIL_ORDERS_H */
|
#endif /* __RAIL_ORDERS_H */
|
||||||
|
|
|
@ -29,41 +29,18 @@ extern const char* const RAIL_ORDER_TYPE_STRINGS[];
|
||||||
#define RAIL_PDU_HEADER_LENGTH 4
|
#define RAIL_PDU_HEADER_LENGTH 4
|
||||||
|
|
||||||
/* Fixed length of PDUs, excluding variable lengths */
|
/* Fixed length of PDUs, excluding variable lengths */
|
||||||
#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */
|
#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */
|
||||||
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
|
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
|
||||||
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
|
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
|
||||||
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
|
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
|
||||||
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
|
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
|
||||||
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
|
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
|
||||||
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
|
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
|
||||||
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
|
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
|
||||||
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
|
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
|
||||||
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
|
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
|
||||||
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
|
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
|
||||||
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
|
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
|
||||||
|
|
||||||
struct rdp_rail_order
|
|
||||||
{
|
|
||||||
rdpSettings* settings;
|
|
||||||
void* plugin;
|
|
||||||
RAIL_HANDSHAKE_ORDER handshake;
|
|
||||||
RAIL_CLIENT_STATUS_ORDER client_status;
|
|
||||||
RAIL_EXEC_ORDER exec;
|
|
||||||
RAIL_EXEC_RESULT_ORDER exec_result;
|
|
||||||
RAIL_SYSPARAM_ORDER sysparam;
|
|
||||||
RAIL_ACTIVATE_ORDER activate;
|
|
||||||
RAIL_SYSMENU_ORDER sysmenu;
|
|
||||||
RAIL_SYSCOMMAND_ORDER syscommand;
|
|
||||||
RAIL_NOTIFY_EVENT_ORDER notify_event;
|
|
||||||
RAIL_MINMAXINFO_ORDER minmaxinfo;
|
|
||||||
RAIL_LOCALMOVESIZE_ORDER localmovesize;
|
|
||||||
RAIL_WINDOW_MOVE_ORDER window_move;
|
|
||||||
RAIL_LANGBAR_INFO_ORDER langbar_info;
|
|
||||||
RAIL_GET_APPID_REQ_ORDER get_appid_req;
|
|
||||||
RAIL_GET_APPID_RESP_ORDER get_appid_resp;
|
|
||||||
};
|
|
||||||
typedef struct rdp_rail_order rdpRailOrder;
|
|
||||||
|
|
||||||
|
|
||||||
void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_string);
|
void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_string);
|
||||||
BOOL rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake);
|
BOOL rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake);
|
||||||
|
|
|
@ -29,19 +29,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-crt winpr-synch winpr-thread winpr-interlocked)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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)
|
||||||
|
|
|
@ -75,6 +75,10 @@ IRP* irp_new(DEVMAN* devman, wStream* s)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
|
irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
|
||||||
|
|
||||||
|
if (!irp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
ZeroMemory(irp, sizeof(IRP));
|
ZeroMemory(irp, sizeof(IRP));
|
||||||
|
|
||||||
irp->input = s;
|
irp->input = s;
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -503,8 +506,10 @@ static void rdpdr_process_connect(rdpdrPlugin* rdpdr)
|
||||||
|
|
||||||
rdpdr->devman = devman_new(rdpdr);
|
rdpdr->devman = devman_new(rdpdr);
|
||||||
settings = (rdpSettings*) rdpdr->channelEntryPoints.pExtendedData;
|
settings = (rdpSettings*) rdpdr->channelEntryPoints.pExtendedData;
|
||||||
|
if (settings->ClientHostname)
|
||||||
strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1);
|
strncpy(rdpdr->computerName, settings->ClientHostname, sizeof(rdpdr->computerName) - 1);
|
||||||
|
else
|
||||||
|
strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1);
|
||||||
|
|
||||||
for (index = 0; index < settings->DeviceCount; index++)
|
for (index = 0; index < settings->DeviceCount; index++)
|
||||||
{
|
{
|
||||||
|
@ -536,8 +541,8 @@ static void rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
|
||||||
|
|
||||||
s = Stream_New(NULL, 12);
|
s = Stream_New(NULL, 12);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
|
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM);
|
Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
Stream_Write_UINT16(s, rdpdr->versionMajor);
|
Stream_Write_UINT16(s, rdpdr->versionMajor);
|
||||||
Stream_Write_UINT16(s, rdpdr->versionMinor);
|
Stream_Write_UINT16(s, rdpdr->versionMinor);
|
||||||
|
@ -559,8 +564,8 @@ static void rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
|
||||||
|
|
||||||
s = Stream_New(NULL, 16 + computerNameLenW + 2);
|
s = Stream_New(NULL, 16 + computerNameLenW + 2);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
|
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME);
|
Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
|
Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
|
||||||
Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */
|
Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */
|
||||||
|
@ -611,8 +616,8 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
|
||||||
|
|
||||||
s = Stream_New(NULL, 256);
|
s = Stream_New(NULL, 256);
|
||||||
|
|
||||||
Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
|
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
|
||||||
Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE);
|
Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
count_pos = (int) Stream_GetPosition(s);
|
count_pos = (int) Stream_GetPosition(s);
|
||||||
count = 0;
|
count = 0;
|
||||||
|
@ -659,9 +664,8 @@ static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use
|
||||||
Stream_Write(s, Stream_Buffer(device->data), data_len);
|
Stream_Write(s, Stream_Buffer(device->data), data_len);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
WLog_INFO(TAG, "registered device #%d: %s (type=%d id=%d)",
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,16 +718,16 @@ static void rdpdr_process_init(rdpdrPlugin* rdpdr)
|
||||||
static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
|
static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
|
||||||
{
|
{
|
||||||
UINT16 component;
|
UINT16 component;
|
||||||
UINT16 packetID;
|
UINT16 packetId;
|
||||||
UINT32 deviceID;
|
UINT32 deviceId;
|
||||||
UINT32 status;
|
UINT32 status;
|
||||||
|
|
||||||
Stream_Read_UINT16(s, component);
|
Stream_Read_UINT16(s, component); /* Component (2 bytes) */
|
||||||
Stream_Read_UINT16(s, packetID);
|
Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
|
||||||
|
|
||||||
if (component == RDPDR_CTYP_CORE)
|
if (component == RDPDR_CTYP_CORE)
|
||||||
{
|
{
|
||||||
switch (packetID)
|
switch (packetId)
|
||||||
{
|
{
|
||||||
case PAKID_CORE_SERVER_ANNOUNCE:
|
case PAKID_CORE_SERVER_ANNOUNCE:
|
||||||
rdpdr_process_server_announce_request(rdpdr, s);
|
rdpdr_process_server_announce_request(rdpdr, s);
|
||||||
|
@ -748,7 +752,7 @@ static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
|
||||||
|
|
||||||
case PAKID_CORE_DEVICE_REPLY:
|
case PAKID_CORE_DEVICE_REPLY:
|
||||||
/* connect to a specific resource */
|
/* connect to a specific resource */
|
||||||
Stream_Read_UINT32(s, deviceID);
|
Stream_Read_UINT32(s, deviceId);
|
||||||
Stream_Read_UINT32(s, status);
|
Stream_Read_UINT32(s, status);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -758,17 +762,19 @@ static void rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
WLog_ERR(TAG, "rdpdr_process_receive: RDPDR_CTYP_CORE unknown PacketId: 0x%04X", packetId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (component == RDPDR_CTYP_PRN)
|
else if (component == RDPDR_CTYP_PRN)
|
||||||
{
|
{
|
||||||
|
WLog_ERR(TAG, "rdpdr_process_receive: RDPDR_CTYP_PRN unknown PacketId: 0x%04X", packetId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
WLog_ERR(TAG, "rdpdr_process_receive: unknown message: Component: 0x%04X PacketId: 0x%04X",
|
||||||
|
component, packetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
@ -843,7 +849,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", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -867,7 +873,7 @@ static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr,
|
||||||
|
|
||||||
if (dataFlags & CHANNEL_FLAG_FIRST)
|
if (dataFlags & CHANNEL_FLAG_FIRST)
|
||||||
{
|
{
|
||||||
if (rdpdr->data_in != NULL)
|
if (rdpdr->data_in)
|
||||||
Stream_Free(rdpdr->data_in, TRUE);
|
Stream_Free(rdpdr->data_in, TRUE);
|
||||||
|
|
||||||
rdpdr->data_in = Stream_New(NULL, totalLength);
|
rdpdr->data_in = Stream_New(NULL, totalLength);
|
||||||
|
@ -881,14 +887,14 @@ static void rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr,
|
||||||
{
|
{
|
||||||
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "svc_plugin_process_received: read error\n");
|
WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received: read error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpdr->data_in = NULL;
|
rdpdr->data_in = NULL;
|
||||||
Stream_SealLength(data_in);
|
Stream_SealLength(data_in);
|
||||||
Stream_SetPosition(data_in, 0);
|
Stream_SetPosition(data_in, 0);
|
||||||
|
|
||||||
MessageQueue_Post(rdpdr->MsgPipe->In, NULL, 0, (void*) data_in, NULL);
|
MessageQueue_Post(rdpdr->queue, NULL, 0, (void*) data_in, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,7 +907,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev
|
||||||
|
|
||||||
if (!rdpdr)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,9 +920,6 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev
|
||||||
case CHANNEL_EVENT_WRITE_COMPLETE:
|
case CHANNEL_EVENT_WRITE_COMPLETE:
|
||||||
Stream_Free((wStream*) pData, TRUE);
|
Stream_Free((wStream*) pData, TRUE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHANNEL_EVENT_USER:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,10 +933,10 @@ static void* rdpdr_virtual_channel_client_thread(void* arg)
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!MessageQueue_Wait(rdpdr->MsgPipe->In))
|
if (!MessageQueue_Wait(rdpdr->queue))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (MessageQueue_Peek(rdpdr->MsgPipe->In, &message, TRUE))
|
if (MessageQueue_Peek(rdpdr->queue, &message, TRUE))
|
||||||
{
|
{
|
||||||
if (message.id == WMQ_QUIT)
|
if (message.id == WMQ_QUIT)
|
||||||
break;
|
break;
|
||||||
|
@ -961,11 +964,11 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpdr->MsgPipe = MessagePipe_New();
|
rdpdr->queue = MessageQueue_New(NULL);
|
||||||
|
|
||||||
rdpdr->thread = CreateThread(NULL, 0,
|
rdpdr->thread = CreateThread(NULL, 0,
|
||||||
(LPTHREAD_START_ROUTINE) rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, NULL);
|
(LPTHREAD_START_ROUTINE) rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, NULL);
|
||||||
|
@ -973,11 +976,17 @@ static void rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa
|
||||||
|
|
||||||
static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
|
static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
|
||||||
{
|
{
|
||||||
MessagePipe_PostQuit(rdpdr->MsgPipe, 0);
|
if (rdpdr->queue)
|
||||||
WaitForSingleObject(rdpdr->thread, INFINITE);
|
{
|
||||||
|
MessageQueue_PostQuit(rdpdr->queue, 0);
|
||||||
|
WaitForSingleObject(rdpdr->thread, INFINITE);
|
||||||
|
|
||||||
MessagePipe_Free(rdpdr->MsgPipe);
|
MessageQueue_Free(rdpdr->queue);
|
||||||
CloseHandle(rdpdr->thread);
|
rdpdr->queue = NULL;
|
||||||
|
|
||||||
|
CloseHandle(rdpdr->thread);
|
||||||
|
rdpdr->thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
drive_hotplug_thread_terminate(rdpdr);
|
drive_hotplug_thread_terminate(rdpdr);
|
||||||
|
|
||||||
|
@ -997,6 +1006,8 @@ static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr)
|
||||||
|
|
||||||
rdpdr_remove_open_handle_data(rdpdr->OpenHandle);
|
rdpdr_remove_open_handle_data(rdpdr->OpenHandle);
|
||||||
rdpdr_remove_init_handle_data(rdpdr->InitHandle);
|
rdpdr_remove_init_handle_data(rdpdr->InitHandle);
|
||||||
|
|
||||||
|
free(rdpdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
|
static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
|
||||||
|
@ -1007,7 +1018,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT
|
||||||
|
|
||||||
if (!rdpdr)
|
if (!rdpdr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "rdpdr_virtual_channel_init_event: error no match\n");
|
WLog_ERR(TAG, "rdpdr_virtual_channel_init_event: error no match");
|
||||||
return;
|
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("rdpdr.client")
|
||||||
|
|
||||||
typedef struct rdpdr_plugin rdpdrPlugin;
|
typedef struct rdpdr_plugin rdpdrPlugin;
|
||||||
|
|
||||||
|
@ -44,7 +47,7 @@ struct rdpdr_plugin
|
||||||
wStream* data_in;
|
wStream* data_in;
|
||||||
void* InitHandle;
|
void* InitHandle;
|
||||||
DWORD OpenHandle;
|
DWORD OpenHandle;
|
||||||
wMessagePipe* MsgPipe;
|
wMessageQueue* queue;
|
||||||
|
|
||||||
DEVMAN* devman;
|
DEVMAN* devman;
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
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)
|
||||||
|
@ -34,27 +37,19 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
||||||
wStream* s;
|
wStream* s;
|
||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
|
ULONG written;
|
||||||
printf("RdpdrServerSendAnnounceRequest\n");
|
WLog_DBG(TAG, "RdpdrServerSendAnnounceRequest");
|
||||||
|
|
||||||
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), NULL);
|
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,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) */
|
||||||
|
@ -99,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
|
||||||
{
|
{
|
||||||
|
@ -107,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,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) */
|
||||||
|
@ -148,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,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 */
|
||||||
|
@ -183,7 +166,6 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
|
||||||
ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */
|
ioCode1 |= RDPDR_IRP_MJ_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 */
|
||||||
|
@ -193,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) */
|
||||||
|
@ -209,7 +188,6 @@ static int rdpdr_server_write_general_capability_set(RdpdrServerContext* context
|
||||||
Stream_Write_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */
|
Stream_Write_UINT32(s, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,14 +199,11 @@ static int rdpdr_server_read_printer_capability_set(RdpdrServerContext* context,
|
||||||
static int rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,14 +215,11 @@ static int rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wS
|
||||||
static int rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,14 +231,11 @@ static int rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, w
|
||||||
static int rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,14 +247,11 @@ static int rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* contex
|
||||||
static int rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,34 +261,24 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
|
||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
UINT16 numCapabilities;
|
UINT16 numCapabilities;
|
||||||
|
ULONG written;
|
||||||
printf("RdpdrServerSendCoreCapabilityRequest\n");
|
WLog_DBG(TAG, "RdpdrServerSendCoreCapabilityRequest");
|
||||||
|
|
||||||
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), NULL);
|
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,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) */
|
||||||
|
|
||||||
|
@ -362,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;
|
||||||
}
|
}
|
||||||
|
@ -376,27 +331,19 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
||||||
wStream* s;
|
wStream* s;
|
||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
|
ULONG written;
|
||||||
printf("RdpdrServerSendClientIdConfirm\n");
|
WLog_DBG(TAG, "RdpdrServerSendClientIdConfirm");
|
||||||
|
|
||||||
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), NULL);
|
|
||||||
|
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,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++)
|
||||||
{
|
{
|
||||||
|
@ -421,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)
|
||||||
{
|
{
|
||||||
|
@ -457,32 +400,24 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
||||||
wStream* s;
|
wStream* s;
|
||||||
BOOL status;
|
BOOL status;
|
||||||
RDPDR_HEADER header;
|
RDPDR_HEADER header;
|
||||||
|
ULONG written;
|
||||||
printf("%s\n", __FUNCTION__);
|
WLog_DBG(TAG, "%s");
|
||||||
|
|
||||||
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), NULL);
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -503,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:
|
||||||
|
@ -541,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,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)
|
||||||
|
@ -580,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)
|
||||||
|
@ -594,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
@ -20,26 +20,15 @@ define_channel_client("rdpei")
|
||||||
set(${MODULE_PREFIX}_SRCS
|
set(${MODULE_PREFIX}_SRCS
|
||||||
rdpei_main.c
|
rdpei_main.c
|
||||||
rdpei_main.h
|
rdpei_main.h
|
||||||
rdpei_common.c
|
../rdpei_common.c
|
||||||
rdpei_common.h)
|
../rdpei_common.h)
|
||||||
|
|
||||||
include_directories(..)
|
include_directories(..)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-sysinfo)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,8 @@ struct _RDPEI_PLUGIN
|
||||||
IWTSListener* listener;
|
IWTSListener* listener;
|
||||||
RDPEI_LISTENER_CALLBACK* listener_callback;
|
RDPEI_LISTENER_CALLBACK* listener_callback;
|
||||||
|
|
||||||
|
RdpeiClientContext* context;
|
||||||
|
|
||||||
int version;
|
int version;
|
||||||
UINT16 maxTouchContacts;
|
UINT16 maxTouchContacts;
|
||||||
UINT64 currentFrameTime;
|
UINT64 currentFrameTime;
|
||||||
|
@ -201,8 +203,8 @@ int rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, UINT16 eventId,
|
||||||
status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL);
|
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 +241,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 +266,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 +291,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 +377,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 +414,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)
|
||||||
|
@ -434,17 +440,12 @@ int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||||
{
|
{
|
||||||
wStream* s;
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback;
|
RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback;
|
||||||
|
|
||||||
s = Stream_New(pBuffer, cbSize);
|
status = rdpei_recv_pdu(callback, data);
|
||||||
|
|
||||||
status = rdpei_recv_pdu(callback, s);
|
|
||||||
|
|
||||||
Stream_Free(s, FALSE);
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -535,6 +536,8 @@ static int rdpei_plugin_terminated(IWTSPlugin* pPlugin)
|
||||||
if (rdpei->listener_callback)
|
if (rdpei->listener_callback)
|
||||||
free(rdpei->listener_callback);
|
free(rdpei->listener_callback);
|
||||||
|
|
||||||
|
free(rdpei->context);
|
||||||
|
|
||||||
free(rdpei);
|
free(rdpei);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -744,7 +747,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
|
|
||||||
rdpei = (RDPEI_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "rdpei");
|
rdpei = (RDPEI_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "rdpei");
|
||||||
|
|
||||||
if (rdpei == NULL)
|
if (!rdpei)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
@ -779,6 +782,7 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
rdpei->iface.pInterface = (void*) context;
|
rdpei->iface.pInterface = (void*) context;
|
||||||
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", (IWTSPlugin*) rdpei);
|
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", (IWTSPlugin*) rdpei);
|
||||||
|
rdpei->context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -27,30 +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/channels/rdpei.h>
|
||||||
#include <freerdp/client/rdpei.h>
|
#include <freerdp/client/rdpei.h>
|
||||||
|
|
||||||
#define RDPINPUT_HEADER_LENGTH 6
|
#define TAG CHANNELS_TAG("rdpei.client")
|
||||||
|
|
||||||
/* Protocol Version */
|
|
||||||
|
|
||||||
#define RDPINPUT_PROTOCOL_V10 0x00010000
|
|
||||||
#define RDPINPUT_PROTOCOL_V101 0x00010001
|
|
||||||
|
|
||||||
/* Client Ready Flags */
|
|
||||||
|
|
||||||
#define READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001
|
|
||||||
#define READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002
|
|
||||||
|
|
||||||
/* Input Event Ids */
|
|
||||||
|
|
||||||
#define EVENTID_SC_READY 0x0001
|
|
||||||
#define EVENTID_CS_READY 0x0002
|
|
||||||
#define EVENTID_TOUCH 0x0003
|
|
||||||
#define EVENTID_SUSPEND_TOUCH 0x0004
|
|
||||||
#define EVENTID_RESUME_TOUCH 0x0005
|
|
||||||
#define EVENTID_DISMISS_HOVERING_CONTACT 0x0006
|
|
||||||
|
|
||||||
#define RDPINPUT_CONTACT_STATE_INITIAL 0x0000
|
#define RDPINPUT_CONTACT_STATE_INITIAL 0x0000
|
||||||
#define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001
|
#define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001
|
||||||
|
@ -100,9 +82,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 */
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* Input Virtual Channel Extension
|
* Input Virtual Channel Extension
|
||||||
*
|
*
|
||||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
* Copyright 2014 David Fort <contact@hardening-consulting.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.
|
||||||
|
@ -587,3 +588,23 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value)
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void touch_event_reset(RDPINPUT_TOUCH_EVENT *event)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < event->frameCount; i++)
|
||||||
|
touch_frame_reset(&event->frames[i]);
|
||||||
|
|
||||||
|
free(event->frames);
|
||||||
|
event->frames = NULL;
|
||||||
|
event->frameCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame)
|
||||||
|
{
|
||||||
|
free(frame->contacts);
|
||||||
|
frame->contacts = NULL;
|
||||||
|
frame->contactCount = 0;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
* Input Virtual Channel Extension
|
* Input Virtual Channel Extension
|
||||||
*
|
*
|
||||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
* Copyright 2014 David Fort <contact@hardening-consulting.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.
|
||||||
|
@ -17,11 +18,22 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H
|
#ifndef FREERDP_CHANNEL_RDPEI_COMMON_H
|
||||||
#define FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H
|
#define FREERDP_CHANNEL_RDPEI_COMMON_H
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
#include <freerdp/channels/rdpei.h>
|
||||||
|
|
||||||
|
/** @brief input event ids */
|
||||||
|
enum {
|
||||||
|
EVENTID_SC_READY = 0x0001,
|
||||||
|
EVENTID_CS_READY = 0x0002,
|
||||||
|
EVENTID_TOUCH = 0x0003,
|
||||||
|
EVENTID_SUSPEND_TOUCH = 0x0004,
|
||||||
|
EVENTID_RESUME_TOUCH = 0x0005,
|
||||||
|
EVENTID_DISMISS_HOVERING_CONTACT = 0x0006
|
||||||
|
};
|
||||||
|
|
||||||
BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value);
|
BOOL rdpei_read_2byte_unsigned(wStream* s, UINT32* value);
|
||||||
BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value);
|
BOOL rdpei_write_2byte_unsigned(wStream* s, UINT32 value);
|
||||||
|
@ -34,5 +46,8 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value);
|
||||||
BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value);
|
BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value);
|
||||||
BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value);
|
BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value);
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_RDPEI_CLIENT_COMMON_H */
|
void touch_event_reset(RDPINPUT_TOUCH_EVENT *event);
|
||||||
|
void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame);
|
||||||
|
|
||||||
|
#endif /* FREERDP_CHANNEL_RDPEI_COMMON_H */
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
# FreeRDP cmake build script
|
||||||
|
#
|
||||||
|
# Copyright 2014 Thincast Technologies Gmbh.
|
||||||
|
# Copyright 2014 David FORT <contact@hardening-consulting.com>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
define_channel_server("rdpei")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_SRCS
|
||||||
|
rdpei_main.c
|
||||||
|
rdpei_main.h
|
||||||
|
../rdpei_common.c
|
||||||
|
../rdpei_common.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
|
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
|
||||||
|
|
||||||
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
|
@ -0,0 +1,464 @@
|
||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Extended Input channel server-side implementation
|
||||||
|
*
|
||||||
|
* Copyright 2014 Thincast Technologies Gmbh.
|
||||||
|
* Copyright 2014 David FORT <contact@hardening-consulting.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/print.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
|
#include "rdpei_main.h"
|
||||||
|
#include "../rdpei_common.h"
|
||||||
|
#include <freerdp/channels/rdpei.h>
|
||||||
|
#include <freerdp/server/rdpei.h>
|
||||||
|
|
||||||
|
/** @brief */
|
||||||
|
enum RdpEiState {
|
||||||
|
STATE_INITIAL,
|
||||||
|
STATE_WAITING_CLIENT_READY,
|
||||||
|
STATE_WAITING_FRAME,
|
||||||
|
STATE_SUSPENDED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _rdpei_server_private
|
||||||
|
{
|
||||||
|
HANDLE channelHandle;
|
||||||
|
HANDLE eventHandle;
|
||||||
|
|
||||||
|
UINT32 expectedBytes;
|
||||||
|
BOOL waitingHeaders;
|
||||||
|
wStream *inputStream;
|
||||||
|
wStream *outputStream;
|
||||||
|
|
||||||
|
UINT16 currentMsgType;
|
||||||
|
|
||||||
|
RDPINPUT_TOUCH_EVENT touchEvent;
|
||||||
|
|
||||||
|
enum RdpEiState automataState;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
RdpeiServerContext* rdpei_server_context_new(HANDLE vcm)
|
||||||
|
{
|
||||||
|
RdpeiServerContext *ret = calloc(1, sizeof(*ret));
|
||||||
|
RdpeiServerPrivate *priv;
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret->priv = priv = calloc(1, sizeof(*ret->priv));
|
||||||
|
if (!priv)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
priv->inputStream = Stream_New(NULL, 256);
|
||||||
|
if (!priv->inputStream)
|
||||||
|
goto out_free_priv;
|
||||||
|
|
||||||
|
priv->outputStream = Stream_New(NULL, 200);
|
||||||
|
if (!priv->inputStream)
|
||||||
|
goto out_free_input_stream;
|
||||||
|
|
||||||
|
ret->vcm = vcm;
|
||||||
|
rdpei_server_context_reset(ret);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
out_free_input_stream:
|
||||||
|
Stream_Free(priv->inputStream, TRUE);
|
||||||
|
out_free_priv:
|
||||||
|
free(ret->priv);
|
||||||
|
out_free:
|
||||||
|
free(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpei_server_init(RdpeiServerContext *context)
|
||||||
|
{
|
||||||
|
void *buffer = NULL;
|
||||||
|
DWORD bytesReturned;
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
|
||||||
|
priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
|
||||||
|
if (!priv->channelHandle)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: unable to open channel\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n",
|
||||||
|
__FUNCTION__, bytesReturned);
|
||||||
|
if (buffer)
|
||||||
|
WTSFreeMemory(buffer);
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
CopyMemory(&priv->eventHandle, buffer, sizeof(HANDLE));
|
||||||
|
WTSFreeMemory(buffer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
WTSVirtualChannelClose(priv->channelHandle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rdpei_server_context_reset(RdpeiServerContext *context)
|
||||||
|
{
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
|
||||||
|
priv->channelHandle = INVALID_HANDLE_VALUE;
|
||||||
|
priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
|
||||||
|
priv->waitingHeaders = TRUE;
|
||||||
|
priv->automataState = STATE_INITIAL;
|
||||||
|
Stream_SetPosition(priv->inputStream, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdpei_server_context_free(RdpeiServerContext* context)
|
||||||
|
{
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
if (priv->channelHandle != INVALID_HANDLE_VALUE)
|
||||||
|
WTSVirtualChannelClose(priv->channelHandle);
|
||||||
|
Stream_Free(priv->inputStream, TRUE);
|
||||||
|
free(priv);
|
||||||
|
free(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context)
|
||||||
|
{
|
||||||
|
return context->priv->eventHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int read_cs_ready_message(RdpeiServerContext *context, wStream *s)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < 10)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, context->protocolFlags);
|
||||||
|
Stream_Read_UINT32(s, context->clientVersion);
|
||||||
|
Stream_Read_UINT16(s, context->maxTouchPoints);
|
||||||
|
|
||||||
|
switch (context->clientVersion)
|
||||||
|
{
|
||||||
|
case RDPINPUT_PROTOCOL_V10:
|
||||||
|
case RDPINPUT_PROTOCOL_V101:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: unhandled RPDEI protocol version 0x%x\n", __FUNCTION__, context->clientVersion);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->onClientReady)
|
||||||
|
context->onClientReady(context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDPINPUT_CONTACT_DATA *contactData)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT8(s, contactData->contactId);
|
||||||
|
if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
|
||||||
|
!rdpei_read_4byte_signed(s, &contactData->x) ||
|
||||||
|
!rdpei_read_4byte_signed(s, &contactData->y) ||
|
||||||
|
!rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
|
||||||
|
{
|
||||||
|
if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) ||
|
||||||
|
!rdpei_read_2byte_signed(s, &contactData->contactRectTop) ||
|
||||||
|
!rdpei_read_2byte_signed(s, &contactData->contactRectRight) ||
|
||||||
|
!rdpei_read_2byte_signed(s, &contactData->contactRectBottom))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) &&
|
||||||
|
!rdpei_read_4byte_unsigned(s, &contactData->orientation))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) &&
|
||||||
|
!rdpei_read_4byte_unsigned(s, &contactData->pressure))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_TOUCH_FRAME *frame)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
RDPINPUT_CONTACT_DATA *contact;
|
||||||
|
|
||||||
|
if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) || !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
frame->contacts = contact = calloc(frame->contactCount, sizeof(RDPINPUT_CONTACT_DATA));
|
||||||
|
if (!frame->contacts)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < frame->contactCount; i++, contact++)
|
||||||
|
{
|
||||||
|
if (read_touch_contact_data(context, s, contact) < 0)
|
||||||
|
{
|
||||||
|
frame->contactCount = i;
|
||||||
|
goto out_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_cleanup:
|
||||||
|
touch_frame_reset(frame);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_touch_event(RdpeiServerContext *context, wStream *s)
|
||||||
|
{
|
||||||
|
UINT32 frameCount;
|
||||||
|
int i, ret;
|
||||||
|
RDPINPUT_TOUCH_EVENT *event = &context->priv->touchEvent;
|
||||||
|
RDPINPUT_TOUCH_FRAME *frame;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) || !rdpei_read_2byte_unsigned(s, &frameCount))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
event->frameCount = frameCount;
|
||||||
|
event->frames = frame = calloc(event->frameCount, sizeof(RDPINPUT_TOUCH_FRAME));
|
||||||
|
if (!event->frames)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < frameCount; i++, frame++)
|
||||||
|
{
|
||||||
|
if (read_touch_frame(context, s, frame) < 0)
|
||||||
|
{
|
||||||
|
event->frameCount = i;
|
||||||
|
goto out_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->onTouchEvent)
|
||||||
|
context->onTouchEvent(context, event);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out_cleanup:
|
||||||
|
touch_event_reset(event);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int read_dismiss_hovering_contact(RdpeiServerContext *context, wStream *s) {
|
||||||
|
BYTE contactId;
|
||||||
|
if (Stream_GetRemainingLength(s) < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT8(s, contactId);
|
||||||
|
if (context->onTouchReleased)
|
||||||
|
context->onTouchReleased(context, contactId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rdpei_server_handle_messages(RdpeiServerContext *context) {
|
||||||
|
DWORD bytesReturned;
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
wStream *s = priv->inputStream;
|
||||||
|
|
||||||
|
if (!WTSVirtualChannelRead(priv->channelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned))
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_NO_DATA)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
priv->expectedBytes -= bytesReturned;
|
||||||
|
Stream_Seek(s, bytesReturned);
|
||||||
|
|
||||||
|
if (priv->expectedBytes)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
Stream_SealLength(s);
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
|
||||||
|
if (priv->waitingHeaders)
|
||||||
|
{
|
||||||
|
UINT32 pduLen;
|
||||||
|
|
||||||
|
/* header case */
|
||||||
|
Stream_Read_UINT16(s, priv->currentMsgType);
|
||||||
|
Stream_Read_UINT16(s, pduLen);
|
||||||
|
|
||||||
|
if (pduLen < RDPINPUT_HEADER_LENGTH)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: invalid pduLength %d\n", __FUNCTION__, pduLen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH;
|
||||||
|
priv->waitingHeaders = FALSE;
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
if (priv->expectedBytes)
|
||||||
|
{
|
||||||
|
Stream_EnsureCapacity(s, priv->expectedBytes);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* when here we have the header + the body */
|
||||||
|
switch (priv->currentMsgType)
|
||||||
|
{
|
||||||
|
case EVENTID_CS_READY:
|
||||||
|
if (priv->automataState != STATE_WAITING_CLIENT_READY)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: not expecting a CS_READY packet in this state(%d)\n", __FUNCTION__, (int)priv->automataState);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_cs_ready_message(context, s) < 0)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EVENTID_TOUCH:
|
||||||
|
if (read_touch_event(context, s) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: error in touch event packet\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENTID_DISMISS_HOVERING_CONTACT:
|
||||||
|
if (read_dismiss_hovering_contact(context, s) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: error reading read_dismiss_hovering_contact\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: unexpected message type 0x%x\n", __FUNCTION__, priv->currentMsgType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_SetPosition(s, 0);
|
||||||
|
priv->waitingHeaders = TRUE;
|
||||||
|
priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version)
|
||||||
|
{
|
||||||
|
ULONG written;
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
|
||||||
|
if (priv->automataState != STATE_INITIAL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_SetPosition(priv->outputStream, 0);
|
||||||
|
Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4);
|
||||||
|
|
||||||
|
Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
|
||||||
|
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4);
|
||||||
|
Stream_Write_UINT32(priv->outputStream, version);
|
||||||
|
|
||||||
|
if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream),
|
||||||
|
Stream_GetPosition(priv->outputStream), &written))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: error writing ready message\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->automataState = STATE_WAITING_CLIENT_READY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpei_server_suspend(RdpeiServerContext *context)
|
||||||
|
{
|
||||||
|
ULONG written;
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
|
||||||
|
switch (priv->automataState)
|
||||||
|
{
|
||||||
|
case STATE_SUSPENDED:
|
||||||
|
fprintf(stderr, "%s: already suspended\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
case STATE_WAITING_FRAME:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_SetPosition(priv->outputStream, 0);
|
||||||
|
Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH);
|
||||||
|
|
||||||
|
Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH);
|
||||||
|
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
|
||||||
|
|
||||||
|
if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream),
|
||||||
|
Stream_GetPosition(priv->outputStream), &written))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: error writing suspendTouch message\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->automataState = STATE_SUSPENDED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rdpei_server_resume(RdpeiServerContext *context)
|
||||||
|
{
|
||||||
|
ULONG written;
|
||||||
|
RdpeiServerPrivate *priv = context->priv;
|
||||||
|
|
||||||
|
switch (priv->automataState)
|
||||||
|
{
|
||||||
|
case STATE_WAITING_FRAME:
|
||||||
|
fprintf(stderr, "%s: not suspended\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
case STATE_SUSPENDED:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: called from unexpected state %d\n", __FUNCTION__, priv->automataState);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream_SetPosition(priv->outputStream, 0);
|
||||||
|
Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH);
|
||||||
|
|
||||||
|
Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH);
|
||||||
|
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
|
||||||
|
|
||||||
|
if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream),
|
||||||
|
Stream_GetPosition(priv->outputStream), &written))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: error writing resumeTouch message\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->automataState = STATE_WAITING_FRAME;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
* X11 Server Cursor
|
* Extended Input channel server-side implementation
|
||||||
*
|
*
|
||||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2014 David Fort <contact@hardening-consulting.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.
|
||||||
|
@ -17,11 +17,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XFREERDP_SERVER_CURSOR_H
|
#ifndef __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_
|
||||||
#define XFREERDP_SERVER_CURSOR_H
|
#define __FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_
|
||||||
|
|
||||||
#include "xfreerdp.h"
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/synch.h>
|
||||||
|
#include <winpr/thread.h>
|
||||||
|
|
||||||
int xf_cursor_init(xfInfo* xfi);
|
|
||||||
|
|
||||||
#endif /* XFREERDP_SERVER_CURSOR_H */
|
#endif /* FREERDP_CHANNEL_SERVER_RDPEI_MAIN_H_ */
|
||||||
|
|
|
@ -20,6 +20,8 @@ define_channel_client("rdpgfx")
|
||||||
set(${MODULE_PREFIX}_SRCS
|
set(${MODULE_PREFIX}_SRCS
|
||||||
rdpgfx_main.c
|
rdpgfx_main.c
|
||||||
rdpgfx_main.h
|
rdpgfx_main.h
|
||||||
|
rdpgfx_codec.c
|
||||||
|
rdpgfx_codec.h
|
||||||
rdpgfx_common.c
|
rdpgfx_common.c
|
||||||
rdpgfx_common.h)
|
rdpgfx_common.h)
|
||||||
|
|
||||||
|
@ -27,19 +29,9 @@ include_directories(..)
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-common freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Graphics Pipeline Extension
|
||||||
|
*
|
||||||
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
#include <freerdp/log.h>
|
||||||
|
|
||||||
|
#include "rdpgfx_common.h"
|
||||||
|
|
||||||
|
#include "rdpgfx_codec.h"
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpgfx.client")
|
||||||
|
|
||||||
|
int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode_remotefx(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode_clear(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode_planar(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta)
|
||||||
|
{
|
||||||
|
UINT32 index;
|
||||||
|
RDPGFX_RECT16* regionRect;
|
||||||
|
RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
|
||||||
|
|
||||||
|
meta->regionRects = NULL;
|
||||||
|
meta->quantQualityVals = NULL;
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
meta->regionRects = (RDPGFX_RECT16*) malloc(meta->numRegionRects * sizeof(RDPGFX_RECT16));
|
||||||
|
|
||||||
|
if (!meta->regionRects)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
meta->quantQualityVals = (RDPGFX_H264_QUANT_QUALITY*) malloc(meta->numRegionRects * sizeof(RDPGFX_H264_QUANT_QUALITY));
|
||||||
|
|
||||||
|
if (!meta->quantQualityVals)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %d", (int) meta->numRegionRects);
|
||||||
|
|
||||||
|
for (index = 0; index < meta->numRegionRects; index++)
|
||||||
|
{
|
||||||
|
regionRect = &(meta->regionRects[index]);
|
||||||
|
rdpgfx_read_rect16(s, regionRect);
|
||||||
|
WLog_DBG(TAG, "regionRects[%d]: left: %d top: %d right: %d bottom: %d",
|
||||||
|
index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (index = 0; index < meta->numRegionRects; index++)
|
||||||
|
{
|
||||||
|
quantQualityVal = &(meta->quantQualityVals[index]);
|
||||||
|
Stream_Read_UINT8(s, quantQualityVal->qpVal); /* qpVal (1 byte) */
|
||||||
|
Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */
|
||||||
|
|
||||||
|
quantQualityVal->qp = quantQualityVal->qpVal & 0x3F;
|
||||||
|
quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1;
|
||||||
|
quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1;
|
||||||
|
WLog_DBG(TAG, "quantQualityVals[%d]: qp: %d r: %d p: %d qualityVal: %d",
|
||||||
|
index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p, quantQualityVal->qualityVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
wStream* s;
|
||||||
|
RDPGFX_H264_BITMAP_STREAM h264;
|
||||||
|
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||||
|
|
||||||
|
s = Stream_New(cmd->data, cmd->length);
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
status = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta));
|
||||||
|
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
if (h264.meta.regionRects)
|
||||||
|
free(h264.meta.regionRects);
|
||||||
|
if (h264.meta.quantQualityVals)
|
||||||
|
free(h264.meta.quantQualityVals);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h264.data = Stream_Pointer(s);
|
||||||
|
h264.length = (UINT32) Stream_GetRemainingLength(s);
|
||||||
|
|
||||||
|
Stream_Free(s, FALSE);
|
||||||
|
|
||||||
|
cmd->extra = (void*) &h264;
|
||||||
|
|
||||||
|
if (context && context->SurfaceCommand)
|
||||||
|
{
|
||||||
|
context->SurfaceCommand(context, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(h264.meta.regionRects);
|
||||||
|
free(h264.meta.quantQualityVals);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode_alpha(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode_progressive(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
switch (cmd->codecId)
|
||||||
|
{
|
||||||
|
case RDPGFX_CODECID_UNCOMPRESSED:
|
||||||
|
status = rdpgfx_decode_uncompressed(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_CAVIDEO:
|
||||||
|
status = rdpgfx_decode_remotefx(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_CLEARCODEC:
|
||||||
|
status = rdpgfx_decode_clear(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_PLANAR:
|
||||||
|
status = rdpgfx_decode_planar(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_H264:
|
||||||
|
status = rdpgfx_decode_h264(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_ALPHA:
|
||||||
|
status = rdpgfx_decode_alpha(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||||
|
status = rdpgfx_decode_progressive(gfx, cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
* X11 Server Graphical Updates
|
* Graphics Pipeline Extension
|
||||||
*
|
*
|
||||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.
|
||||||
|
@ -17,12 +17,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __XF_UPDATE_H
|
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H
|
||||||
#define __XF_UPDATE_H
|
#define FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H
|
||||||
|
|
||||||
#include "xfreerdp.h"
|
#include <winpr/crt.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
void* xf_update_thread(void* param);
|
#include <freerdp/channels/rdpgfx.h>
|
||||||
|
|
||||||
#endif /* __XF_UPDATE_H */
|
#include "rdpgfx_main.h"
|
||||||
|
|
||||||
|
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd);
|
||||||
|
|
||||||
|
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H */
|
|
@ -26,12 +26,95 @@
|
||||||
|
|
||||||
#include "rdpgfx_common.h"
|
#include "rdpgfx_common.h"
|
||||||
|
|
||||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* point16)
|
const char* RDPGFX_CMDID_STRINGS[] =
|
||||||
{
|
{
|
||||||
Stream_Read_UINT16(s, point16->x); /* x (2 bytes) */
|
"RDPGFX_CMDID_UNUSED_0000",
|
||||||
Stream_Read_UINT16(s, point16->y); /* y (2 bytes) */
|
"RDPGFX_CMDID_WIRETOSURFACE_1",
|
||||||
|
"RDPGFX_CMDID_WIRETOSURFACE_2",
|
||||||
|
"RDPGFX_CMDID_DELETEENCODINGCONTEXT",
|
||||||
|
"RDPGFX_CMDID_SOLIDFILL",
|
||||||
|
"RDPGFX_CMDID_SURFACETOSURFACE",
|
||||||
|
"RDPGFX_CMDID_SURFACETOCACHE",
|
||||||
|
"RDPGFX_CMDID_CACHETOSURFACE",
|
||||||
|
"RDPGFX_CMDID_EVICTCACHEENTRY",
|
||||||
|
"RDPGFX_CMDID_CREATESURFACE",
|
||||||
|
"RDPGFX_CMDID_DELETESURFACE",
|
||||||
|
"RDPGFX_CMDID_STARTFRAME",
|
||||||
|
"RDPGFX_CMDID_ENDFRAME",
|
||||||
|
"RDPGFX_CMDID_FRAMEACKNOWLEDGE",
|
||||||
|
"RDPGFX_CMDID_RESETGRAPHICS",
|
||||||
|
"RDPGFX_CMDID_MAPSURFACETOOUTPUT",
|
||||||
|
"RDPGFX_CMDID_CACHEIMPORTOFFER",
|
||||||
|
"RDPGFX_CMDID_CACHEIMPORTREPLY",
|
||||||
|
"RDPGFX_CMDID_CAPSADVERTISE",
|
||||||
|
"RDPGFX_CMDID_CAPSCONFIRM",
|
||||||
|
"RDPGFX_CMDID_UNUSED_0014",
|
||||||
|
"RDPGFX_CMDID_MAPSURFACETOWINDOW"
|
||||||
|
};
|
||||||
|
|
||||||
return 0;
|
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId)
|
||||||
|
{
|
||||||
|
if (cmdId <= RDPGFX_CMDID_MAPSURFACETOWINDOW)
|
||||||
|
return RDPGFX_CMDID_STRINGS[cmdId];
|
||||||
|
else
|
||||||
|
return "RDPGFX_CMDID_UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* rdpgfx_get_codec_id_string(UINT16 codecId)
|
||||||
|
{
|
||||||
|
switch (codecId)
|
||||||
|
{
|
||||||
|
case RDPGFX_CODECID_UNCOMPRESSED:
|
||||||
|
return "RDPGFX_CODECID_UNCOMPRESSED";
|
||||||
|
case RDPGFX_CODECID_CAVIDEO:
|
||||||
|
return "RDPGFX_CODECID_CAVIDEO";
|
||||||
|
case RDPGFX_CODECID_CLEARCODEC:
|
||||||
|
return "RDPGFX_CODECID_CLEARCODEC";
|
||||||
|
case RDPGFX_CODECID_PLANAR:
|
||||||
|
return "RDPGFX_CODECID_PLANAR";
|
||||||
|
case RDPGFX_CODECID_H264:
|
||||||
|
return "RDPGFX_CODECID_H264";
|
||||||
|
case RDPGFX_CODECID_ALPHA:
|
||||||
|
return "RDPGFX_CODECID_ALPHA";
|
||||||
|
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||||
|
return "RDPGFX_CODECID_CAPROGRESSIVE";
|
||||||
|
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||||
|
return "RDPGFX_CODECID_CAPROGRESSIVE_V2";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "RDPGFX_CODECID_UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||||
|
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||||
|
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
|
||||||
|
{
|
||||||
|
Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||||
|
Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||||
|
Stream_Write_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16)
|
||||||
|
{
|
||||||
|
if (Stream_GetRemainingLength(s) < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Stream_Read_UINT16(s, pt16->x); /* x (2 bytes) */
|
||||||
|
Stream_Read_UINT16(s, pt16->y); /* y (2 bytes) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
||||||
|
@ -39,17 +122,20 @@ int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
||||||
Stream_Write_UINT16(s, point16->x); /* x (2 bytes) */
|
Stream_Write_UINT16(s, point16->x); /* x (2 bytes) */
|
||||||
Stream_Write_UINT16(s, point16->y); /* y (2 bytes) */
|
Stream_Write_UINT16(s, point16->y); /* y (2 bytes) */
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) */
|
||||||
Stream_Read_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
|
Stream_Read_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||||
|
@ -59,17 +145,20 @@ int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||||
Stream_Write_UINT16(s, rect16->right); /* right (2 bytes) */
|
Stream_Write_UINT16(s, rect16->right); /* right (2 bytes) */
|
||||||
Stream_Write_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
|
Stream_Write_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) */
|
||||||
Stream_Read_UINT8(s, color32->XA); /* XA (1 byte) */
|
Stream_Read_UINT8(s, color32->XA); /* XA (1 byte) */
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
|
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
|
||||||
|
@ -79,23 +168,5 @@ int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
|
||||||
Stream_Write_UINT8(s, color32->R); /* R (1 byte) */
|
Stream_Write_UINT8(s, color32->R); /* R (1 byte) */
|
||||||
Stream_Write_UINT8(s, color32->XA); /* XA (1 byte) */
|
Stream_Write_UINT8(s, color32->XA); /* XA (1 byte) */
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
|
||||||
{
|
|
||||||
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
|
||||||
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
|
||||||
Stream_Read_UINT16(s, header->pduLength); /* pduLength (4 bytes) */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
|
|
||||||
{
|
|
||||||
Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
|
||||||
Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */
|
|
||||||
Stream_Write_UINT16(s, header->pduLength); /* pduLength (4 bytes) */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,20 @@
|
||||||
|
|
||||||
#include <freerdp/channels/rdpgfx.h>
|
#include <freerdp/channels/rdpgfx.h>
|
||||||
|
|
||||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* point16);
|
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId);
|
||||||
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
|
const char* rdpgfx_get_codec_id_string(UINT16 codecId);
|
||||||
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
|
||||||
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
|
||||||
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
|
|
||||||
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
|
|
||||||
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header);
|
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header);
|
||||||
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header);
|
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header);
|
||||||
|
|
||||||
|
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16);
|
||||||
|
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
|
||||||
|
|
||||||
|
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||||
|
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||||
|
|
||||||
|
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||||
|
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_COMMON_H */
|
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_COMMON_H */
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
||||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
* Graphics Pipeline Extension
|
* Graphics Pipeline Extension
|
||||||
*
|
*
|
||||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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.
|
||||||
|
@ -20,17 +20,65 @@
|
||||||
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
|
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
|
||||||
#define FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
|
#define FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <freerdp/dvc.h>
|
#include <freerdp/dvc.h>
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
|
|
||||||
|
#include <winpr/wlog.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>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("rdpgfx.client")
|
||||||
|
|
||||||
|
struct _RDPGFX_CHANNEL_CALLBACK
|
||||||
|
{
|
||||||
|
IWTSVirtualChannelCallback iface;
|
||||||
|
|
||||||
|
IWTSPlugin* plugin;
|
||||||
|
IWTSVirtualChannelManager* channel_mgr;
|
||||||
|
IWTSVirtualChannel* channel;
|
||||||
|
};
|
||||||
|
typedef struct _RDPGFX_CHANNEL_CALLBACK RDPGFX_CHANNEL_CALLBACK;
|
||||||
|
|
||||||
|
struct _RDPGFX_LISTENER_CALLBACK
|
||||||
|
{
|
||||||
|
IWTSListenerCallback iface;
|
||||||
|
|
||||||
|
IWTSPlugin* plugin;
|
||||||
|
IWTSVirtualChannelManager* channel_mgr;
|
||||||
|
RDPGFX_CHANNEL_CALLBACK* channel_callback;
|
||||||
|
};
|
||||||
|
typedef struct _RDPGFX_LISTENER_CALLBACK RDPGFX_LISTENER_CALLBACK;
|
||||||
|
|
||||||
|
struct _RDPGFX_PLUGIN
|
||||||
|
{
|
||||||
|
IWTSPlugin iface;
|
||||||
|
|
||||||
|
IWTSListener* listener;
|
||||||
|
RDPGFX_LISTENER_CALLBACK* listener_callback;
|
||||||
|
|
||||||
|
wLog* log;
|
||||||
|
rdpSettings* settings;
|
||||||
|
|
||||||
|
BOOL ThinClient;
|
||||||
|
BOOL SmallCache;
|
||||||
|
BOOL Progressive;
|
||||||
|
BOOL ProgressiveV2;
|
||||||
|
BOOL H264;
|
||||||
|
|
||||||
|
ZGFX_CONTEXT* zgfx;
|
||||||
|
UINT32 UnacknowledgedFrames;
|
||||||
|
UINT32 TotalDecodedFrames;
|
||||||
|
|
||||||
|
wHashTable* SurfaceTable;
|
||||||
|
|
||||||
|
UINT16 MaxCacheSlot;
|
||||||
|
void* CacheSlots[25600];
|
||||||
|
};
|
||||||
|
typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN;
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */
|
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */
|
||||||
|
|
||||||
|
|
|
@ -23,19 +23,9 @@ set(${MODULE_PREFIX}_SRCS
|
||||||
|
|
||||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils)
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE winpr
|
|
||||||
MODULES winpr-sysinfo winpr-utils)
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
|
|
||||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,9 @@ include_directories(${ALSA_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||||
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[] =
|
||||||
|
|
|
@ -31,18 +31,15 @@ include_directories(..)
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,11 @@
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <winpr/wtypes.h>
|
#include <winpr/wtypes.h>
|
||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/codec/dsp.h>
|
#include <freerdp/codec/dsp.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
|
|
||||||
#import <AudioToolbox/AudioToolbox.h>
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
|
|
||||||
|
@ -37,66 +36,66 @@
|
||||||
|
|
||||||
typedef struct rdpsnd_ios_plugin
|
typedef struct rdpsnd_ios_plugin
|
||||||
{
|
{
|
||||||
rdpsndDevicePlugin device;
|
rdpsndDevicePlugin device;
|
||||||
AudioComponentInstance audio_unit;
|
AudioComponentInstance audio_unit;
|
||||||
TPCircularBuffer buffer;
|
TPCircularBuffer buffer;
|
||||||
BOOL is_opened;
|
BOOL is_opened;
|
||||||
BOOL is_playing;
|
BOOL is_playing;
|
||||||
} rdpsndIOSPlugin;
|
} rdpsndIOSPlugin;
|
||||||
|
|
||||||
#define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr)
|
#define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr)
|
||||||
|
|
||||||
static OSStatus rdpsnd_ios_render_cb(
|
static OSStatus rdpsnd_ios_render_cb(
|
||||||
void *inRefCon,
|
void *inRefCon,
|
||||||
AudioUnitRenderActionFlags __unused *ioActionFlags,
|
AudioUnitRenderActionFlags __unused *ioActionFlags,
|
||||||
const AudioTimeStamp __unused *inTimeStamp,
|
const AudioTimeStamp __unused *inTimeStamp,
|
||||||
UInt32 inBusNumber,
|
UInt32 inBusNumber,
|
||||||
UInt32 __unused inNumberFrames,
|
UInt32 __unused inNumberFrames,
|
||||||
AudioBufferList *ioData
|
AudioBufferList *ioData
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (inBusNumber != 0)
|
if (inBusNumber != 0)
|
||||||
{
|
{
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpsndIOSPlugin *p = THIS(inRefCon);
|
rdpsndIOSPlugin *p = THIS(inRefCon);
|
||||||
|
|
||||||
for (i = 0; i < ioData->mNumberBuffers; i++)
|
for (i = 0; i < ioData->mNumberBuffers; i++)
|
||||||
{
|
{
|
||||||
AudioBuffer* target_buffer = &ioData->mBuffers[i];
|
AudioBuffer* target_buffer = &ioData->mBuffers[i];
|
||||||
|
|
||||||
int32_t available_bytes = 0;
|
int32_t available_bytes = 0;
|
||||||
const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
|
const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
|
||||||
if (buffer != NULL && available_bytes > 0)
|
if (buffer != NULL && available_bytes > 0)
|
||||||
{
|
{
|
||||||
const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
|
const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
|
||||||
|
|
||||||
memcpy(target_buffer->mData, buffer, bytes_to_copy);
|
memcpy(target_buffer->mData, buffer, bytes_to_copy);
|
||||||
target_buffer->mDataByteSize = bytes_to_copy;
|
target_buffer->mDataByteSize = bytes_to_copy;
|
||||||
|
|
||||||
TPCircularBufferConsume(&p->buffer, bytes_to_copy);
|
TPCircularBufferConsume(&p->buffer, bytes_to_copy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
target_buffer->mDataByteSize = 0;
|
target_buffer->mDataByteSize = 0;
|
||||||
AudioOutputUnitStop(p->audio_unit);
|
AudioOutputUnitStop(p->audio_unit);
|
||||||
p->is_playing = 0;
|
p->is_playing = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* format)
|
static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* format)
|
||||||
{
|
{
|
||||||
if (format->wFormatTag == WAVE_FORMAT_PCM)
|
if (format->wFormatTag == WAVE_FORMAT_PCM)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency)
|
static void rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency)
|
||||||
|
@ -109,170 +108,170 @@ static void rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __
|
||||||
|
|
||||||
static void rdpsnd_ios_start(rdpsndDevicePlugin* device)
|
static void rdpsnd_ios_start(rdpsndDevicePlugin* device)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = THIS(device);
|
rdpsndIOSPlugin *p = THIS(device);
|
||||||
|
|
||||||
/* If this device is not playing... */
|
/* If this device is not playing... */
|
||||||
if (!p->is_playing)
|
if (!p->is_playing)
|
||||||
{
|
{
|
||||||
/* Start the device. */
|
/* Start the device. */
|
||||||
int32_t available_bytes = 0;
|
int32_t available_bytes = 0;
|
||||||
TPCircularBufferTail(&p->buffer, &available_bytes);
|
TPCircularBufferTail(&p->buffer, &available_bytes);
|
||||||
if (available_bytes > 0)
|
if (available_bytes > 0)
|
||||||
{
|
{
|
||||||
p->is_playing = 1;
|
p->is_playing = 1;
|
||||||
AudioOutputUnitStart(p->audio_unit);
|
AudioOutputUnitStart(p->audio_unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device)
|
static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = THIS(device);
|
rdpsndIOSPlugin *p = THIS(device);
|
||||||
|
|
||||||
/* If the device is playing... */
|
/* If the device is playing... */
|
||||||
if (p->is_playing)
|
if (p->is_playing)
|
||||||
{
|
{
|
||||||
/* Stop the device. */
|
/* Stop the device. */
|
||||||
AudioOutputUnitStop(p->audio_unit);
|
AudioOutputUnitStop(p->audio_unit);
|
||||||
p->is_playing = 0;
|
p->is_playing = 0;
|
||||||
|
|
||||||
/* Free all buffers. */
|
/* Free all buffers. */
|
||||||
TPCircularBufferClear(&p->buffer);
|
TPCircularBufferClear(&p->buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size)
|
static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = THIS(device);
|
rdpsndIOSPlugin *p = THIS(device);
|
||||||
|
|
||||||
const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
|
const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpsnd_ios_start(device);
|
rdpsnd_ios_start(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency)
|
static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = THIS(device);
|
rdpsndIOSPlugin *p = THIS(device);
|
||||||
|
|
||||||
if (p->is_opened)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the output audio unit. */
|
if (p->is_opened)
|
||||||
AudioComponentDescription desc;
|
{
|
||||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
return;
|
||||||
desc.componentType = kAudioUnitType_Output;
|
}
|
||||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
|
||||||
desc.componentFlags = 0;
|
|
||||||
desc.componentFlagsMask = 0;
|
|
||||||
|
|
||||||
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
|
|
||||||
if (audioComponent == NULL) return;
|
|
||||||
|
|
||||||
/* Open the audio unit. */
|
/* Find the output audio unit. */
|
||||||
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
|
AudioComponentDescription desc;
|
||||||
if (status != 0) return;
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||||
|
desc.componentType = kAudioUnitType_Output;
|
||||||
|
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||||
|
desc.componentFlags = 0;
|
||||||
|
desc.componentFlagsMask = 0;
|
||||||
|
|
||||||
/* Set the format for the AudioUnit. */
|
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
|
||||||
AudioStreamBasicDescription audioFormat = {0};
|
if (audioComponent == NULL) return;
|
||||||
audioFormat.mSampleRate = format->nSamplesPerSec;
|
|
||||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
|
||||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
|
||||||
audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */
|
|
||||||
audioFormat.mChannelsPerFrame = format->nChannels;
|
|
||||||
audioFormat.mBitsPerChannel = format->wBitsPerSample;
|
|
||||||
audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
|
|
||||||
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
|
|
||||||
|
|
||||||
status = AudioUnitSetProperty(
|
|
||||||
p->audio_unit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&audioFormat,
|
|
||||||
sizeof(audioFormat));
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
AudioComponentInstanceDispose(p->audio_unit);
|
|
||||||
p->audio_unit = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up the AudioUnit callback. */
|
|
||||||
AURenderCallbackStruct callbackStruct = {0};
|
|
||||||
callbackStruct.inputProc = rdpsnd_ios_render_cb;
|
|
||||||
callbackStruct.inputProcRefCon = p;
|
|
||||||
status = AudioUnitSetProperty(
|
|
||||||
p->audio_unit,
|
|
||||||
kAudioUnitProperty_SetRenderCallback,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&callbackStruct,
|
|
||||||
sizeof(callbackStruct));
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
AudioComponentInstanceDispose(p->audio_unit);
|
|
||||||
p->audio_unit = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the AudioUnit. */
|
/* Open the audio unit. */
|
||||||
status = AudioUnitInitialize(p->audio_unit);
|
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
|
||||||
if (status != 0)
|
if (status != 0) return;
|
||||||
{
|
|
||||||
AudioComponentInstanceDispose(p->audio_unit);
|
|
||||||
p->audio_unit = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate the circular buffer. */
|
|
||||||
const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
AudioUnitUninitialize(p->audio_unit);
|
|
||||||
AudioComponentInstanceDispose(p->audio_unit);
|
|
||||||
p->audio_unit = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->is_opened = 1;
|
/* Set the format for the AudioUnit. */
|
||||||
|
AudioStreamBasicDescription audioFormat = {0};
|
||||||
|
audioFormat.mSampleRate = format->nSamplesPerSec;
|
||||||
|
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
||||||
|
audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */
|
||||||
|
audioFormat.mChannelsPerFrame = format->nChannels;
|
||||||
|
audioFormat.mBitsPerChannel = format->wBitsPerSample;
|
||||||
|
audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
|
||||||
|
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
|
||||||
|
|
||||||
|
status = AudioUnitSetProperty(
|
||||||
|
p->audio_unit,
|
||||||
|
kAudioUnitProperty_StreamFormat,
|
||||||
|
kAudioUnitScope_Input,
|
||||||
|
0,
|
||||||
|
&audioFormat,
|
||||||
|
sizeof(audioFormat));
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
AudioComponentInstanceDispose(p->audio_unit);
|
||||||
|
p->audio_unit = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the AudioUnit callback. */
|
||||||
|
AURenderCallbackStruct callbackStruct = {0};
|
||||||
|
callbackStruct.inputProc = rdpsnd_ios_render_cb;
|
||||||
|
callbackStruct.inputProcRefCon = p;
|
||||||
|
status = AudioUnitSetProperty(
|
||||||
|
p->audio_unit,
|
||||||
|
kAudioUnitProperty_SetRenderCallback,
|
||||||
|
kAudioUnitScope_Input,
|
||||||
|
0,
|
||||||
|
&callbackStruct,
|
||||||
|
sizeof(callbackStruct));
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
AudioComponentInstanceDispose(p->audio_unit);
|
||||||
|
p->audio_unit = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the AudioUnit. */
|
||||||
|
status = AudioUnitInitialize(p->audio_unit);
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
AudioComponentInstanceDispose(p->audio_unit);
|
||||||
|
p->audio_unit = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the circular buffer. */
|
||||||
|
const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
AudioUnitUninitialize(p->audio_unit);
|
||||||
|
AudioComponentInstanceDispose(p->audio_unit);
|
||||||
|
p->audio_unit = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->is_opened = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_ios_close(rdpsndDevicePlugin* device)
|
static void rdpsnd_ios_close(rdpsndDevicePlugin* device)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = THIS(device);
|
rdpsndIOSPlugin *p = THIS(device);
|
||||||
|
|
||||||
/* Make sure the device is stopped. */
|
/* Make sure the device is stopped. */
|
||||||
rdpsnd_ios_stop(device);
|
rdpsnd_ios_stop(device);
|
||||||
|
|
||||||
/* If the device is open... */
|
/* If the device is open... */
|
||||||
if (p->is_opened)
|
if (p->is_opened)
|
||||||
{
|
{
|
||||||
/* Close the device. */
|
/* Close the device. */
|
||||||
AudioUnitUninitialize(p->audio_unit);
|
AudioUnitUninitialize(p->audio_unit);
|
||||||
AudioComponentInstanceDispose(p->audio_unit);
|
AudioComponentInstanceDispose(p->audio_unit);
|
||||||
p->audio_unit = NULL;
|
p->audio_unit = NULL;
|
||||||
p->is_opened = 0;
|
p->is_opened = 0;
|
||||||
|
|
||||||
/* Destroy the circular buffer. */
|
/* Destroy the circular buffer. */
|
||||||
TPCircularBufferCleanup(&p->buffer);
|
TPCircularBufferCleanup(&p->buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
|
static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = THIS(device);
|
rdpsndIOSPlugin *p = THIS(device);
|
||||||
|
|
||||||
/* Ensure the device is closed. */
|
/* Ensure the device is closed. */
|
||||||
rdpsnd_ios_close(device);
|
rdpsnd_ios_close(device);
|
||||||
|
|
||||||
/* Free memory associated with the device. */
|
/* Free memory associated with the device. */
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STATIC_CHANNELS
|
#ifdef STATIC_CHANNELS
|
||||||
|
@ -281,19 +280,21 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
|
||||||
|
|
||||||
int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
|
int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||||
{
|
{
|
||||||
rdpsndIOSPlugin *p = (rdpsndIOSPlugin*)malloc(sizeof(rdpsndIOSPlugin));
|
rdpsndIOSPlugin* p = (rdpsndIOSPlugin*) calloc(1, sizeof(rdpsndIOSPlugin));
|
||||||
memset(p, 0, sizeof(rdpsndIOSPlugin));
|
|
||||||
|
if (!p)
|
||||||
p->device.Open = rdpsnd_ios_open;
|
return -1;
|
||||||
p->device.FormatSupported = rdpsnd_ios_format_supported;
|
|
||||||
p->device.SetFormat = rdpsnd_ios_set_format;
|
p->device.Open = rdpsnd_ios_open;
|
||||||
p->device.SetVolume = rdpsnd_ios_set_volume;
|
p->device.FormatSupported = rdpsnd_ios_format_supported;
|
||||||
p->device.Play = rdpsnd_ios_play;
|
p->device.SetFormat = rdpsnd_ios_set_format;
|
||||||
p->device.Start = rdpsnd_ios_start;
|
p->device.SetVolume = rdpsnd_ios_set_volume;
|
||||||
p->device.Close = rdpsnd_ios_close;
|
p->device.Play = rdpsnd_ios_play;
|
||||||
p->device.Free = rdpsnd_ios_free;
|
p->device.Start = rdpsnd_ios_start;
|
||||||
|
p->device.Close = rdpsnd_ios_close;
|
||||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
|
p->device.Free = rdpsnd_ios_free;
|
||||||
|
|
||||||
return 0;
|
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
|
||||||
}
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -31,18 +31,15 @@ include_directories(${MACAUDIO_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-utils)
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
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)
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
|
|
||||||
#include <freerdp/types.h>
|
#include <freerdp/types.h>
|
||||||
#include <freerdp/codec/dsp.h>
|
#include <freerdp/codec/dsp.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
|
||||||
|
|
||||||
#include <AudioToolbox/AudioToolbox.h>
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
#include <AudioToolbox/AudioQueue.h>
|
#include <AudioToolbox/AudioQueue.h>
|
||||||
|
@ -122,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,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++)
|
||||||
|
@ -145,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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,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;
|
||||||
|
@ -282,23 +281,21 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||||
{
|
{
|
||||||
rdpsndMacPlugin* mac;
|
rdpsndMacPlugin* mac;
|
||||||
|
|
||||||
mac = (rdpsndMacPlugin*) malloc(sizeof(rdpsndMacPlugin));
|
mac = (rdpsndMacPlugin*) calloc(1, sizeof(rdpsndMacPlugin));
|
||||||
|
|
||||||
if (mac)
|
if (!mac)
|
||||||
{
|
return -1;
|
||||||
ZeroMemory(mac, sizeof(rdpsndMacPlugin));
|
|
||||||
|
|
||||||
mac->device.Open = rdpsnd_mac_open;
|
mac->device.Open = rdpsnd_mac_open;
|
||||||
mac->device.FormatSupported = rdpsnd_mac_format_supported;
|
mac->device.FormatSupported = rdpsnd_mac_format_supported;
|
||||||
mac->device.SetFormat = rdpsnd_mac_set_format;
|
mac->device.SetFormat = rdpsnd_mac_set_format;
|
||||||
mac->device.SetVolume = rdpsnd_mac_set_volume;
|
mac->device.SetVolume = rdpsnd_mac_set_volume;
|
||||||
mac->device.Play = rdpsnd_mac_play;
|
mac->device.Play = rdpsnd_mac_play;
|
||||||
mac->device.Start = rdpsnd_mac_start;
|
mac->device.Start = rdpsnd_mac_start;
|
||||||
mac->device.Close = rdpsnd_mac_close;
|
mac->device.Close = rdpsnd_mac_close;
|
||||||
mac->device.Free = rdpsnd_mac_free;
|
mac->device.Free = rdpsnd_mac_free;
|
||||||
|
|
||||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
|
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,9 @@ include_directories(${OPENSLES_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||||
|
|
||||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
|
||||||
|
|
||||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|
||||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
|
||||||
MODULE freerdp
|
|
||||||
MODULES freerdp-codec freerdp-utils
|
|
||||||
${OPENSLES_LIBRARIES})
|
|
||||||
|
|
||||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OPENSLES_LIBRARIES})
|
set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES})
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue