Debian release 2.0.0~git20180411.1.7a7b1802+dfsg1-2
-----BEGIN PGP SIGNATURE----- iQJVBAABCAA/FiEEm/uu6GwKpf+/IgeCmvRrMCV3GzEFAlr67DEhHG1pa2UuZ2Fi cmllbEBkYXMtbmV0endlcmt0ZWFtLmRlAAoJEJr0azAldxsxmnYP+gKvhwEKMTJW rIo7GQM7CRhTH2Zo1ITCA4ybYtwTn8qhTUcfx0DzeYaB2sRU/PtYa/J3Xo5j3FUe yKQmEivZxzjyLlZUAI8B3pQcVg6huI+WZq7somRteQDqFtBkwDVyqOTiAJNnvA5l xx0wzsUtKfupU6zLmltGxIzsv3vJFsYq3NG+5OLgGI3Ae03QAGs5gLcp2snN6o0P Ea8x5V5Np/slTli5DgDNW/UQ2HEf65w8gmd/vo+44DWqnz6k7kil+WHxVUHKcXvL bFg6+OaPP3GTHdY8+ZBlo56U8+8HJbIkTLFu+sDOr5BFJL92N5DUluOeHIRxKoix bchKYZold/VuTD5/fPIURWNah6bVY29CKJmbFgzaq/Q4iWaUKxbdHZqcq+25Tm1V nmuTt5eHwoQOdDDV3EvEE6t1Jyo4jLgwqPQZ9q6Ds4bSLwvhzXEcqH6aF05Xcttr s2SCErZ3YLtzWPQyL6KfWA14rfcqsAi8XIZq0YHYhZvtk+IntnSAujqb175H3uXI sX3ZQUF0cJ62ho7nAsAOUqjRARuNEQB/3r500DKBP7YNIi+4itUn2FembAl6XVsx hGNrv4wzAiffnu/cmsNpMWoxWzfe5GEyhOtNyMc55h6vf/91UIhPDEsOi6LeMb0f UuyQr354Fagv+/ZEtqnZWDw3ua7kivEy =QQTz -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- Comment: Debian powered! iQKTBAABCgB9FiEE890J+NqH0d9QRsmbBhL0lE7NzVoFAlsDLbxfFIAAAAAALgAo aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEYz REQwOUY4REE4N0QxREY1MDQ2Qzk5QjA2MTJGNDk0NEVDRENENUEACgkQBhL0lE7N zVqA0xAAspmdmkPNbO36T0WRcXlKs4pxq4z+kbgBccMs/NB341Xk/AZdRYoou3St gCBhqlQpWqeXTyb8uSeCpMZywmaNTlZqm/8zED2xD2sXujTO9z628D+DYiueqIK6 nEiKvSe+GPNHTf69bfmcM1GFwKVkFM0ViR+/Jdzp201gbcvrmFfNxgtvdhBKsU88 gjfzVicTZd6bPBA5weMOKLKEbiCuXp0Hx/V2fSqYC62ep6lKppHBcgbGZ1zlBrgi aGtUS5kCBbXAdDCQWgE8zEf75FSnsH042LgR9UcNaHn3etYWREnfpOu49j/l8Oro PoevzSSc6e6QqQAE4PUwMj7kffIbpFF2/ovVaczsDbjPaTr7qpdF6at1bqujgBw+ WEinCGKlM2ogGQxa2mi/ToZGJM66DwF6WPFL25RbWV73xZuOlodo3btfNiO/egz/ /whD96gBMZ6lEgCvg8rKeEFk7I3VSWCCxEOox/HgHSEXOBhtFo3UDZXUB1Q8Rt4l NIZmWLbFpCjtbc5xJ1obSC8RWC3ibiYzdtpgBP9zd6qUdgkLO6is1BYMcWFeSn9W GQcoBOc/h+Xdrw3EpEfR0fBv2IvCeiYbXIuUS5QyUkoEW/jGYONyb6MUa+YjztdN 402tB/57mEUPcq6fav5D8hmb5kiHYoxfXBbEGfd/e1JIVQFoLdI= =M36K -----END PGP SIGNATURE----- Merge tag 'debian/2.0.0_git20180411.1.7a7b1802+dfsg1-2' into stretch-backports Debian release 2.0.0~git20180411.1.7a7b1802+dfsg1-2
This commit is contained in:
commit
97ca4d06b0
54
.travis.yml
Normal file
54
.travis.yml
Normal file
@ -0,0 +1,54 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
os: linux
|
||||
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
compiler: clang
|
||||
exclude:
|
||||
- compiler: gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gdb
|
||||
- libx11-dev
|
||||
- libxrandr-dev
|
||||
- libxi-dev
|
||||
- libxv-dev
|
||||
- libcups2-dev
|
||||
- libxdamage-dev
|
||||
- libxcursor-dev
|
||||
- libxext-dev
|
||||
- libxinerama-dev
|
||||
- libxkbcommon-dev
|
||||
- libxkbfile-dev
|
||||
- libxml2-dev
|
||||
- libasound2-dev
|
||||
- libgstreamer1.0-dev
|
||||
- libgstreamer-plugins-base1.0-dev
|
||||
- libpulse-dev
|
||||
- libpcsclite-dev
|
||||
- libgsm1-dev
|
||||
- libavcodec-dev
|
||||
- libavutil-dev
|
||||
- libx264-dev
|
||||
- libxext-dev
|
||||
|
||||
before_script:
|
||||
- ulimit -c unlimited -S
|
||||
|
||||
script:
|
||||
- sudo hostname travis-ci.local
|
||||
- cmake -G "Unix Makefiles" -C ci/cmake-preloads/config-linux-all.txt -D CMAKE_BUILD_TYPE=Debug -DWITH_LIBSYSTEMD=OFF -DWITH_WAYLAND=OFF .
|
||||
- make
|
||||
- make test
|
||||
181
CMakeLists.txt
181
CMakeLists.txt
@ -59,7 +59,6 @@ include(FindPkgConfig)
|
||||
include(TestBigEndian)
|
||||
|
||||
include(FindFeature)
|
||||
include(AutoVersioning)
|
||||
include(ConfigOptions)
|
||||
include(ComplexLibrary)
|
||||
include(FeatureSummary)
|
||||
@ -68,6 +67,7 @@ include(CheckCXXCompilerFlag)
|
||||
include(GNUInstallDirsWrapper)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(InstallFreeRDPMan)
|
||||
include(GetGitRevisionDescription)
|
||||
|
||||
# Soname versioning
|
||||
set(BUILD_NUMBER 0)
|
||||
@ -75,10 +75,24 @@ if ($ENV{BUILD_NUMBER})
|
||||
set(BUILD_NUMBER $ENV{BUILD_NUMBER})
|
||||
endif()
|
||||
set(WITH_LIBRARY_VERSIONING "ON")
|
||||
set(FREERDP_VERSION_MAJOR "2")
|
||||
set(FREERDP_VERSION_MINOR "0")
|
||||
set(FREERDP_VERSION_REVISION "0")
|
||||
set(FREERDP_VERSION_SUFFIX "dev")
|
||||
|
||||
set(RAW_VERSTION_STRING "2.0.0-rc2")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSTION_STRING)
|
||||
elseif(USE_VERSION_FROM_GIT_TAG)
|
||||
git_get_exact_tag(_GIT_TAG --tags --always)
|
||||
if (NOT ${_GIT_TAG} STREQUAL "n/a")
|
||||
set(RAW_VERSTION_STRING ${_GIT_TAG})
|
||||
endif()
|
||||
endif()
|
||||
string(STRIP ${RAW_VERSTION_STRING} RAW_VERSTION_STRING)
|
||||
|
||||
set(VERSION_REGEX "^.?([0-9]+)\\.([0-9]+)\\.([0-9]+)-?(.*)")
|
||||
string(REGEX REPLACE "${VERSION_REGEX}" "\\1" FREERDP_VERSION_MAJOR "${RAW_VERSTION_STRING}")
|
||||
string(REGEX REPLACE "${VERSION_REGEX}" "\\2" FREERDP_VERSION_MINOR "${RAW_VERSTION_STRING}")
|
||||
string(REGEX REPLACE "${VERSION_REGEX}" "\\3" FREERDP_VERSION_REVISION "${RAW_VERSTION_STRING}")
|
||||
string(REGEX REPLACE "${VERSION_REGEX}" "\\4" FREERDP_VERSION_SUFFIX "${RAW_VERSTION_STRING}")
|
||||
|
||||
set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}")
|
||||
set(FREERDP_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}.${FREERDP_VERSION_REVISION}")
|
||||
if (FREERDP_VERSION_SUFFIX)
|
||||
@ -86,6 +100,8 @@ if (FREERDP_VERSION_SUFFIX)
|
||||
else()
|
||||
set(FREERDP_VERSION_FULL "${FREERDP_VERSION}")
|
||||
endif()
|
||||
message("FREERDP_VERSION=${FREERDP_VERSION_FULL}")
|
||||
|
||||
set(FREERDP_INCLUDE_DIR "include/freerdp${FREERDP_VERSION_MAJOR}/")
|
||||
|
||||
# Compatibility options
|
||||
@ -102,26 +118,42 @@ if (FREERDP_EXTERNAL_PATH)
|
||||
get_filename_component (FREERDP_EXTERNAL_PATH "${FREERDP_EXTERNAL_PATH}" ABSOLUTE)
|
||||
endif()
|
||||
|
||||
# Allow to search the host machine for git
|
||||
# Allow to search the host machine for git/ccache
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
|
||||
endif(CMAKE_CROSSCOMPILING)
|
||||
|
||||
find_program(CCACHE ccache)
|
||||
if(CCACHE AND WITH_CCACHE)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.3.2)
|
||||
if(NOT DEFINED CMAKE_C_COMPILER_LAUNCHER)
|
||||
SET(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
||||
endif(NOT DEFINED CMAKE_C_COMPILER_LAUNCHER)
|
||||
if(NOT DEFINED CMAKE_CXX_COMPILER_LAUNCHER)
|
||||
SET(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
||||
endif(NOT DEFINED CMAKE_CXX_COMPILER_LAUNCHER)
|
||||
else()
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
|
||||
endif()
|
||||
endif(CCACHE AND WITH_CCACHE)
|
||||
|
||||
include(GetGitRevisionDescription)
|
||||
git_get_exact_tag(GIT_REVISION --tags --always)
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_version" )
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_version GIT_REVISION)
|
||||
|
||||
if (${GIT_REVISION} STREQUAL "n/a")
|
||||
git_rev_parse (GIT_REVISION --short)
|
||||
string(STRIP ${GIT_REVISION} GIT_REVISION)
|
||||
else()
|
||||
git_get_exact_tag(GIT_REVISION --tags --always)
|
||||
|
||||
if (${GIT_REVISION} STREQUAL "n/a")
|
||||
git_rev_parse (GIT_REVISION --short)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
endif(CMAKE_CROSSCOMPILING)
|
||||
# /Allow to search the host machine for git/ccache
|
||||
|
||||
message(STATUS "Git Revision ${GIT_REVISION}")
|
||||
|
||||
@ -158,6 +190,9 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "BSD")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
set(FREEBSD TRUE)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "kFreeBSD")
|
||||
set(KFREEBSD TRUE)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||
set(OPENBSD TRUE)
|
||||
endif()
|
||||
@ -189,6 +224,11 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
add_definitions("-D_FILE_OFFSET_BITS=64")
|
||||
endif()
|
||||
|
||||
# Use Standard conforming getpwnam_r() on Solaris.
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
|
||||
add_definitions("-D_POSIX_PTHREAD_SEMANTICS")
|
||||
endif()
|
||||
|
||||
# Compiler-specific flags
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
|
||||
@ -252,9 +292,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||
endif()
|
||||
if(WITH_SSE2)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# When building with Unix Makefiles and doing any release builds
|
||||
@ -278,9 +315,7 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-macros -Wno-padded")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-c11-extensions -Wno-gnu")
|
||||
if(WITH_SSE2)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mssse3")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-command-line-argument")
|
||||
CHECK_C_COMPILER_FLAG(-Wno-deprecated-declarations Wno-deprecated-declarations)
|
||||
if(Wno-deprecated-declarations)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
|
||||
@ -300,7 +335,14 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
|
||||
CHECK_C_COMPILER_FLAG ("-fsanitize=address" fsanitize-address)
|
||||
if(fsanitize-address)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||
if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
else()
|
||||
message(FATAL_ERROR "Missing support for address sanitizer!")
|
||||
endif()
|
||||
if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS)
|
||||
set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
|
||||
@ -312,14 +354,47 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCC)
|
||||
if(fno-omit-frame-pointer)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer")
|
||||
endif()
|
||||
elseif(WITH_SANITIZE_LEAK)
|
||||
elseif(WITH_SANITIZE_MEMORY)
|
||||
if (DEFINED CMAKE_REQUIRED_FLAGS)
|
||||
set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_FLAGS "-fsanitize=leak")
|
||||
CHECK_C_COMPILER_FLAG ("-fsanitize=leak" fsanitize-leak)
|
||||
if(fsanitize-leak)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=leak")
|
||||
set(CMAKE_REQUIRED_FLAGS "-fsanitize=memory")
|
||||
CHECK_C_COMPILER_FLAG ("-fsanitize=memory" fsanitize-memory)
|
||||
if(fsanitize-memory)
|
||||
if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory")
|
||||
else()
|
||||
message(FATAL_ERROR "Missing support for memory sanitizer!")
|
||||
endif()
|
||||
if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS)
|
||||
set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
|
||||
else()
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
endif()
|
||||
|
||||
CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer)
|
||||
if(fno-omit-frame-pointer)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer")
|
||||
endif()
|
||||
elseif(WITH_SANITIZE_THREAD)
|
||||
if (DEFINED CMAKE_REQUIRED_FLAGS)
|
||||
set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_FLAGS "-fsanitize=thread")
|
||||
CHECK_C_COMPILER_FLAG ("-fsanitize=thread" fsanitize-thread)
|
||||
if(fsanitize-thread)
|
||||
if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
|
||||
else()
|
||||
message(FATAL_ERROR "Missing support for thread sanitizer!")
|
||||
endif()
|
||||
if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS)
|
||||
set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
|
||||
@ -399,7 +474,7 @@ if(WIN32)
|
||||
elseif (${CMAKE_GENERATOR} MATCHES "Visual Studio*")
|
||||
set(CMAKE_PDB_BINARY_DIR "${CMAKE_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}")
|
||||
else()
|
||||
message(FATAL "Unknown generator ${CMAKE_GENERATOR}")
|
||||
message(FATAL_ERROR "Unknown generator ${CMAKE_GENERATOR}")
|
||||
endif()
|
||||
|
||||
# Set product and vendor for dll and exe version information.
|
||||
@ -566,12 +641,12 @@ else()
|
||||
endif()
|
||||
|
||||
if(UNIX OR CYGWIN)
|
||||
check_include_files(sys/eventfd.h HAVE_AIO_H)
|
||||
check_include_files(sys/eventfd.h HAVE_EVENTFD_H)
|
||||
if (HAVE_EVENTFD_H)
|
||||
check_include_files(aio.h HAVE_AIO_H)
|
||||
check_include_files(sys/eventfd.h HAVE_SYS_EVENTFD_H)
|
||||
if (HAVE_SYS_EVENTFD_H)
|
||||
check_symbol_exists(eventfd_read sys/eventfd.h WITH_EVENTFD_READ_WRITE)
|
||||
endif()
|
||||
check_include_files(sys/timerfd.h HAVE_TIMERFD_H)
|
||||
check_include_files(sys/timerfd.h HAVE_SYS_TIMERFD_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
|
||||
check_symbol_exists(ceill math.h HAVE_MATH_C99_LONG_DOUBLE)
|
||||
@ -637,6 +712,10 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED")
|
||||
set(FFMPEG_FEATURE_PURPOSE "multimedia")
|
||||
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
|
||||
set(VAAPI_FEATURE_TYPE "OPTIONAL")
|
||||
set(VAAPI_FEATURE_PURPOSE "multimedia")
|
||||
set(VAAPI_FEATURE_DESCRIPTION "VA-API hardware acceleration for video playback")
|
||||
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
|
||||
@ -661,14 +740,14 @@ set(OPENH264_FEATURE_TYPE "OPTIONAL")
|
||||
set(OPENH264_FEATURE_PURPOSE "codec")
|
||||
set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library")
|
||||
|
||||
set(KRB5_FEATURE_TYPE "OPTIONAL")
|
||||
set(KRB5_FEATURE_PURPOSE "auth")
|
||||
set(KRB5_FEATURE_DESCRIPTION "add kerberos support")
|
||||
|
||||
set(GSM_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSM_FEATURE_PURPOSE "codec")
|
||||
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
|
||||
|
||||
set(GSSAPI_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSSAPI_FEATURE_PURPOSE "auth")
|
||||
set(GSSAPI_FEATURE_DESCRIPTION "add kerberos support")
|
||||
|
||||
if(WIN32)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||
@ -680,6 +759,7 @@ if(WIN32)
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(VAAPI_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||
@ -688,6 +768,7 @@ endif()
|
||||
if(APPLE)
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||
set(VAAPI_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
|
||||
set(X11_FEATURE_TYPE "OPTIONAL")
|
||||
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||
@ -729,6 +810,7 @@ if(ANDROID)
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(VAAPI_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||
set(OPENSLES_FEATURE_TYPE "REQUIRED")
|
||||
@ -762,7 +844,25 @@ find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DE
|
||||
find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_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(KRB5 ${KRB5_FEATURE_TYPE} ${KRB5_FEATURE_PURPOSE} ${KRB5_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION})
|
||||
|
||||
if ( (WITH_GSSAPI) AND (NOT GSS_FOUND))
|
||||
message(WARNING "-DWITH_GSSAPI=ON is set, but not GSSAPI implementation was found, disabling")
|
||||
elseif(WITH_GSSAPI)
|
||||
if(GSS_FLAVOUR STREQUAL "MIT")
|
||||
add_definitions("-DWITH_GSSAPI -DWITH_GSSAPI_MIT")
|
||||
if(GSS_VERSION_1_13)
|
||||
add_definitions("-DHAVE_AT_LEAST_KRB_V1_13")
|
||||
endif()
|
||||
include_directories(${_GSS_INCLUDE_DIR})
|
||||
elseif(GSS_FLAVOUR STREQUAL "Heimdal")
|
||||
add_definitions("-DWITH_GSSAPI -DWITH_GSSAPI_HEIMDAL")
|
||||
include_directories(${_GSS_INCLUDE_DIR})
|
||||
else()
|
||||
message(WARNING "Kerberos version not detected")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(TARGET_ARCH MATCHES "x86|x64")
|
||||
if (NOT APPLE)
|
||||
@ -819,14 +919,15 @@ add_definitions("-DHAVE_CONFIG_H")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
# RPATH configuration
|
||||
if(CMAKE_SKIP_RPATH)
|
||||
set(CMAKE_SKIP_RPATH FALSE)
|
||||
set(CMAKE_SKIP_INSTALL_RPATH TRUE)
|
||||
endif()
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..")
|
||||
if (APPLE)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
||||
else (APPLE)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..")
|
||||
endif(APPLE)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set(CMAKE_MACOSX_RPATH ON)
|
||||
|
||||
6
README
6
README
@ -11,9 +11,9 @@ Resources
|
||||
Project website: http://www.freerdp.com/
|
||||
Issue tracker: https://github.com/FreeRDP/FreeRDP/issues
|
||||
Sources: https://github.com/FreeRDP/FreeRDP/
|
||||
Downloads: https://pub.freerdp.com/releases/
|
||||
Wiki: https://github.com/FreeRDP/FreeRDP/wiki
|
||||
Downloads and other resources: http://pub.freerdp.com
|
||||
API doc: http://pub.freerdp.com/api/
|
||||
API documentation: https://pub.freerdp.com/api/
|
||||
|
||||
IRC channel: #freerdp @ irc.freenode.net
|
||||
Mailing list: https://lists.sourceforge.net/lists/listinfo/freerdp-devel
|
||||
@ -32,5 +32,3 @@ Compilation
|
||||
|
||||
Instructions on how to get started compiling FreeRDP can be found on the wiki:
|
||||
https://github.com/FreeRDP/FreeRDP/wiki/Compilation
|
||||
|
||||
|
||||
|
||||
@ -219,7 +219,7 @@ static UINT audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* audin_alsa_thread_func(void* arg)
|
||||
static DWORD WINAPI audin_alsa_thread_func(LPVOID arg)
|
||||
{
|
||||
long error;
|
||||
BYTE* buffer;
|
||||
@ -300,8 +300,8 @@ out:
|
||||
setChannelError(alsa->rdpcontext, error,
|
||||
"audin_alsa_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,7 +427,7 @@ static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive,
|
||||
}
|
||||
|
||||
if (!(alsa->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_alsa_thread_func, alsa, 0, NULL)))
|
||||
audin_alsa_thread_func, alsa, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
goto error_out;
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -31,10 +32,10 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include <freerdp/addin.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include "audin_main.h"
|
||||
|
||||
@ -70,7 +71,7 @@ struct _AUDIN_CHANNEL_CALLBACK
|
||||
* Open PDU and Format Change PDU
|
||||
*/
|
||||
audinFormat* formats;
|
||||
int formats_count;
|
||||
UINT32 formats_count;
|
||||
};
|
||||
|
||||
typedef struct _AUDIN_PLUGIN AUDIN_PLUGIN;
|
||||
@ -92,37 +93,45 @@ struct _AUDIN_PLUGIN
|
||||
|
||||
rdpContext* rdpcontext;
|
||||
BOOL attached;
|
||||
wLog* log;
|
||||
};
|
||||
|
||||
static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args);
|
||||
|
||||
static UINT audin_write_and_free_stream(AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
UINT error = ERROR_INTERNAL_ERROR;
|
||||
const size_t length = Stream_GetPosition(s);
|
||||
const BYTE* data = Stream_Buffer(s);
|
||||
|
||||
if (callback && callback->channel && callback->channel->Write)
|
||||
error = callback->channel->Write(callback->channel, length, data, NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
UINT error;
|
||||
wStream* out;
|
||||
UINT32 Version;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
Stream_Read_UINT32(s, Version);
|
||||
DEBUG_DVC("Version=%"PRIu32"", Version);
|
||||
out = Stream_New(NULL, 5);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
|
||||
Stream_Write_UINT32(out, Version);
|
||||
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out),
|
||||
Stream_Buffer(out), NULL);
|
||||
Stream_Free(out, TRUE);
|
||||
return error;
|
||||
return audin_write_and_free_stream(callback, out);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,11 +139,13 @@ static UINT audin_process_version(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
static UINT audin_send_incoming_data_pdu(AUDIN_CHANNEL_CALLBACK* callback)
|
||||
{
|
||||
BYTE out_data[1];
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
out_data[0] = MSG_SNDIN_DATA_INCOMING;
|
||||
BYTE out_data[1] = { MSG_SNDIN_DATA_INCOMING };
|
||||
|
||||
if (!callback || !callback->channel || !callback->channel->Write)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
return callback->channel->Write(callback->channel, 1, out_data, NULL);
|
||||
}
|
||||
|
||||
@ -143,23 +154,25 @@ static UINT audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCal
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
|
||||
UINT32 i;
|
||||
BYTE* fm;
|
||||
UINT error;
|
||||
wStream* out;
|
||||
UINT32 NumFormats;
|
||||
audinFormat format;
|
||||
UINT32 cbSizeFormatsPacket;
|
||||
size_t cbSizeFormatsPacket;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, NumFormats);
|
||||
DEBUG_DVC("NumFormats %"PRIu32"", NumFormats);
|
||||
|
||||
if ((NumFormats < 1) || (NumFormats > 1000))
|
||||
{
|
||||
WLog_ERR(TAG, "bad NumFormats %"PRIu32"", NumFormats);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %"PRIu32"", NumFormats);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
@ -168,7 +181,7 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
|
||||
if (!callback->formats)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
@ -177,7 +190,7 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
if (!out)
|
||||
{
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -186,6 +199,9 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
/* SoundFormats (variable) */
|
||||
for (i = 0; i < NumFormats; i++)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 18)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_GetPointer(s, fm);
|
||||
Stream_Read_UINT16(s, format.wFormatTag);
|
||||
Stream_Read_UINT16(s, format.nChannels);
|
||||
@ -195,6 +211,10 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
Stream_Read_UINT16(s, format.wBitsPerSample);
|
||||
Stream_Read_UINT16(s, format.cbSize);
|
||||
format.data = Stream_Pointer(s);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < format.cbSize)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_Seek(s, format.cbSize);
|
||||
DEBUG_DVC("wFormatTag=%"PRIu16" nChannels=%"PRIu16" nSamplesPerSec=%"PRIu32" "
|
||||
"nBlockAlign=%"PRIu16" wBitsPerSample=%"PRIu16" cbSize=%"PRIu16"",
|
||||
@ -220,7 +240,7 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
if (!Stream_EnsureRemainingCapacity(out, 18 + format.cbSize))
|
||||
{
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -228,18 +248,19 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = audin_send_incoming_data_pdu(pChannelCallback)))
|
||||
if ((error = audin_send_incoming_data_pdu(callback)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_send_incoming_data_pdu failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out);
|
||||
cbSizeFormatsPacket = Stream_GetPosition(out);
|
||||
Stream_SetPosition(out, 0);
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
|
||||
Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */
|
||||
Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
|
||||
error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, Stream_Buffer(out), NULL);
|
||||
Stream_SetPosition(out, cbSizeFormatsPacket);
|
||||
error = audin_write_and_free_stream(callback, out);
|
||||
out:
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
@ -248,7 +269,6 @@ out:
|
||||
callback->formats = NULL;
|
||||
}
|
||||
|
||||
Stream_Free(out, TRUE);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -257,25 +277,20 @@ out:
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
|
||||
UINT32 NewFormat)
|
||||
{
|
||||
UINT error;
|
||||
wStream* out;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
out = Stream_New(NULL, 5);
|
||||
wStream* out = Stream_New(NULL, 5);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_FORMATCHANGE);
|
||||
Stream_Write_UINT32(out, NewFormat);
|
||||
error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL);
|
||||
Stream_Free(out, TRUE);
|
||||
return error;
|
||||
return audin_write_and_free_stream(callback, out);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,24 +298,20 @@ static UINT audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCal
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Result)
|
||||
static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
|
||||
UINT32 Result)
|
||||
{
|
||||
UINT error;
|
||||
wStream* out;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
out = Stream_New(NULL, 5);
|
||||
wStream* out = Stream_New(NULL, 5);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_OPEN_REPLY);
|
||||
Stream_Write_UINT32(out, Result);
|
||||
error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL);
|
||||
Stream_Free(out, TRUE);
|
||||
return error;
|
||||
return audin_write_and_free_stream(callback, out);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,9 +337,9 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data)
|
||||
if (!audin->attached)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
if ((error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback)))
|
||||
if ((error = audin_send_incoming_data_pdu(callback)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_send_incoming_data_pdu failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!");
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -336,16 +347,13 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data)
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_DATA);
|
||||
Stream_Write(out, data, size);
|
||||
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out),
|
||||
Stream_Buffer(out), NULL);
|
||||
Stream_Free(out, TRUE);
|
||||
return error;
|
||||
return audin_write_and_free_stream(callback, out);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,14 +361,19 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
|
||||
audinFormat* format;
|
||||
UINT32 initialFormat;
|
||||
UINT32 FramesPerPacket;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!audin || !callback || !s)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, FramesPerPacket);
|
||||
Stream_Read_UINT32(s, initialFormat);
|
||||
DEBUG_DVC("FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"",
|
||||
@ -368,8 +381,8 @@ static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wSt
|
||||
|
||||
if (initialFormat >= (UINT32) callback->formats_count)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)",
|
||||
initialFormat, callback->formats_count);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)",
|
||||
initialFormat, callback->formats_count);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
@ -381,7 +394,7 @@ static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wSt
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "SetFormat failed with errorcode %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -389,19 +402,19 @@ static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wSt
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Open failed with errorcode %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = audin_send_format_change_pdu(pChannelCallback, initialFormat)))
|
||||
if ((error = audin_send_format_change_pdu(audin, callback, initialFormat)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_send_format_change_pdu failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_send_format_change_pdu failed!");
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((error = audin_send_open_reply_pdu(pChannelCallback, 0)))
|
||||
WLog_ERR(TAG, "audin_send_open_reply_pdu failed!");
|
||||
if ((error = audin_send_open_reply_pdu(audin, callback, 0)))
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_send_open_reply_pdu failed!");
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -411,20 +424,26 @@ static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wSt
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
|
||||
wStream* s)
|
||||
{
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
|
||||
UINT32 NewFormat;
|
||||
audinFormat* format;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!audin || !callback || !s)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, NewFormat);
|
||||
DEBUG_DVC("NewFormat=%"PRIu32"", NewFormat);
|
||||
|
||||
if (NewFormat >= (UINT32) callback->formats_count)
|
||||
if (NewFormat >= callback->formats_count)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)",
|
||||
NewFormat, callback->formats_count);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)",
|
||||
NewFormat, callback->formats_count);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
@ -436,7 +455,7 @@ static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCall
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -444,7 +463,7 @@ static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCall
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "SetFormat failed with errorcode %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -452,13 +471,13 @@ static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCall
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Open failed with errorcode %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = audin_send_format_change_pdu(pChannelCallback, NewFormat)))
|
||||
WLog_ERR(TAG, "audin_send_format_change_pdu failed!");
|
||||
if ((error = audin_send_format_change_pdu(audin, callback, NewFormat)))
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_send_format_change_pdu failed!");
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -472,29 +491,43 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
{
|
||||
UINT error;
|
||||
BYTE MessageId;
|
||||
AUDIN_PLUGIN* audin;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
if (!callback || !data)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
audin = (AUDIN_PLUGIN*) callback->plugin;
|
||||
|
||||
if (!audin)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (Stream_GetRemainingCapacity(data) < 1)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_Read_UINT8(data, MessageId);
|
||||
DEBUG_DVC("MessageId=0x%02"PRIx8"", MessageId);
|
||||
|
||||
switch (MessageId)
|
||||
{
|
||||
case MSG_SNDIN_VERSION:
|
||||
error = audin_process_version(pChannelCallback, data);
|
||||
error = audin_process_version(audin, callback, data);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATS:
|
||||
error = audin_process_formats(pChannelCallback, data);
|
||||
error = audin_process_formats(audin, callback, data);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_OPEN:
|
||||
error = audin_process_open(pChannelCallback, data);
|
||||
error = audin_process_open(audin, callback, data);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATCHANGE:
|
||||
error = audin_process_format_change(pChannelCallback, data);
|
||||
error = audin_process_format_change(audin, callback, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown MessageId=0x%02"PRIx8"", MessageId);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02"PRIx8"", MessageId);
|
||||
error = ERROR_INVALID_DATA;
|
||||
break;
|
||||
}
|
||||
@ -519,7 +552,7 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
IFCALLRET(audin->device->Close, error, audin->device);
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error);
|
||||
}
|
||||
|
||||
free(callback->formats);
|
||||
@ -537,13 +570,19 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
AUDIN_CHANNEL_CALLBACK* callback;
|
||||
AUDIN_PLUGIN* audin;
|
||||
AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback;
|
||||
|
||||
if (!listener_callback || !listener_callback->plugin)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
audin = (AUDIN_PLUGIN*) listener_callback->plugin;
|
||||
DEBUG_DVC("...");
|
||||
callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK));
|
||||
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -569,7 +608,7 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag
|
||||
|
||||
if (!audin->listener_callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -597,7 +636,7 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Free failed with errorcode %"PRIu32"", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %"PRIu32"", error);
|
||||
// dont stop on error
|
||||
}
|
||||
|
||||
@ -648,7 +687,7 @@ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi
|
||||
|
||||
if (audin->device)
|
||||
{
|
||||
WLog_ERR(TAG, "existing device, abort.");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "existing device, abort.");
|
||||
return ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
@ -662,38 +701,34 @@ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args)
|
||||
static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV* args)
|
||||
{
|
||||
PFREERDP_AUDIN_DEVICE_ENTRY entry;
|
||||
FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin;
|
||||
UINT error;
|
||||
|
||||
if (!audin_process_addin_args(audin, args))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL,
|
||||
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", name, NULL,
|
||||
0);
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
WLog_ERR(TAG, "freerdp_load_channel_addin_entry did not return any function pointers for %s ",
|
||||
name);
|
||||
WLog_Print(audin->log, WLOG_ERROR,
|
||||
"freerdp_load_channel_addin_entry did not return any function pointers for %s ",
|
||||
name);
|
||||
return ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
entryPoints.plugin = pPlugin;
|
||||
entryPoints.plugin = (IWTSPlugin*) audin;
|
||||
entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
|
||||
entryPoints.args = args;
|
||||
entryPoints.rdpcontext = ((AUDIN_PLUGIN*)pPlugin)->rdpcontext;
|
||||
entryPoints.rdpcontext = audin->rdpcontext;
|
||||
|
||||
if ((error = entry(&entryPoints)))
|
||||
{
|
||||
WLog_ERR(TAG, "%s entry returned error %"PRIu32".", name, error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %"PRIu32".", name, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Loaded %s backend for audin", name);
|
||||
WLog_Print(audin->log, WLOG_INFO, "Loaded %s backend for audin", name);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -702,14 +737,14 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
|
||||
static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, const char* subsystem)
|
||||
{
|
||||
free(audin->subsystem);
|
||||
audin->subsystem = _strdup(subsystem);
|
||||
|
||||
if (!audin->subsystem)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "_strdup failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
@ -728,7 +763,7 @@ static UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
|
||||
|
||||
if (!audin->device_name)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "_strdup failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
@ -763,6 +798,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
|
||||
return FALSE;
|
||||
|
||||
arg = audin_args;
|
||||
errno = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@ -774,7 +810,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, arg->Value)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem failed with error %"PRIu32"!", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem failed with error %"PRIu32"!", error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -782,21 +818,34 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
|
||||
{
|
||||
if ((error = audin_set_device_name(audin, arg->Value)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name failed with error %"PRIu32"!", error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name failed with error %"PRIu32"!", error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
CommandLineSwitchCase(arg, "format")
|
||||
{
|
||||
audin->fixed_format = atoi(arg->Value);
|
||||
unsigned long val = strtoul(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT16_MAX))
|
||||
return FALSE;
|
||||
|
||||
audin->fixed_format = val;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "rate")
|
||||
{
|
||||
audin->fixed_rate = atoi(arg->Value);
|
||||
long val = strtol(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
|
||||
return FALSE;
|
||||
|
||||
audin->fixed_rate = val;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "channel")
|
||||
{
|
||||
audin->fixed_channel = atoi(arg->Value);
|
||||
unsigned long val = strtoul(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT16_MAX))
|
||||
audin->fixed_channel = val;
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
@ -867,6 +916,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
audin->log = WLog_Get(TAG);
|
||||
audin->attached = TRUE;
|
||||
audin->iface.Initialize = audin_plugin_initialize;
|
||||
audin->iface.Connected = NULL;
|
||||
@ -886,10 +936,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
|
||||
if (audin->subsystem)
|
||||
{
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
if ((error = audin_load_device_plugin(audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %"PRIu32"!",
|
||||
audin->subsystem, error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!",
|
||||
audin->subsystem, error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -899,18 +949,18 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
if ((error = audin_set_subsystem(audin, entry->subsystem)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %"PRIu32"!",
|
||||
entry->subsystem, error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem for %s failed with error %"PRIu32"!",
|
||||
entry->subsystem, error);
|
||||
}
|
||||
else if ((error = audin_set_device_name(audin, entry->device)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for %s failed with error %"PRIu32"!",
|
||||
entry->subsystem, error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name for %s failed with error %"PRIu32"!",
|
||||
entry->subsystem, error);
|
||||
}
|
||||
else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
else if ((error = audin_load_device_plugin(audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %"PRIu32"!",
|
||||
entry->subsystem, error);
|
||||
WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!",
|
||||
entry->subsystem, error);
|
||||
}
|
||||
|
||||
entry++;
|
||||
@ -918,7 +968,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
}
|
||||
|
||||
if (audin->device == NULL)
|
||||
WLog_ERR(TAG, "no sound device.");
|
||||
WLog_Print(audin->log, WLOG_ERROR, "no sound device.");
|
||||
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin);
|
||||
out:
|
||||
|
||||
@ -70,7 +70,7 @@ typedef struct _AudinOpenSLESDevice
|
||||
rdpContext* rdpcontext;
|
||||
} AudinOpenSLESDevice;
|
||||
|
||||
static void* audin_opensles_thread_func(void* arg)
|
||||
static DWORD WINAPI audin_opensles_thread_func(LPVOID arg)
|
||||
{
|
||||
union
|
||||
{
|
||||
@ -173,8 +173,8 @@ out:
|
||||
if (error && opensles->rdpcontext)
|
||||
setChannelError(opensles->rdpcontext, error, "audin_opensles_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,7 +356,7 @@ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive,
|
||||
goto error_out;
|
||||
}
|
||||
if (!(opensles->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_opensles_thread_func,
|
||||
audin_opensles_thread_func,
|
||||
opensles, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
|
||||
@ -173,7 +173,7 @@ static UINT audin_oss_set_format(IAudinDevice* device, audinFormat* format,
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void* audin_oss_thread_func(void* arg)
|
||||
static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
|
||||
{
|
||||
char dev_name[PATH_MAX] = "/dev/dsp";
|
||||
char mixer_name[PATH_MAX] = "/dev/mixer";
|
||||
@ -352,8 +352,8 @@ err_out:
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,8 +374,7 @@ static UINT audin_oss_open(IAudinDevice* device, AudinReceive receive,
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!(oss->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)audin_oss_thread_func, oss, 0, NULL)))
|
||||
if (!(oss->thread = CreateThread(NULL, 0, audin_oss_thread_func, oss, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(oss->stopEvent);
|
||||
@ -471,6 +470,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
arg = audin_oss_args;
|
||||
errno = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@ -488,7 +488,17 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
oss->dev_unit = strtol(str_num, &eptr, 10);
|
||||
{
|
||||
long val = strtol(str_num, &eptr, 10);
|
||||
|
||||
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
|
||||
{
|
||||
free(str_num);
|
||||
return CHANNEL_RC_NULL_DATA;
|
||||
}
|
||||
|
||||
oss->dev_unit = val;
|
||||
}
|
||||
|
||||
if (oss->dev_unit < 0 || *eptr != '\0')
|
||||
oss->dev_unit = -1;
|
||||
|
||||
@ -400,14 +400,15 @@ static UINT audin_pulse_close(IAudinDevice* device)
|
||||
{
|
||||
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
|
||||
|
||||
if (!pulse->context || !pulse->stream)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (pulse->stream)
|
||||
{
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pa_stream_disconnect(pulse->stream);
|
||||
pa_stream_unref(pulse->stream);
|
||||
pulse->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pa_stream_disconnect(pulse->stream);
|
||||
pa_stream_unref(pulse->stream);
|
||||
pulse->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
pulse->receive = NULL;
|
||||
pulse->user_data = NULL;
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance
|
||||
setChannelError(winmm->rdpcontext, error, "waveInProc reported an error");
|
||||
}
|
||||
|
||||
static DWORD audin_winmm_thread_func(void* arg)
|
||||
static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
|
||||
{
|
||||
AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg;
|
||||
char *buffer;
|
||||
@ -332,8 +332,7 @@ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* u
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!(winmm->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_winmm_thread_func, winmm, 0, NULL)))
|
||||
if (!(winmm->thread = CreateThread(NULL, 0, audin_winmm_thread_func, winmm, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(winmm->stopEvent);
|
||||
|
||||
@ -401,7 +401,7 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s,
|
||||
return success;
|
||||
}
|
||||
|
||||
static void* audin_server_thread_func(void* arg)
|
||||
static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
||||
{
|
||||
wStream* s;
|
||||
void* buffer;
|
||||
@ -596,8 +596,8 @@ out:
|
||||
setChannelError(audin->context.rdpcontext, error,
|
||||
"audin_server_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static BOOL audin_server_open(audin_server_context* context)
|
||||
@ -632,8 +632,7 @@ static BOOL audin_server_open(audin_server_context* context)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(audin->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_server_thread_func, (void*) audin, 0, NULL)))
|
||||
if (!(audin->thread = CreateThread(NULL, 0, audin_server_thread_func, (void*) audin, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(audin->stopEvent);
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 position;
|
||||
size_t position;
|
||||
BOOL asciiNames;
|
||||
int formatNameLength;
|
||||
char* szFormatName;
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include "cliprdr_main.h"
|
||||
#include "cliprdr_format.h"
|
||||
|
||||
#ifdef WITH_DEBUG_CLIPRDR
|
||||
static const char* const CB_MSG_TYPE_STRINGS[] =
|
||||
{
|
||||
"",
|
||||
@ -49,6 +50,7 @@ static const char* const CB_MSG_TYPE_STRINGS[] =
|
||||
"CB_LOCK_CLIPDATA",
|
||||
"CB_UNLOCK_CLIPDATA"
|
||||
};
|
||||
#endif
|
||||
|
||||
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr)
|
||||
{
|
||||
@ -87,7 +89,7 @@ static wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags,
|
||||
*/
|
||||
static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s)
|
||||
{
|
||||
UINT32 pos;
|
||||
size_t pos;
|
||||
UINT32 dataLen;
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
pos = Stream_GetPosition(s);
|
||||
@ -160,6 +162,9 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr,
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, version); /* version (4 bytes) */
|
||||
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
|
||||
DEBUG_CLIPRDR("Version: %"PRIu32"", version);
|
||||
@ -218,15 +223,25 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s,
|
||||
UINT16 cCapabilitiesSets;
|
||||
UINT16 capabilitySetType;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
|
||||
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
|
||||
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities");
|
||||
|
||||
for (index = 0; index < cCapabilitiesSets; index++)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
|
||||
Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */
|
||||
|
||||
if (lengthCapability < 4 || Stream_GetRemainingLength(s) < lengthCapability-4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
switch (capabilitySetType)
|
||||
{
|
||||
case CB_CAPSTYPE_GENERAL:
|
||||
@ -448,8 +463,7 @@ static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s,
|
||||
unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA;
|
||||
unlockClipboardData.msgFlags = flags;
|
||||
unlockClipboardData.dataLen = length;
|
||||
Stream_Read_UINT32(s,
|
||||
unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */
|
||||
Stream_Read_UINT32(s, unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */
|
||||
IFCALLRET(context->ServerUnlockClipboardData, error, context,
|
||||
&unlockClipboardData);
|
||||
|
||||
@ -470,9 +484,17 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s)
|
||||
UINT16 msgFlags;
|
||||
UINT32 dataLen;
|
||||
UINT error;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, msgType); /* msgType (2 bytes) */
|
||||
Stream_Read_UINT16(s, msgFlags); /* msgFlags (2 bytes) */
|
||||
Stream_Read_UINT32(s, dataLen); /* dataLen (4 bytes) */
|
||||
|
||||
if (Stream_GetRemainingLength(s) < dataLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
#ifdef WITH_DEBUG_CLIPRDR
|
||||
WLog_DBG(TAG, "msgType: %s (%"PRIu16"), msgFlags: %"PRIu16" dataLen: %"PRIu32"",
|
||||
CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen);
|
||||
@ -500,40 +522,35 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s)
|
||||
break;
|
||||
|
||||
case CB_FORMAT_LIST_RESPONSE:
|
||||
if ((error = cliprdr_process_format_list_response(cliprdr, s, dataLen,
|
||||
msgFlags)))
|
||||
if ((error = cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags)))
|
||||
WLog_ERR(TAG, "cliprdr_process_format_list_response failed with error %"PRIu32"!",
|
||||
error);
|
||||
|
||||
break;
|
||||
|
||||
case CB_FORMAT_DATA_REQUEST:
|
||||
if ((error = cliprdr_process_format_data_request(cliprdr, s, dataLen,
|
||||
msgFlags)))
|
||||
if ((error = cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags)))
|
||||
WLog_ERR(TAG, "cliprdr_process_format_data_request failed with error %"PRIu32"!",
|
||||
error);
|
||||
|
||||
break;
|
||||
|
||||
case CB_FORMAT_DATA_RESPONSE:
|
||||
if ((error = cliprdr_process_format_data_response(cliprdr, s, dataLen,
|
||||
msgFlags)))
|
||||
if ((error = cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags)))
|
||||
WLog_ERR(TAG, "cliprdr_process_format_data_response failed with error %"PRIu32"!",
|
||||
error);
|
||||
|
||||
break;
|
||||
|
||||
case CB_FILECONTENTS_REQUEST:
|
||||
if ((error = cliprdr_process_filecontents_request(cliprdr, s, dataLen,
|
||||
msgFlags)))
|
||||
if ((error = cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags)))
|
||||
WLog_ERR(TAG, "cliprdr_process_filecontents_request failed with error %"PRIu32"!",
|
||||
error);
|
||||
|
||||
break;
|
||||
|
||||
case CB_FILECONTENTS_RESPONSE:
|
||||
if ((error = cliprdr_process_filecontents_response(cliprdr, s, dataLen,
|
||||
msgFlags)))
|
||||
if ((error = cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags)))
|
||||
WLog_ERR(TAG, "cliprdr_process_filecontents_response failed with error %"PRIu32"!",
|
||||
error);
|
||||
|
||||
@ -586,12 +603,9 @@ static UINT cliprdr_client_capabilities(CliprdrClientContext* context,
|
||||
|
||||
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
|
||||
Stream_Write_UINT16(s, 0); /* pad1 */
|
||||
generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*)
|
||||
capabilities->capabilitySets;
|
||||
Stream_Write_UINT16(s,
|
||||
generalCapabilitySet->capabilitySetType); /* capabilitySetType */
|
||||
Stream_Write_UINT16(s,
|
||||
generalCapabilitySet->capabilitySetLength); /* lengthCapability */
|
||||
generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*)capabilities->capabilitySets;
|
||||
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */
|
||||
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */
|
||||
Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */
|
||||
Stream_Write_UINT32(s, generalCapabilitySet->generalFlags); /* generalFlags */
|
||||
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientCapabilities");
|
||||
@ -618,9 +632,7 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context,
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
length = ConvertToUnicode(CP_UTF8, 0, tempDirectory->szTempDir, -1, &wszTempDir,
|
||||
0);
|
||||
|
||||
length = ConvertToUnicode(CP_UTF8, 0, tempDirectory->szTempDir, -1, &wszTempDir, 0);
|
||||
if (length < 0)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
@ -796,8 +808,7 @@ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context,
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(s,
|
||||
lockClipboardData->clipDataId); /* clipDataId (4 bytes) */
|
||||
Stream_Write_UINT32(s, lockClipboardData->clipDataId); /* clipDataId (4 bytes) */
|
||||
WLog_Print(cliprdr->log, WLOG_DEBUG,
|
||||
"ClientLockClipboardData: clipDataId: 0x%08"PRIX32"",
|
||||
lockClipboardData->clipDataId);
|
||||
@ -822,8 +833,7 @@ static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context,
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(s,
|
||||
unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */
|
||||
Stream_Write_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */
|
||||
WLog_Print(cliprdr->log, WLOG_DEBUG,
|
||||
"ClientUnlockClipboardData: clipDataId: 0x%08"PRIX32"",
|
||||
unlockClipboardData->clipDataId);
|
||||
@ -852,8 +862,7 @@ static UINT cliprdr_client_format_data_request(CliprdrClientContext* context,
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(s,
|
||||
formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
|
||||
Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
|
||||
WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataRequest");
|
||||
return cliprdr_packet_send(cliprdr, s);
|
||||
}
|
||||
@ -1048,7 +1057,7 @@ static VOID VCAPITYPE cliprdr_virtual_channel_open_event_ex(LPVOID lpUserParam,
|
||||
"cliprdr_virtual_channel_open_event_ex reported an error");
|
||||
}
|
||||
|
||||
static void* cliprdr_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI cliprdr_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -1090,8 +1099,8 @@ static void* cliprdr_virtual_channel_client_thread(void* arg)
|
||||
setChannelError(cliprdr->context->rdpcontext, error,
|
||||
"cliprdr_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1122,8 +1131,7 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr,
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
if (!(cliprdr->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) cliprdr_virtual_channel_client_thread, (void*) cliprdr,
|
||||
if (!(cliprdr->thread = CreateThread(NULL, 0, cliprdr_virtual_channel_client_thread, (void*) cliprdr,
|
||||
0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
@ -1182,6 +1190,7 @@ static UINT cliprdr_virtual_channel_event_disconnected(cliprdrPlugin* cliprdr)
|
||||
static UINT cliprdr_virtual_channel_event_terminated(cliprdrPlugin* cliprdr)
|
||||
{
|
||||
cliprdr->InitHandle = 0;
|
||||
free(cliprdr->context);
|
||||
free(cliprdr);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
@ -1201,8 +1210,7 @@ static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam,
|
||||
switch (event)
|
||||
{
|
||||
case CHANNEL_EVENT_CONNECTED:
|
||||
if ((error = cliprdr_virtual_channel_event_connected(cliprdr, pData,
|
||||
dataLength)))
|
||||
if ((error = cliprdr_virtual_channel_event_connected(cliprdr, pData, dataLength)))
|
||||
WLog_ERR(TAG, "cliprdr_virtual_channel_event_connected failed with error %"PRIu32"!",
|
||||
error);
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ wStream* cliprdr_server_packet_new(UINT16 msgType, UINT16 msgFlags,
|
||||
*/
|
||||
UINT cliprdr_server_packet_send(CliprdrServerPrivate* cliprdr, wStream* s)
|
||||
{
|
||||
UINT32 pos;
|
||||
size_t pos;
|
||||
BOOL status;
|
||||
UINT32 dataLen;
|
||||
UINT32 written;
|
||||
@ -628,7 +628,7 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context,
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 dataLen;
|
||||
UINT32 position;
|
||||
size_t position;
|
||||
BOOL asciiNames;
|
||||
int formatNameLength;
|
||||
char* szFormatName;
|
||||
@ -1185,7 +1185,7 @@ static UINT cliprdr_server_init(CliprdrServerContext* context)
|
||||
UINT cliprdr_server_read(CliprdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
int position;
|
||||
size_t position;
|
||||
DWORD BytesToRead;
|
||||
DWORD BytesReturned;
|
||||
CLIPRDR_HEADER header;
|
||||
@ -1319,7 +1319,7 @@ UINT cliprdr_server_read(CliprdrServerContext* context)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void* cliprdr_server_thread(void* arg)
|
||||
static DWORD WINAPI cliprdr_server_thread(LPVOID arg)
|
||||
{
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
@ -1388,8 +1388,8 @@ out:
|
||||
setChannelError(context->rdpcontext, error,
|
||||
"cliprdr_server_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1478,8 +1478,7 @@ static UINT cliprdr_server_start(CliprdrServerContext* context)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!(cliprdr->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) cliprdr_server_thread, (void*) context, 0, NULL)))
|
||||
if (!(cliprdr->Thread = CreateThread(NULL, 0, cliprdr_server_thread, (void*) context, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(cliprdr->StopEvent);
|
||||
|
||||
@ -98,7 +98,6 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac
|
||||
type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT;
|
||||
|
||||
s = Stream_New(NULL, length);
|
||||
|
||||
if(!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
@ -112,10 +111,9 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac
|
||||
NumMonitors = disp->MaxNumMonitors;
|
||||
|
||||
Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
|
||||
|
||||
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
|
||||
|
||||
//WLog_ERR(TAG, "NumMonitors: %"PRIu32"", NumMonitors);
|
||||
WLog_DBG(TAG, "disp_send_display_control_monitor_layout_pdu: NumMonitors=%"PRIu32"", NumMonitors);
|
||||
|
||||
for (index = 0; index < NumMonitors; index++)
|
||||
{
|
||||
@ -147,16 +145,11 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac
|
||||
Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
|
||||
Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
|
||||
|
||||
#if 0
|
||||
WLog_DBG(TAG, "\t: Flags: 0x%08"PRIX32"", Monitors[index].Flags);
|
||||
WLog_DBG(TAG, "\t: Left: %"PRId32"", Monitors[index].Left);
|
||||
WLog_DBG(TAG, "\t: Top: %"PRId32"", Monitors[index].Top);
|
||||
WLog_DBG(TAG, "\t: Width: %"PRIu32"", Monitors[index].Width);
|
||||
WLog_DBG(TAG, "\t: Height: %"PRIu32"", Monitors[index].Height);
|
||||
WLog_DBG(TAG, "\t: PhysicalWidth: %"PRIu32"", Monitors[index].PhysicalWidth);
|
||||
WLog_DBG(TAG, "\t: PhysicalHeight: %"PRIu32"", Monitors[index].PhysicalHeight);
|
||||
WLog_DBG(TAG, "\t: Orientation: %"PRIu32"", Monitors[index].Orientation);
|
||||
#endif
|
||||
WLog_DBG(TAG, "\t%d : Flags: 0x%08"PRIX32" Left/Top: (%"PRId32",%"PRId32") W/H=%"PRIu32"x%"PRIu32")", index,
|
||||
Monitors[index].Flags, Monitors[index].Left, Monitors[index].Top, Monitors[index].Width,
|
||||
Monitors[index].Height);
|
||||
WLog_DBG(TAG, "\t PhysicalWidth: %"PRIu32" PhysicalHeight: %"PRIu32" Orientation: %"PRIu32"",
|
||||
Monitors[index].PhysicalWidth, Monitors[index].PhysicalHeight, Monitors[index].Orientation);
|
||||
}
|
||||
|
||||
Stream_SealLength(s);
|
||||
@ -176,8 +169,11 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac
|
||||
UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
DISP_PLUGIN* disp;
|
||||
DispClientContext *context;
|
||||
UINT ret = CHANNEL_RC_OK;
|
||||
|
||||
disp = (DISP_PLUGIN*) callback->plugin;
|
||||
context = (DispClientContext *)disp->iface.pInterface;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 12)
|
||||
{
|
||||
@ -188,10 +184,11 @@ UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream
|
||||
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: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"",
|
||||
// disp->MaxNumMonitors, disp->MaxMonitorAreaFactorA, disp->MaxMonitorAreaFactorB);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
if (context->DisplayControlCaps)
|
||||
ret = context->DisplayControlCaps(context, disp->MaxNumMonitors, disp->MaxMonitorAreaFactorA, disp->MaxMonitorAreaFactorB);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,11 +357,9 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
DispClientContext* context;
|
||||
|
||||
disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp");
|
||||
|
||||
if (!disp)
|
||||
{
|
||||
disp = (DISP_PLUGIN*) calloc(1, sizeof(DISP_PLUGIN));
|
||||
|
||||
if (!disp)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
@ -375,9 +370,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
disp->iface.Connected = NULL;
|
||||
disp->iface.Disconnected = NULL;
|
||||
disp->iface.Terminated = disp_plugin_terminated;
|
||||
disp->MaxNumMonitors = 16;
|
||||
disp->MaxMonitorAreaFactorA = 8192;
|
||||
disp->MaxMonitorAreaFactorB = 8192;
|
||||
|
||||
context = (DispClientContext*) calloc(1, sizeof(DispClientContext));
|
||||
|
||||
if (!context)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
@ -386,15 +383,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
||||
@ -189,7 +189,7 @@ static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
|
||||
if (!dvcman)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -201,7 +201,7 @@ static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
|
||||
if (!dvcman->channels)
|
||||
{
|
||||
WLog_ERR(TAG, "ArrayList_New failed!");
|
||||
WLog_Print(plugin->log, WLOG_ERROR, "ArrayList_New failed!");
|
||||
free(dvcman);
|
||||
return NULL;
|
||||
}
|
||||
@ -211,7 +211,7 @@ static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
|
||||
if (!dvcman->pool)
|
||||
{
|
||||
WLog_ERR(TAG, "StreamPool_New failed!");
|
||||
WLog_Print(plugin->log, WLOG_ERROR, "StreamPool_New failed!");
|
||||
ArrayList_Free(dvcman->channels);
|
||||
free(dvcman);
|
||||
return NULL;
|
||||
@ -225,13 +225,14 @@ static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr,
|
||||
static UINT dvcman_load_addin(drdynvcPlugin* drdynvc,
|
||||
IWTSVirtualChannelManager* pChannelMgr,
|
||||
ADDIN_ARGV* args,
|
||||
rdpSettings* settings)
|
||||
{
|
||||
DVCMAN_ENTRY_POINTS entryPoints;
|
||||
PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL;
|
||||
WLog_INFO(TAG, "Loading Dynamic Virtual Channel %s", args->argv[0]);
|
||||
WLog_Print(drdynvc->log, WLOG_INFO, "Loading Dynamic Virtual Channel %s", args->argv[0]);
|
||||
pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry(
|
||||
args->argv[0],
|
||||
NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC);
|
||||
@ -251,16 +252,17 @@ static UINT dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr,
|
||||
return ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
static DVCMAN_CHANNEL* dvcman_channel_new(IWTSVirtualChannelManager*
|
||||
pChannelMgr,
|
||||
static DVCMAN_CHANNEL* dvcman_channel_new(drdynvcPlugin* drdynvc,
|
||||
IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId, const char* ChannelName)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel;
|
||||
|
||||
if (dvcman_find_channel_by_id(pChannelMgr, ChannelId))
|
||||
{
|
||||
WLog_ERR(TAG, "Protocol error: Duplicated ChannelId %"PRIu32" (%s)!", ChannelId,
|
||||
ChannelName);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Protocol error: Duplicated ChannelId %"PRIu32" (%s)!",
|
||||
ChannelId,
|
||||
ChannelName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -268,7 +270,7 @@ static DVCMAN_CHANNEL* dvcman_channel_new(IWTSVirtualChannelManager*
|
||||
|
||||
if (!channel)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "calloc failed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -278,14 +280,14 @@ static DVCMAN_CHANNEL* dvcman_channel_new(IWTSVirtualChannelManager*
|
||||
|
||||
if (!channel->channel_name)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "_strdup failed!");
|
||||
free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!InitializeCriticalSectionEx(&(channel->lock), 0 , 0))
|
||||
if (!InitializeCriticalSectionEx(&(channel->lock), 0, 0))
|
||||
{
|
||||
WLog_ERR(TAG, "InitializeCriticalSectionEx failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "InitializeCriticalSectionEx failed!");
|
||||
free(channel->channel_name);
|
||||
free(channel);
|
||||
return NULL;
|
||||
@ -297,31 +299,49 @@ static DVCMAN_CHANNEL* dvcman_channel_new(IWTSVirtualChannelManager*
|
||||
static void dvcman_channel_free(void* arg)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) arg;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (channel->channel_callback)
|
||||
if (channel)
|
||||
{
|
||||
channel->channel_callback->OnClose(channel->channel_callback);
|
||||
channel->channel_callback = NULL;
|
||||
}
|
||||
if (channel->channel_callback)
|
||||
{
|
||||
IFCALL(channel->channel_callback->OnClose,
|
||||
channel->channel_callback);
|
||||
}
|
||||
|
||||
if (channel->dvc_data)
|
||||
{
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
}
|
||||
if (channel->status == CHANNEL_RC_OK)
|
||||
{
|
||||
IWTSVirtualChannel* ichannel = (IWTSVirtualChannel*) channel;
|
||||
|
||||
DeleteCriticalSection(&(channel->lock));
|
||||
if (channel->dvcman && channel->dvcman->drdynvc)
|
||||
{
|
||||
DrdynvcClientContext* context = channel->dvcman->drdynvc->context;
|
||||
|
||||
if (channel->channel_name)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
IFCALLRET(context->OnChannelDisconnected, error,
|
||||
context, channel->channel_name,
|
||||
channel->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
error = IFCALLRESULT(CHANNEL_RC_OK, ichannel->Close, ichannel);
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
WLog_ERR(TAG, "Close failed with error %"PRIu32"!", error);
|
||||
}
|
||||
|
||||
if (channel->dvc_data)
|
||||
Stream_Release(channel->dvc_data);
|
||||
|
||||
DeleteCriticalSection(&(channel->lock));
|
||||
free(channel->channel_name);
|
||||
channel->channel_name = NULL;
|
||||
}
|
||||
|
||||
free(channel);
|
||||
}
|
||||
|
||||
static void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
|
||||
static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
int i;
|
||||
IWTSPlugin* pPlugin;
|
||||
@ -345,7 +365,7 @@ static void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
|
||||
|
||||
if (pPlugin->Terminated)
|
||||
if ((error = pPlugin->Terminated(pPlugin)))
|
||||
WLog_ERR(TAG, "Terminated failed with error %"PRIu32"!", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Terminated failed with error %"PRIu32"!", error);
|
||||
}
|
||||
|
||||
dvcman->num_plugins = 0;
|
||||
@ -358,7 +378,7 @@ static void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT dvcman_init(IWTSVirtualChannelManager* pChannelMgr)
|
||||
static UINT dvcman_init(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
int i;
|
||||
IWTSPlugin* pPlugin;
|
||||
@ -372,7 +392,7 @@ static UINT dvcman_init(IWTSVirtualChannelManager* pChannelMgr)
|
||||
if (pPlugin->Initialize)
|
||||
if ((error = pPlugin->Initialize(pPlugin, pChannelMgr)))
|
||||
{
|
||||
WLog_ERR(TAG, "Initialize failed with error %"PRIu32"!", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Initialize failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
@ -422,7 +442,8 @@ static UINT dvcman_close_channel_iface(IWTSVirtualChannel* pChannel)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
static UINT dvcman_create_channel(drdynvcPlugin* drdynvc,
|
||||
IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId, const char* ChannelName)
|
||||
{
|
||||
int i;
|
||||
@ -434,13 +455,13 @@ static UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
||||
UINT error;
|
||||
|
||||
if (!(channel = dvcman_channel_new(pChannelMgr, ChannelId, ChannelName)))
|
||||
if (!(channel = dvcman_channel_new(drdynvc, pChannelMgr, ChannelId, ChannelName)))
|
||||
{
|
||||
WLog_ERR(TAG, "dvcman_channel_new failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_channel_new failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
channel->status = 1;
|
||||
channel->status = ERROR_NOT_CONNECTED;
|
||||
ArrayList_Add(dvcman->channels, channel);
|
||||
|
||||
for (i = 0; i < dvcman->num_listeners; i++)
|
||||
@ -459,9 +480,9 @@ static UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
(IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback)) == CHANNEL_RC_OK
|
||||
&& bAccept)
|
||||
{
|
||||
WLog_DBG(TAG, "listener %s created new channel %"PRIu32"",
|
||||
listener->channel_name, channel->channel_id);
|
||||
channel->status = 0;
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG, "listener %s created new channel %"PRIu32"",
|
||||
listener->channel_name, channel->channel_id);
|
||||
channel->status = CHANNEL_RC_OK;
|
||||
channel->channel_callback = pCallback;
|
||||
channel->pInterface = listener->iface.pInterface;
|
||||
context = dvcman->drdynvc->context;
|
||||
@ -469,7 +490,8 @@ static UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
listener->iface.pInterface);
|
||||
|
||||
if (error)
|
||||
WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "context.OnChannelConnected failed with error %"PRIu32"",
|
||||
error);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -477,12 +499,12 @@ static UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
WLog_ERR(TAG, "OnNewChannelConnection failed with error %"PRIu32"!", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "OnNewChannelConnection failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "OnNewChannelConnection returned with bAccept FALSE!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "OnNewChannelConnection returned with bAccept FALSE!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
@ -497,7 +519,8 @@ static UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
static UINT dvcman_open_channel(drdynvcPlugin* drdynvc,
|
||||
IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel;
|
||||
@ -507,7 +530,7 @@ static UINT dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
|
||||
if (!channel)
|
||||
{
|
||||
WLog_ERR(TAG, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -517,11 +540,11 @@ static UINT dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
|
||||
if ((pCallback->OnOpen) && (error = pCallback->OnOpen(pCallback)))
|
||||
{
|
||||
WLog_ERR(TAG, "OnOpen failed with error %"PRIu32"!", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "OnOpen failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "open_channel: ChannelId %"PRIu32"", ChannelId);
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG, "open_channel: ChannelId %"PRIu32"", ChannelId);
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
@ -536,15 +559,13 @@ static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel;
|
||||
IWTSVirtualChannel* ichannel;
|
||||
DrdynvcClientContext* context;
|
||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
||||
|
||||
if (!channel)
|
||||
{
|
||||
//WLog_ERR(TAG, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
//WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
/**
|
||||
* Windows 8 / Windows Server 2012 send close requests for channels that failed to be created.
|
||||
* Do not warn, simply return success here.
|
||||
@ -552,30 +573,8 @@ static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
if (channel->status == CHANNEL_RC_OK)
|
||||
{
|
||||
context = dvcman->drdynvc->context;
|
||||
IFCALLRET(context->OnChannelDisconnected, error, context, channel->channel_name,
|
||||
channel->pInterface);
|
||||
|
||||
if (error)
|
||||
{
|
||||
WLog_ERR(TAG, "OnChannelDisconnected returned with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "dvcman_close_channel: channel %"PRIu32" closed", ChannelId);
|
||||
ichannel = (IWTSVirtualChannel*) channel;
|
||||
|
||||
if ((ichannel->Close) && (error = ichannel->Close(ichannel)))
|
||||
{
|
||||
WLog_ERR(TAG, "Close failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList_Remove(dvcman->channels, channel);
|
||||
return CHANNEL_RC_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -583,8 +582,8 @@ static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr,
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT dvcman_receive_channel_data_first(IWTSVirtualChannelManager*
|
||||
pChannelMgr,
|
||||
static UINT dvcman_receive_channel_data_first(drdynvcPlugin* drdynvc,
|
||||
IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId, UINT32 length)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel;
|
||||
@ -596,7 +595,7 @@ static UINT dvcman_receive_channel_data_first(IWTSVirtualChannelManager*
|
||||
* Windows Server 2012 R2 can send some messages over Microsoft::Windows::RDS::Geometry::v08.01
|
||||
* even if the dynamic virtual channel wasn't registered on our side. Ignoring it works.
|
||||
*/
|
||||
WLog_ERR(TAG, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -607,7 +606,7 @@ static UINT dvcman_receive_channel_data_first(IWTSVirtualChannelManager*
|
||||
|
||||
if (!channel->dvc_data)
|
||||
{
|
||||
WLog_ERR(TAG, "StreamPool_Take failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -620,7 +619,8 @@ static UINT dvcman_receive_channel_data_first(IWTSVirtualChannelManager*
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr,
|
||||
static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc,
|
||||
IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId, wStream* data)
|
||||
{
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
@ -632,7 +632,7 @@ static UINT dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr,
|
||||
{
|
||||
/* Windows 8.1 tries to open channels not created.
|
||||
* Ignore cases like this. */
|
||||
WLog_ERR(TAG, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -642,7 +642,7 @@ static UINT dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr,
|
||||
if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(
|
||||
channel->dvc_data))
|
||||
{
|
||||
WLog_ERR(TAG, "data exceeding declared length!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "data exceeding declared length!");
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
return ERROR_INVALID_DATA;
|
||||
@ -712,8 +712,14 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s)
|
||||
switch (status)
|
||||
{
|
||||
case CHANNEL_RC_OK:
|
||||
case CHANNEL_RC_NOT_CONNECTED:
|
||||
return CHANNEL_RC_OK;
|
||||
case CHANNEL_RC_NOT_CONNECTED:
|
||||
Stream_Free(s, TRUE);
|
||||
return CHANNEL_RC_OK;
|
||||
case CHANNEL_RC_BAD_CHANNEL_HANDLE:
|
||||
Stream_Free(s, TRUE);
|
||||
WLog_ERR(TAG, "VirtualChannelWriteEx failed with CHANNEL_RC_BAD_CHANNEL_HANDLE");
|
||||
return status;
|
||||
|
||||
default:
|
||||
Stream_Free(s, TRUE);
|
||||
@ -733,7 +739,7 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId,
|
||||
const BYTE* data, UINT32 dataSize)
|
||||
{
|
||||
wStream* data_out;
|
||||
unsigned long pos;
|
||||
size_t pos;
|
||||
UINT32 cbChId;
|
||||
UINT32 cbLen;
|
||||
unsigned long chunkLength;
|
||||
@ -922,7 +928,7 @@ static UINT32 drdynvc_read_variable_uint(wStream* s, int cbLen)
|
||||
static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp,
|
||||
int cbChId, wStream* s)
|
||||
{
|
||||
unsigned long pos;
|
||||
size_t pos;
|
||||
UINT status;
|
||||
UINT32 ChannelId;
|
||||
wStream* data_out;
|
||||
@ -954,11 +960,11 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp,
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG, "process_create_request: ChannelId=%"PRIu32" ChannelName=%s",
|
||||
ChannelId,
|
||||
Stream_Pointer(s));
|
||||
channel_status = dvcman_create_channel(drdynvc->channel_mgr, ChannelId,
|
||||
channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId,
|
||||
(char*) Stream_Pointer(s));
|
||||
data_out = Stream_New(NULL, pos + 4);
|
||||
|
||||
if (!s)
|
||||
if (!data_out)
|
||||
{
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
@ -976,22 +982,21 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp,
|
||||
else
|
||||
{
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG, "no listener");
|
||||
Stream_Write_UINT32(data_out,
|
||||
(UINT32) 0xC0000001); /* same code used by mstsc */
|
||||
Stream_Write_UINT32(data_out, (UINT32)0xC0000001); /* same code used by mstsc */
|
||||
}
|
||||
|
||||
status = drdynvc_send(drdynvc, data_out);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]",
|
||||
WTSErrorToString(status), status);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]",
|
||||
WTSErrorToString(status), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (channel_status == CHANNEL_RC_OK)
|
||||
{
|
||||
if ((status = dvcman_open_channel(drdynvc->channel_mgr, ChannelId)))
|
||||
if ((status = dvcman_open_channel(drdynvc, drdynvc->channel_mgr, ChannelId)))
|
||||
{
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_open_channel failed with error %"PRIu32"!", status);
|
||||
return status;
|
||||
@ -1019,15 +1024,16 @@ static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp,
|
||||
UINT32 ChannelId;
|
||||
ChannelId = drdynvc_read_variable_uint(s, cbChId);
|
||||
Length = drdynvc_read_variable_uint(s, Sp);
|
||||
WLog_DBG(TAG, "process_data_first: Sp=%d cbChId=%d, ChannelId=%"PRIu32" Length=%"PRIu32"", Sp,
|
||||
cbChId, ChannelId, Length);
|
||||
status = dvcman_receive_channel_data_first(drdynvc->channel_mgr, ChannelId,
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG,
|
||||
"process_data_first: Sp=%d cbChId=%d, ChannelId=%"PRIu32" Length=%"PRIu32"", Sp,
|
||||
cbChId, ChannelId, Length);
|
||||
status = dvcman_receive_channel_data_first(drdynvc, drdynvc->channel_mgr, ChannelId,
|
||||
Length);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId, s);
|
||||
return dvcman_receive_channel_data(drdynvc, drdynvc->channel_mgr, ChannelId, s);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1043,7 +1049,7 @@ static UINT drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId,
|
||||
WLog_Print(drdynvc->log, WLOG_TRACE, "process_data: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp,
|
||||
cbChId,
|
||||
ChannelId);
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId, s);
|
||||
return dvcman_receive_channel_data(drdynvc, drdynvc->channel_mgr, ChannelId, s);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1059,12 +1065,13 @@ static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp,
|
||||
UINT32 ChannelId;
|
||||
wStream* data_out;
|
||||
ChannelId = drdynvc_read_variable_uint(s, cbChId);
|
||||
WLog_DBG(TAG, "process_close_request: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp,
|
||||
cbChId, ChannelId);
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG, "process_close_request: Sp=%d cbChId=%d, ChannelId=%"PRIu32"",
|
||||
Sp,
|
||||
cbChId, ChannelId);
|
||||
|
||||
if ((error = dvcman_close_channel(drdynvc->channel_mgr, ChannelId)))
|
||||
{
|
||||
WLog_ERR(TAG, "dvcman_close_channel failed with error %"PRIu32"!", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_close_channel failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1072,7 +1079,7 @@ static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp,
|
||||
|
||||
if (!data_out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -1082,8 +1089,8 @@ static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp,
|
||||
error = drdynvc_send(drdynvc, data_out);
|
||||
|
||||
if (error)
|
||||
WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]",
|
||||
WTSErrorToString(error), error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]",
|
||||
WTSErrorToString(error), error);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -1123,7 +1130,7 @@ static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc, wStream* s)
|
||||
return drdynvc_process_close_request(drdynvc, Sp, cbChId, s);
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown drdynvc cmd 0x%x", Cmd);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "unknown drdynvc cmd 0x%x", Cmd);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
@ -1153,13 +1160,13 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc,
|
||||
|
||||
if (!(data_in = drdynvc->data_in))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
|
||||
Stream_Free(drdynvc->data_in, TRUE);
|
||||
drdynvc->data_in = NULL;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
@ -1171,7 +1178,7 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc,
|
||||
{
|
||||
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
|
||||
{
|
||||
WLog_ERR(TAG, "drdynvc_plugin_process_received: read error");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "drdynvc_plugin_process_received: read error");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
@ -1181,7 +1188,7 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc,
|
||||
|
||||
if (!MessageQueue_Post(drdynvc->queue, NULL, 0, (void*) data_in, NULL))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_Post failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
@ -1198,6 +1205,7 @@ static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam,
|
||||
if (!drdynvc || (drdynvc->OpenHandle != openHandle))
|
||||
{
|
||||
WLog_ERR(TAG, "drdynvc_virtual_channel_open_event: error no match");
|
||||
Stream_Free((wStream*) pData, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1206,7 +1214,8 @@ static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam,
|
||||
case CHANNEL_EVENT_DATA_RECEIVED:
|
||||
if ((error = drdynvc_virtual_channel_event_data_received(drdynvc, pData, dataLength, totalLength,
|
||||
dataFlags)))
|
||||
WLog_ERR(TAG, "drdynvc_virtual_channel_event_data_received failed with error %"PRIu32"", error);
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR,
|
||||
"drdynvc_virtual_channel_event_data_received failed with error %"PRIu32"", error);
|
||||
|
||||
break;
|
||||
|
||||
@ -1222,7 +1231,7 @@ static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam,
|
||||
setChannelError(drdynvc->rdpcontext, error, "drdynvc_virtual_channel_open_event reported an error");
|
||||
}
|
||||
|
||||
static void* drdynvc_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -1232,7 +1241,7 @@ static void* drdynvc_virtual_channel_client_thread(void* arg)
|
||||
if (!drdynvc)
|
||||
{
|
||||
ExitThread((DWORD) CHANNEL_RC_BAD_CHANNEL_HANDLE);
|
||||
return NULL;
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
}
|
||||
|
||||
while (1)
|
||||
@ -1289,7 +1298,21 @@ static void* drdynvc_virtual_channel_client_thread(void* arg)
|
||||
"drdynvc_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD) error);
|
||||
return NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void drdynvc_queue_object_free(void* obj)
|
||||
{
|
||||
wStream* s;
|
||||
wMessage* msg = (wMessage*)obj;
|
||||
|
||||
if (!msg || (msg->id != 0))
|
||||
return;
|
||||
|
||||
s = (wStream*)msg->wParam;
|
||||
|
||||
if (s)
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1328,6 +1351,7 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO
|
||||
goto error;
|
||||
}
|
||||
|
||||
drdynvc->queue->object.fnObjectFree = drdynvc_queue_object_free;
|
||||
drdynvc->channel_mgr = dvcman_new(drdynvc);
|
||||
|
||||
if (!drdynvc->channel_mgr)
|
||||
@ -1342,13 +1366,13 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO
|
||||
for (index = 0; index < settings->DynamicChannelCount; index++)
|
||||
{
|
||||
args = settings->DynamicChannelArray[index];
|
||||
error = dvcman_load_addin(drdynvc->channel_mgr, args, settings);
|
||||
error = dvcman_load_addin(drdynvc, drdynvc->channel_mgr, args, settings);
|
||||
|
||||
if (CHANNEL_RC_OK != error)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((error = dvcman_init(drdynvc->channel_mgr)))
|
||||
if ((error = dvcman_init(drdynvc, drdynvc->channel_mgr)))
|
||||
{
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_init failed with error %"PRIu32"!", error);
|
||||
goto error;
|
||||
@ -1356,8 +1380,7 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO
|
||||
|
||||
drdynvc->state = DRDYNVC_STATE_CAPABILITIES;
|
||||
|
||||
if (!(drdynvc->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) drdynvc_virtual_channel_client_thread, (void*) drdynvc,
|
||||
if (!(drdynvc->thread = CreateThread(NULL, 0, drdynvc_virtual_channel_client_thread, (void*) drdynvc,
|
||||
0, NULL)))
|
||||
{
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
@ -1418,7 +1441,7 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc)
|
||||
|
||||
if (drdynvc->channel_mgr)
|
||||
{
|
||||
dvcman_free(drdynvc->channel_mgr);
|
||||
dvcman_free(drdynvc, drdynvc->channel_mgr);
|
||||
drdynvc->channel_mgr = NULL;
|
||||
}
|
||||
|
||||
@ -1436,6 +1459,7 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc)
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
|
||||
drdynvc->InitHandle = 0;
|
||||
free(drdynvc->context);
|
||||
free(drdynvc);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
@ -1598,7 +1622,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI
|
||||
|
||||
if (!context)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(drdynvc->log, WLOG_ERROR, "calloc failed!");
|
||||
free(drdynvc);
|
||||
return FALSE;
|
||||
}
|
||||
@ -1610,7 +1634,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI
|
||||
drdynvc->rdpcontext = pEntryPointsEx->context;
|
||||
}
|
||||
|
||||
drdynvc->log = WLog_Get("com.freerdp.channels.drdynvc.client");
|
||||
drdynvc->log = WLog_Get(TAG);
|
||||
WLog_Print(drdynvc->log, WLOG_DEBUG, "VirtualChannelEntryEx");
|
||||
CopyMemory(&(drdynvc->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
|
||||
drdynvc->InitHandle = pInitHandle;
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#define TAG CHANNELS_TAG("drdynvc.server")
|
||||
|
||||
|
||||
static void* drdynvc_server_thread(void* arg)
|
||||
static DWORD WINAPI drdynvc_server_thread(LPVOID arg)
|
||||
{
|
||||
#if 0
|
||||
wStream* s;
|
||||
@ -56,7 +56,7 @@ static void* drdynvc_server_thread(void* arg)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
ExitThread((DWORD) CHANNEL_RC_NO_MEMORY);
|
||||
return NULL;
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle,
|
||||
@ -111,7 +111,7 @@ static void* drdynvc_server_thread(void* arg)
|
||||
#endif
|
||||
// WTF ... this code only reads data into the stream until there is no more memory
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,8 +136,7 @@ static UINT drdynvc_server_start(DrdynvcServerContext* context)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!(context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) drdynvc_server_thread, (void*) context, 0, NULL)))
|
||||
if (!(context->priv->Thread = CreateThread(NULL, 0, drdynvc_server_thread, (void*) context, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(context->priv->StopEvent);
|
||||
|
||||
@ -181,8 +181,11 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void drive_file_set_fullpath(DRIVE_FILE* file, WCHAR* fullpath)
|
||||
static BOOL drive_file_set_fullpath(DRIVE_FILE* file, WCHAR* fullpath)
|
||||
{
|
||||
if (!file || !fullpath)
|
||||
return FALSE;
|
||||
|
||||
free(file->fullpath);
|
||||
file->fullpath = fullpath;
|
||||
file->filename = _wcsrchr(file->fullpath, L'/');
|
||||
@ -191,9 +194,11 @@ static void drive_file_set_fullpath(DRIVE_FILE* file, WCHAR* fullpath)
|
||||
file->filename = file->fullpath;
|
||||
else
|
||||
file->filename += 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL drive_file_init(DRIVE_FILE* file)
|
||||
static BOOL drive_file_init(DRIVE_FILE* file)
|
||||
{
|
||||
UINT CreateDisposition = 0;
|
||||
DWORD dwAttr = GetFileAttributesW(file->fullpath);
|
||||
@ -315,6 +320,10 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat
|
||||
UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
|
||||
{
|
||||
DRIVE_FILE* file;
|
||||
|
||||
if (!base_path || !path)
|
||||
return NULL;
|
||||
|
||||
file = (DRIVE_FILE*) calloc(1, sizeof(DRIVE_FILE));
|
||||
|
||||
if (!file)
|
||||
@ -350,6 +359,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat
|
||||
|
||||
BOOL drive_file_free(DRIVE_FILE* file)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
if (!file)
|
||||
return FALSE;
|
||||
|
||||
@ -368,33 +378,32 @@ BOOL drive_file_free(DRIVE_FILE* file)
|
||||
if (file->delete_pending)
|
||||
{
|
||||
if (file->is_dir)
|
||||
drive_file_remove_dir(file->fullpath);
|
||||
else if (!DeleteFileW(file->fullpath))
|
||||
{
|
||||
free(file->fullpath);
|
||||
free(file);
|
||||
return FALSE;
|
||||
if (!drive_file_remove_dir(file->fullpath))
|
||||
goto fail;
|
||||
}
|
||||
else if (!DeleteFileW(file->fullpath))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
DEBUG_WSTR("Free %s", file->fullpath);
|
||||
free(file->fullpath);
|
||||
free(file);
|
||||
return TRUE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset)
|
||||
{
|
||||
LONG lDistHigh;
|
||||
DWORD dwPtrLow;
|
||||
LARGE_INTEGER loffset;
|
||||
|
||||
if (!file)
|
||||
return FALSE;
|
||||
|
||||
lDistHigh = Offset >> 32;
|
||||
DEBUG_WSTR("Seek %s", file->fullpath);
|
||||
dwPtrLow = SetFilePointer(file->file_handle, Offset & 0xFFFFFFFF, &lDistHigh, FILE_BEGIN);
|
||||
return dwPtrLow != INVALID_SET_FILE_POINTER;
|
||||
loffset.QuadPart = Offset;
|
||||
return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN);
|
||||
}
|
||||
|
||||
BOOL drive_file_read(DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
|
||||
@ -552,6 +561,9 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
switch (FsInformationClass)
|
||||
{
|
||||
case FileBasicInformation:
|
||||
if (Stream_GetRemainingLength(input) < 36)
|
||||
return FALSE;
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
|
||||
Stream_Read_UINT64(input, liCreationTime.QuadPart);
|
||||
Stream_Read_UINT64(input, liLastAccessTime.QuadPart);
|
||||
@ -611,6 +623,9 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
|
||||
case FileAllocationInformation:
|
||||
if (Stream_GetRemainingLength(input) < 8)
|
||||
return FALSE;
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
|
||||
Stream_Read_INT64(input, size);
|
||||
|
||||
@ -623,8 +638,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
|
||||
liSize.QuadPart = size & 0xFFFFFFFF;
|
||||
|
||||
if (SetFilePointer(file->file_handle, liSize.LowPart, &liSize.HighPart,
|
||||
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
||||
if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
|
||||
{
|
||||
WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError());
|
||||
return FALSE;
|
||||
@ -648,7 +662,12 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
break; /* TODO: SetLastError ??? */
|
||||
|
||||
if (Length)
|
||||
{
|
||||
if (Stream_GetRemainingLength(input) < 1)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(input, delete_pending);
|
||||
}
|
||||
else
|
||||
delete_pending = 1;
|
||||
|
||||
@ -668,13 +687,19 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
break;
|
||||
|
||||
case FileRenameInformation:
|
||||
if (Stream_GetRemainingLength(input) < 6)
|
||||
return FALSE;
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
|
||||
Stream_Read_UINT8(input, ReplaceIfExists);
|
||||
Stream_Seek_UINT8(input); /* RootDirectory */
|
||||
Stream_Read_UINT32(input, FileNameLength);
|
||||
|
||||
if (Stream_GetRemainingLength(input) < FileNameLength)
|
||||
return FALSE;
|
||||
|
||||
fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input),
|
||||
FileNameLength);
|
||||
|
||||
if (!fullpath)
|
||||
{
|
||||
WLog_ERR(TAG, "drive_file_combine_fullpath failed!");
|
||||
@ -695,7 +720,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
if (MoveFileExW(file->fullpath, fullpath,
|
||||
MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
|
||||
{
|
||||
drive_file_set_fullpath(file, fullpath);
|
||||
if (!drive_file_set_fullpath(file, fullpath))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -66,6 +66,4 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
|
||||
const WCHAR* path, UINT32 PathLength, wStream* output);
|
||||
|
||||
extern UINT sys_code_page;
|
||||
|
||||
#endif /* FREERDP_CHANNEL_DRIVE_CLIENT_FILE_H */
|
||||
#endif /* FREERDP_CHANNEL_DRIVE_FILE_H */
|
||||
|
||||
@ -64,6 +64,8 @@ struct _DRIVE_DEVICE
|
||||
rdpContext* rdpcontext;
|
||||
};
|
||||
|
||||
static UINT sys_code_page = 0;
|
||||
|
||||
static DWORD drive_map_windows_err(DWORD fs_errno)
|
||||
{
|
||||
DWORD rc;
|
||||
@ -89,6 +91,14 @@ static DWORD drive_map_windows_err(DWORD fs_errno)
|
||||
rc = STATUS_DEVICE_BUSY;
|
||||
break;
|
||||
|
||||
case ERROR_INVALID_DRIVE:
|
||||
rc = STATUS_NO_SUCH_DEVICE;
|
||||
break;
|
||||
|
||||
case ERROR_NOT_READY:
|
||||
rc = STATUS_NO_SUCH_DEVICE;
|
||||
break;
|
||||
|
||||
case ERROR_FILE_EXISTS:
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
rc = STATUS_OBJECT_NAME_COLLISION;
|
||||
@ -116,7 +126,7 @@ static DWORD drive_map_windows_err(DWORD fs_errno)
|
||||
|
||||
default:
|
||||
rc = STATUS_UNSUCCESSFUL;
|
||||
WLog_ERR(TAG, "Error code not found: %"PRId32"", fs_errno);
|
||||
WLog_ERR(TAG, "Error code not found: %"PRIu32"", fs_errno);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -127,6 +137,10 @@ static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
|
||||
{
|
||||
DRIVE_FILE* file = NULL;
|
||||
void* key = (void*)(size_t) id;
|
||||
|
||||
if (!drive)
|
||||
return NULL;
|
||||
|
||||
file = (DRIVE_FILE*) ListDictionary_GetItemValue(drive->files, key);
|
||||
return file;
|
||||
}
|
||||
@ -138,7 +152,6 @@ static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
|
||||
*/
|
||||
static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
void* key;
|
||||
UINT32 FileId;
|
||||
DRIVE_FILE* file;
|
||||
BYTE Information;
|
||||
@ -148,14 +161,25 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
|
||||
UINT32 CreateDisposition;
|
||||
UINT32 CreateOptions;
|
||||
UINT32 PathLength;
|
||||
UINT64 allocationSize;
|
||||
const WCHAR* path;
|
||||
|
||||
if (!drive || !irp || !irp->devman || !irp->Complete)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 6*4+8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, DesiredAccess);
|
||||
Stream_Seek(irp->input, 8); /* AllocationSize(8) */
|
||||
Stream_Read_UINT64(irp->input, allocationSize);
|
||||
Stream_Read_UINT32(irp->input, FileAttributes);
|
||||
Stream_Read_UINT32(irp->input, SharedAccess);
|
||||
Stream_Read_UINT32(irp->input, CreateDisposition);
|
||||
Stream_Read_UINT32(irp->input, CreateOptions);
|
||||
Stream_Read_UINT32(irp->input, PathLength);
|
||||
if (Stream_GetRemainingLength(irp->input) < PathLength)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
path = (WCHAR*) Stream_Pointer(irp->input);
|
||||
FileId = irp->devman->id_sequence++;
|
||||
file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition,
|
||||
@ -169,7 +193,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
|
||||
}
|
||||
else
|
||||
{
|
||||
key = (void*)(size_t) file->id;
|
||||
void* key = (void*)(size_t) file->id;
|
||||
|
||||
if (!ListDictionary_Add(drive->files, key, file))
|
||||
{
|
||||
@ -214,13 +238,14 @@ static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
void* key;
|
||||
DRIVE_FILE* file;
|
||||
if (!drive || !irp || !irp->Complete || !irp->output)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
key = (void*)(size_t) irp->FileId;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ListDictionary_Remove(drive->files, key);
|
||||
@ -245,11 +270,17 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
|
||||
DRIVE_FILE* file;
|
||||
UINT32 Length;
|
||||
UINT64 Offset;
|
||||
BYTE* buffer = NULL;
|
||||
|
||||
if (!drive || !irp || !irp->output || !irp->Complete)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 12)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length);
|
||||
Stream_Read_UINT64(irp->input, Offset);
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
if (!file)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
@ -260,39 +291,29 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
|
||||
irp->IoStatus = drive_map_windows_err(GetLastError());
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
else if (Length == 0)
|
||||
Stream_Write_UINT32(irp->output, 0);
|
||||
else
|
||||
{
|
||||
buffer = (BYTE*) malloc(Length);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
WLog_ERR(TAG, "malloc failed!");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
BYTE* buffer = Stream_Pointer(irp->output) + sizeof(UINT32);
|
||||
if (!drive_file_read(file, buffer, &Length))
|
||||
{
|
||||
irp->IoStatus = drive_map_windows_err(GetLastError());
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
Length = 0;
|
||||
Stream_Write_UINT32(irp->output, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length);
|
||||
|
||||
if (Length > 0)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(irp->output, (int) Length))
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
Stream_Write_UINT32(irp->output, Length);
|
||||
Stream_Seek(irp->output, Length);
|
||||
}
|
||||
|
||||
Stream_Write(irp->output, buffer, Length);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return irp->Complete(irp);
|
||||
}
|
||||
|
||||
@ -306,11 +327,18 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
|
||||
DRIVE_FILE* file;
|
||||
UINT32 Length;
|
||||
UINT64 Offset;
|
||||
|
||||
if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length);
|
||||
Stream_Read_UINT64(irp->input, Offset);
|
||||
Stream_Seek(irp->input, 20); /* Padding */
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
if (!file)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
@ -341,9 +369,16 @@ static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
DRIVE_FILE* file;
|
||||
UINT32 FsInformationClass;
|
||||
Stream_Read_UINT32(irp->input, FsInformationClass);
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
|
||||
if (!drive || !irp || !irp->Complete)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, FsInformationClass);
|
||||
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
if (!file)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
@ -366,11 +401,18 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
|
||||
DRIVE_FILE* file;
|
||||
UINT32 FsInformationClass;
|
||||
UINT32 Length;
|
||||
|
||||
if (!drive || !irp || !irp->Complete || !irp->input || !irp->output)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, FsInformationClass);
|
||||
Stream_Read_UINT32(irp->input, Length);
|
||||
Stream_Seek(irp->input, 24); /* Padding */
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
if (!file)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
@ -398,7 +440,7 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
|
||||
IRP* irp)
|
||||
{
|
||||
UINT32 FsInformationClass;
|
||||
wStream* output = irp->output;
|
||||
wStream* output = NULL;
|
||||
char* volumeLabel = {"FREERDP"};
|
||||
char* diskType = {"FAT32"};
|
||||
WCHAR* outStr = NULL;
|
||||
@ -408,6 +450,15 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
|
||||
DWORD lpNumberOfFreeClusters;
|
||||
DWORD lpTotalNumberOfClusters;
|
||||
WIN32_FILE_ATTRIBUTE_DATA wfad;
|
||||
|
||||
if (!drive || !irp)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
output = irp->output;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, FsInformationClass);
|
||||
GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters,
|
||||
&lpTotalNumberOfClusters);
|
||||
@ -536,9 +587,16 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
|
||||
static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
UINT32 FsInformationClass;
|
||||
wStream* output = irp->output;
|
||||
|
||||
if (!drive || !irp || !irp->output || !irp->Complete)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, FsInformationClass);
|
||||
Stream_Write_UINT32(output, 0); /* Length */
|
||||
|
||||
Stream_Write_UINT32(irp->output, 0); /* Length */
|
||||
return irp->Complete(irp);
|
||||
}
|
||||
|
||||
@ -554,13 +612,20 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
|
||||
BYTE InitialQuery;
|
||||
UINT32 PathLength;
|
||||
UINT32 FsInformationClass;
|
||||
|
||||
if (!drive || !irp || !irp->Complete)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, FsInformationClass);
|
||||
Stream_Read_UINT8(irp->input, InitialQuery);
|
||||
Stream_Read_UINT32(irp->input, PathLength);
|
||||
Stream_Seek(irp->input, 23); /* Padding */
|
||||
path = (WCHAR*) Stream_Pointer(irp->input);
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
|
||||
file = drive_get_file_by_id(drive, irp->FileId);
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
@ -582,21 +647,21 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
|
||||
*/
|
||||
static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
if (!drive || !irp)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
switch (irp->MinorFunction)
|
||||
{
|
||||
case IRP_MN_QUERY_DIRECTORY:
|
||||
return drive_process_irp_query_directory(drive, irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */
|
||||
return irp->Discard(irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
Stream_Write_UINT32(irp->output, 0); /* Length */
|
||||
return irp->Complete(irp);
|
||||
break;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
@ -609,6 +674,9 @@ static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
|
||||
*/
|
||||
static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
if (!drive || !irp)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
|
||||
return irp->Complete(irp);
|
||||
}
|
||||
@ -621,6 +689,9 @@ static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
|
||||
static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
|
||||
{
|
||||
UINT error;
|
||||
if (!drive || !irp)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
@ -674,13 +745,19 @@ static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* drive_thread_func(void* arg)
|
||||
static DWORD WINAPI drive_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP* irp;
|
||||
wMessage message;
|
||||
DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if(!drive)
|
||||
{
|
||||
error = ERROR_INVALID_PARAMETER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!MessageQueue_Wait(drive->IrpQueue))
|
||||
@ -703,18 +780,21 @@ static void* drive_thread_func(void* arg)
|
||||
irp = (IRP*) message.wParam;
|
||||
|
||||
if (irp)
|
||||
{
|
||||
if ((error = drive_process_irp(drive, irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "drive_process_irp failed with error %"PRIu32"!", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error && drive->rdpcontext)
|
||||
fail:
|
||||
if (error && drive && drive->rdpcontext)
|
||||
setChannelError(drive->rdpcontext, error, "drive_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -726,6 +806,9 @@ static UINT drive_irp_request(DEVICE* device, IRP* irp)
|
||||
{
|
||||
DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device;
|
||||
|
||||
if (!drive)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*) irp, NULL))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
||||
@ -735,10 +818,11 @@ static UINT drive_irp_request(DEVICE* device, IRP* irp)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void drive_free_resources(DRIVE_DEVICE* drive)
|
||||
static UINT drive_free_int(DRIVE_DEVICE* drive)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
if (!drive)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
CloseHandle(drive->thread);
|
||||
ListDictionary_Free(drive->files);
|
||||
@ -746,6 +830,7 @@ static void drive_free_resources(DRIVE_DEVICE* drive)
|
||||
Stream_Free(drive->device.data, TRUE);
|
||||
free(drive->path);
|
||||
free(drive);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -758,6 +843,9 @@ static UINT drive_free(DEVICE* device)
|
||||
DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!drive)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (MessageQueue_PostQuit(drive->IrpQueue, 0)
|
||||
&& (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
|
||||
{
|
||||
@ -766,8 +854,7 @@ static UINT drive_free(DEVICE* device)
|
||||
return error;
|
||||
}
|
||||
|
||||
drive_free_resources(drive);
|
||||
return error;
|
||||
return drive_free_int(drive);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,10 +862,10 @@ static UINT drive_free(DEVICE* device)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
char* name, char* path)
|
||||
{
|
||||
int i, length;
|
||||
size_t i, length;
|
||||
DRIVE_DEVICE* drive;
|
||||
UINT error;
|
||||
#ifdef WIN32
|
||||
@ -813,7 +900,7 @@ UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
drive->device.IRPRequest = drive_irp_request;
|
||||
drive->device.Free = drive_free;
|
||||
drive->rdpcontext = pEntryPoints->rdpcontext;
|
||||
length = (int) strlen(name);
|
||||
length = strlen(name);
|
||||
drive->device.data = Stream_New(NULL, length + 1);
|
||||
|
||||
if (!drive->device.data)
|
||||
@ -862,7 +949,7 @@ UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (!(drive->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) drive_thread_func, drive,
|
||||
if (!(drive->thread = CreateThread(NULL, 0, drive_thread_func, drive,
|
||||
CREATE_SUSPENDED, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
@ -874,7 +961,7 @@ UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
out_error:
|
||||
drive_free_resources(drive);
|
||||
drive_free_int(drive);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -884,8 +971,6 @@ out_error:
|
||||
#define DeviceServiceEntry FREERDP_API DeviceServiceEntry
|
||||
#endif
|
||||
|
||||
UINT sys_code_page = 0;
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -920,30 +1005,13 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
}
|
||||
else if (strcmp(drive->Path, "%") == 0)
|
||||
{
|
||||
char* home_env = NULL;
|
||||
/* home directory */
|
||||
home_env = getenv("HOME");
|
||||
free(drive->Path);
|
||||
drive->Path = GetKnownPath(KNOWN_PATH_HOME);
|
||||
|
||||
if (home_env)
|
||||
if (!drive->Path)
|
||||
{
|
||||
drive->Path = _strdup(home_env);
|
||||
|
||||
if (!drive->Path)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drive->Path = _strdup("/");
|
||||
|
||||
if (!drive->Path)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ static UINT echo_server_open_channel(echo_server* echo)
|
||||
return echo->echo_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static void* echo_server_thread_func(void* arg)
|
||||
static DWORD WINAPI echo_server_thread_func(LPVOID arg)
|
||||
{
|
||||
wStream* s;
|
||||
void* buffer;
|
||||
@ -206,8 +206,8 @@ static void* echo_server_thread_func(void* arg)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WTSVirtualChannelClose(echo->echo_channel);
|
||||
ExitThread((DWORD)ERROR_NOT_ENOUGH_MEMORY);
|
||||
return NULL;
|
||||
ExitThread(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
while (ready)
|
||||
@ -264,8 +264,8 @@ out:
|
||||
setChannelError(echo->context.rdpcontext, error,
|
||||
"echo_server_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,8 +285,7 @@ static UINT echo_server_open(echo_server_context* context)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!(echo->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) echo_server_thread_func, (void*) echo, 0, NULL)))
|
||||
if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*) echo, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
CloseHandle(echo->stopEvent);
|
||||
|
||||
@ -1011,7 +1011,7 @@ static VOID VCAPITYPE encomsp_virtual_channel_open_event_ex(LPVOID lpUserParam,
|
||||
return;
|
||||
}
|
||||
|
||||
static void* encomsp_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -1054,8 +1054,8 @@ static void* encomsp_virtual_channel_client_thread(void* arg)
|
||||
setChannelError(encomsp->rdpcontext, error,
|
||||
"encomsp_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1087,7 +1087,7 @@ static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp,
|
||||
}
|
||||
|
||||
if (!(encomsp->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) encomsp_virtual_channel_client_thread, (void*) encomsp,
|
||||
encomsp_virtual_channel_client_thread, (void*) encomsp,
|
||||
0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
@ -1148,6 +1148,7 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp)
|
||||
static UINT encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp)
|
||||
{
|
||||
encomsp->InitHandle = 0;
|
||||
free(encomsp->context);
|
||||
free(encomsp);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ static UINT encomsp_server_receive_pdu(EncomspServerContext* context,
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* encomsp_server_thread(void* arg)
|
||||
static DWORD WINAPI encomsp_server_thread(LPVOID arg)
|
||||
{
|
||||
wStream* s;
|
||||
DWORD nCount;
|
||||
@ -285,8 +285,8 @@ out:
|
||||
setChannelError(context->rdpcontext, error,
|
||||
"encomsp_server_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,7 +309,7 @@ static UINT encomsp_server_start(EncomspServerContext* context)
|
||||
}
|
||||
|
||||
if (!(context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) encomsp_server_thread, (void*) context, 0, NULL)))
|
||||
encomsp_server_thread, (void*) context, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(context->priv->StopEvent);
|
||||
|
||||
22
channels/geometry/CMakeLists.txt
Normal file
22
channels/geometry/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2017 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("geometry")
|
||||
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
11
channels/geometry/ChannelOptions.cmake
Normal file
11
channels/geometry/ChannelOptions.cmake
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
|
||||
define_channel_options(NAME "geometry" TYPE "dynamic"
|
||||
DESCRIPTION "Geometry tracking Virtual Channel Extension"
|
||||
SPECIFICATIONS "[MS-RDPEGT]"
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
||||
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||
39
channels/geometry/client/CMakeLists.txt
Normal file
39
channels/geometry/client/CMakeLists.txt
Normal file
@ -0,0 +1,39 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2017 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_client("geometry")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
geometry_main.c
|
||||
geometry_main.h)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||
|
||||
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
||||
if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
||||
481
channels/geometry/client/geometry_main.c
Normal file
481
channels/geometry/client/geometry_main.c
Normal file
@ -0,0 +1,481 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Geometry tracking Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2017 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/interlocked.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/client/geometry.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#define TAG CHANNELS_TAG("geometry.client")
|
||||
|
||||
#include "geometry_main.h"
|
||||
|
||||
struct _GEOMETRY_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
};
|
||||
typedef struct _GEOMETRY_CHANNEL_CALLBACK GEOMETRY_CHANNEL_CALLBACK;
|
||||
|
||||
struct _GEOMETRY_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
GEOMETRY_CHANNEL_CALLBACK* channel_callback;
|
||||
};
|
||||
typedef struct _GEOMETRY_LISTENER_CALLBACK GEOMETRY_LISTENER_CALLBACK;
|
||||
|
||||
struct _GEOMETRY_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
IWTSListener* listener;
|
||||
GEOMETRY_LISTENER_CALLBACK* listener_callback;
|
||||
|
||||
GeometryClientContext* context;
|
||||
};
|
||||
typedef struct _GEOMETRY_PLUGIN GEOMETRY_PLUGIN;
|
||||
|
||||
|
||||
static UINT32 mappedGeometryHash(UINT64 *g)
|
||||
{
|
||||
return (UINT32)((*g >> 32) + (*g & 0xffffffff));
|
||||
}
|
||||
|
||||
static BOOL mappedGeometryKeyCompare(UINT64 *g1, UINT64 *g2)
|
||||
{
|
||||
return *g1 == *g2;
|
||||
}
|
||||
|
||||
void mappedGeometryRef(MAPPED_GEOMETRY *g)
|
||||
{
|
||||
InterlockedIncrement(&g->refCounter);
|
||||
}
|
||||
|
||||
void mappedGeometryUnref(MAPPED_GEOMETRY *g)
|
||||
{
|
||||
if (InterlockedDecrement(&g->refCounter))
|
||||
return;
|
||||
|
||||
g->MappedGeometryUpdate = NULL;
|
||||
g->MappedGeometryClear = NULL;
|
||||
g->custom = NULL;
|
||||
free(g->geometry.rects);
|
||||
free(g);
|
||||
}
|
||||
|
||||
|
||||
void freerdp_rgndata_reset(FREERDP_RGNDATA *data)
|
||||
{
|
||||
data->nRectCount = 0;
|
||||
}
|
||||
|
||||
static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgndata)
|
||||
{
|
||||
UINT32 dwSize, iType;
|
||||
INT32 right, bottom;
|
||||
|
||||
if (len < 32)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid RGNDATA");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, dwSize);
|
||||
|
||||
if (dwSize != 32)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid RGNDATA dwSize");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, iType);
|
||||
|
||||
if (iType != RDH_RECTANGLE)
|
||||
{
|
||||
WLog_ERR(TAG, "iType %"PRIu32" for RGNDATA is not supported", iType);
|
||||
return ERROR_UNSUPPORTED_TYPE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, rgndata->nRectCount);
|
||||
Stream_Seek_UINT32(s); /* nRgnSize IGNORED */
|
||||
Stream_Read_INT32(s, rgndata->boundingRect.x);
|
||||
Stream_Read_INT32(s, rgndata->boundingRect.y);
|
||||
Stream_Read_INT32(s, right);
|
||||
Stream_Read_INT32(s, bottom);
|
||||
rgndata->boundingRect.width = right - rgndata->boundingRect.x;
|
||||
rgndata->boundingRect.height = bottom - rgndata->boundingRect.y;
|
||||
len -= 32;
|
||||
|
||||
if (len / (4 * 4) < rgndata->nRectCount)
|
||||
{
|
||||
WLog_ERR(TAG, "not enough data for region rectangles");
|
||||
}
|
||||
|
||||
if (rgndata->nRectCount)
|
||||
{
|
||||
int i;
|
||||
RDP_RECT *tmp = realloc(rgndata->rects, rgndata->nRectCount * sizeof(RDP_RECT));
|
||||
|
||||
if (!tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to allocate memory for %"PRIu32" RECTs", rgndata->nRectCount);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
rgndata->rects = tmp;
|
||||
|
||||
for (i = 0; i < rgndata->nRectCount; i++)
|
||||
{
|
||||
Stream_Read_INT32(s, rgndata->rects[i].x);
|
||||
Stream_Read_INT32(s, rgndata->rects[i].y);
|
||||
Stream_Read_INT32(s, right);
|
||||
Stream_Read_INT32(s, bottom);
|
||||
rgndata->rects[i].width = right - rgndata->rects[i].x;
|
||||
rgndata->rects[i].height = bottom - rgndata->rects[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
UINT32 length, cbGeometryBuffer;
|
||||
MAPPED_GEOMETRY *mappedGeometry;
|
||||
GEOMETRY_PLUGIN* geometry;
|
||||
GeometryClientContext *context;
|
||||
UINT ret = CHANNEL_RC_OK;
|
||||
UINT32 version, updateType, geometryType;
|
||||
UINT64 id;
|
||||
|
||||
geometry = (GEOMETRY_PLUGIN*) callback->plugin;
|
||||
context = (GeometryClientContext*)geometry->iface.pInterface;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
{
|
||||
WLog_ERR(TAG, "not enough remaining data");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, length); /* Length (4 bytes) */
|
||||
|
||||
if (length < 73 || Stream_GetRemainingLength(s) < (length - 4))
|
||||
{
|
||||
WLog_ERR(TAG, "invalid packet length");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, version);
|
||||
Stream_Read_UINT64(s, id);
|
||||
Stream_Read_UINT32(s, updateType);
|
||||
Stream_Seek_UINT32(s); /* flags */
|
||||
|
||||
mappedGeometry = HashTable_GetItemValue(context->geometries, &id);
|
||||
|
||||
if (updateType == GEOMETRY_CLEAR )
|
||||
{
|
||||
if (!mappedGeometry)
|
||||
{
|
||||
WLog_ERR(TAG, "geometry 0x%"PRIx64" not found here, ignoring clear command", id);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "clearing geometry 0x%"PRIx64"", id);
|
||||
|
||||
if (mappedGeometry->MappedGeometryClear && !mappedGeometry->MappedGeometryClear(mappedGeometry))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (!HashTable_Remove(context->geometries, &id))
|
||||
WLog_ERR(TAG, "geometry not removed from geometries");
|
||||
}
|
||||
else if (updateType == GEOMETRY_UPDATE)
|
||||
{
|
||||
BOOL newOne = FALSE;
|
||||
|
||||
if (!mappedGeometry)
|
||||
{
|
||||
newOne = TRUE;
|
||||
WLog_DBG(TAG, "creating geometry 0x%"PRIx64"", id);
|
||||
mappedGeometry = calloc(1, sizeof(MAPPED_GEOMETRY));
|
||||
if (!mappedGeometry)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
mappedGeometry->refCounter = 1;
|
||||
mappedGeometry->mappingId = id;
|
||||
|
||||
if (HashTable_Add(context->geometries, &(mappedGeometry->mappingId), mappedGeometry) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to register geometry 0x%"PRIx64" in the table", id);
|
||||
free(mappedGeometry);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "updating geometry 0x%"PRIx64"", id);
|
||||
}
|
||||
|
||||
Stream_Read_UINT64(s, mappedGeometry->topLevelId);
|
||||
|
||||
Stream_Read_INT32(s, mappedGeometry->left);
|
||||
Stream_Read_INT32(s, mappedGeometry->top);
|
||||
Stream_Read_INT32(s, mappedGeometry->right);
|
||||
Stream_Read_INT32(s, mappedGeometry->bottom);
|
||||
|
||||
Stream_Read_INT32(s, mappedGeometry->topLevelLeft);
|
||||
Stream_Read_INT32(s, mappedGeometry->topLevelTop);
|
||||
Stream_Read_INT32(s, mappedGeometry->topLevelRight);
|
||||
Stream_Read_INT32(s, mappedGeometry->topLevelBottom);
|
||||
|
||||
Stream_Read_UINT32(s, geometryType);
|
||||
|
||||
Stream_Read_UINT32(s, cbGeometryBuffer);
|
||||
if (Stream_GetRemainingLength(s) < cbGeometryBuffer)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid packet length");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
if (cbGeometryBuffer)
|
||||
{
|
||||
ret = geometry_read_RGNDATA(s, cbGeometryBuffer, &mappedGeometry->geometry);
|
||||
if (ret != CHANNEL_RC_OK)
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
freerdp_rgndata_reset(&mappedGeometry->geometry);
|
||||
}
|
||||
|
||||
if (newOne)
|
||||
{
|
||||
if (context->MappedGeometryAdded && !context->MappedGeometryAdded(context, mappedGeometry))
|
||||
{
|
||||
WLog_ERR(TAG, "geometry added callback failed");
|
||||
ret = ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mappedGeometry->MappedGeometryUpdate && !mappedGeometry->MappedGeometryUpdate(mappedGeometry))
|
||||
{
|
||||
WLog_ERR(TAG, "geometry update callback failed");
|
||||
ret = ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "unknown updateType=%"PRIu32"", updateType);
|
||||
ret = CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT geometry_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
|
||||
{
|
||||
GEOMETRY_CHANNEL_CALLBACK* callback = (GEOMETRY_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
return geometry_recv_pdu(callback, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT geometry_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
free(pChannelCallback);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
GEOMETRY_CHANNEL_CALLBACK* callback;
|
||||
GEOMETRY_LISTENER_CALLBACK* listener_callback = (GEOMETRY_LISTENER_CALLBACK*) pListenerCallback;
|
||||
callback = (GEOMETRY_CHANNEL_CALLBACK*) calloc(1, sizeof(GEOMETRY_CHANNEL_CALLBACK));
|
||||
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
callback->iface.OnDataReceived = geometry_on_data_received;
|
||||
callback->iface.OnClose = geometry_on_close;
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
listener_callback->channel_callback = callback;
|
||||
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
UINT status;
|
||||
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*) pPlugin;
|
||||
geometry->listener_callback = (GEOMETRY_LISTENER_CALLBACK*) calloc(1,
|
||||
sizeof(GEOMETRY_LISTENER_CALLBACK));
|
||||
|
||||
if (!geometry->listener_callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
geometry->listener_callback->iface.OnNewChannelConnection = geometry_on_new_channel_connection;
|
||||
geometry->listener_callback->plugin = pPlugin;
|
||||
geometry->listener_callback->channel_mgr = pChannelMgr;
|
||||
status = pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0,
|
||||
(IWTSListenerCallback*) geometry->listener_callback, &(geometry->listener));
|
||||
geometry->listener->pInterface = geometry->iface.pInterface;
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
{
|
||||
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*) pPlugin;
|
||||
GeometryClientContext* context = (GeometryClientContext *)geometry->iface.pInterface;
|
||||
|
||||
if (context)
|
||||
HashTable_Free(context->geometries);
|
||||
|
||||
free(geometry->listener_callback);
|
||||
free(geometry->iface.pInterface);
|
||||
free(pPlugin);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel Client Interface
|
||||
*/
|
||||
|
||||
#ifdef BUILTIN_CHANNELS
|
||||
#define DVCPluginEntry geometry_DVCPluginEntry
|
||||
#else
|
||||
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
GEOMETRY_PLUGIN* geometry;
|
||||
GeometryClientContext* context;
|
||||
geometry = (GEOMETRY_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "geometry");
|
||||
|
||||
if (!geometry)
|
||||
{
|
||||
geometry = (GEOMETRY_PLUGIN*) calloc(1, sizeof(GEOMETRY_PLUGIN));
|
||||
|
||||
if (!geometry)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
geometry->iface.Initialize = geometry_plugin_initialize;
|
||||
geometry->iface.Connected = NULL;
|
||||
geometry->iface.Disconnected = NULL;
|
||||
geometry->iface.Terminated = geometry_plugin_terminated;
|
||||
context = (GeometryClientContext*) calloc(1, sizeof(GeometryClientContext));
|
||||
|
||||
if (!context)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
goto error_context;
|
||||
}
|
||||
|
||||
context->geometries = HashTable_New(FALSE);
|
||||
context->geometries->hash = (HASH_TABLE_HASH_FN)mappedGeometryHash;
|
||||
context->geometries->keyCompare = (HASH_TABLE_KEY_COMPARE_FN)mappedGeometryKeyCompare;
|
||||
context->geometries->valueFree = (HASH_TABLE_VALUE_FREE_FN)mappedGeometryUnref;
|
||||
|
||||
context->handle = (void*) geometry;
|
||||
geometry->iface.pInterface = (void*) context;
|
||||
geometry->context = context;
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", (IWTSPlugin*) geometry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "could not get geometry Plugin.");
|
||||
return CHANNEL_RC_BAD_CHANNEL;
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
error_context:
|
||||
free(geometry);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
}
|
||||
34
channels/geometry/client/geometry_main.h
Normal file
34
channels/geometry/client/geometry_main.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Geometry tracking virtual channel extension
|
||||
*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H
|
||||
#define FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/client/geometry.h>
|
||||
|
||||
|
||||
#endif /* FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H */
|
||||
|
||||
@ -304,7 +304,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void* parallel_thread_func(void* arg)
|
||||
static DWORD WINAPI parallel_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP* irp;
|
||||
wMessage message;
|
||||
@ -343,8 +343,8 @@ static void* parallel_thread_func(void* arg)
|
||||
setChannelError(parallel->rdpcontext, error,
|
||||
"parallel_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -375,8 +375,8 @@ static UINT parallel_free(DEVICE* device)
|
||||
UINT error;
|
||||
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
|
||||
|
||||
if (MessageQueue_PostQuit(parallel->queue, 0)
|
||||
&& (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
|
||||
if (!MessageQueue_PostQuit(parallel->queue, 0)
|
||||
|| (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
|
||||
{
|
||||
error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error);
|
||||
@ -405,7 +405,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
char* name;
|
||||
char* path;
|
||||
int i;
|
||||
size_t i;
|
||||
size_t length;
|
||||
RDPDR_PARALLEL* device;
|
||||
PARALLEL_DEVICE* parallel;
|
||||
@ -414,10 +414,10 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
name = device->Name;
|
||||
path = device->Path;
|
||||
|
||||
if (!name || (name[0] == '*'))
|
||||
if (!name || (name[0] == '*') || !path)
|
||||
{
|
||||
/* TODO: implement auto detection of parallel ports */
|
||||
return CHANNEL_RC_OK;
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
if (name[0] && path[0])
|
||||
@ -466,7 +466,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
}
|
||||
|
||||
if (!(parallel->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) parallel_thread_func, (void*) parallel, 0, NULL)))
|
||||
parallel_thread_func, (void*) parallel, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
|
||||
@ -231,7 +231,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void* printer_thread_func(void* arg)
|
||||
static DWORD WINAPI printer_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP* irp;
|
||||
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) arg;
|
||||
@ -275,8 +275,8 @@ static void* printer_thread_func(void* arg)
|
||||
setChannelError(printer_dev->rdpcontext, error,
|
||||
"printer_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD) error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -445,8 +445,7 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!(printer_dev->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) printer_thread_func, (void*) printer_dev, 0, NULL)))
|
||||
if (!(printer_dev->thread = CreateThread(NULL, 0, printer_thread_func, (void*) printer_dev, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
RailClientContext* rail_get_client_interface(railPlugin* rail)
|
||||
{
|
||||
RailClientContext* pInterface;
|
||||
|
||||
if (!rail)
|
||||
return NULL;
|
||||
|
||||
pInterface = (RailClientContext*) rail->channelEntryPoints.pInterface;
|
||||
return pInterface;
|
||||
}
|
||||
@ -52,14 +56,10 @@ static UINT rail_send(railPlugin* rail, wStream* s)
|
||||
UINT status;
|
||||
|
||||
if (!rail)
|
||||
{
|
||||
status = CHANNEL_RC_BAD_INIT_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = rail->channelEntryPoints.pVirtualChannelWriteEx(rail->InitHandle, rail->OpenHandle,
|
||||
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
|
||||
}
|
||||
return CHANNEL_RC_BAD_INIT_HANDLE;
|
||||
|
||||
status = rail->channelEntryPoints.pVirtualChannelWriteEx(rail->InitHandle, rail->OpenHandle,
|
||||
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
@ -79,6 +79,10 @@ static UINT rail_send(railPlugin* rail, wStream* s)
|
||||
UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length)
|
||||
{
|
||||
wStream* s = NULL;
|
||||
|
||||
if (!rail || !data)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = Stream_New(NULL, length);
|
||||
|
||||
if (!s)
|
||||
@ -97,17 +101,15 @@ UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length)
|
||||
*/
|
||||
static void rail_client_clean_exec_order(RAIL_EXEC_ORDER* exec)
|
||||
{
|
||||
if (!exec)
|
||||
return;
|
||||
if (!exec)
|
||||
return;
|
||||
|
||||
free(exec->exeOrFile.string);
|
||||
exec->exeOrFile.string = NULL;
|
||||
|
||||
free(exec->workingDir.string);
|
||||
exec->workingDir.string = NULL;
|
||||
|
||||
free(exec->arguments.string);
|
||||
exec->arguments.string = NULL;
|
||||
free(exec->exeOrFile.string);
|
||||
exec->exeOrFile.string = NULL;
|
||||
free(exec->workingDir.string);
|
||||
exec->workingDir.string = NULL;
|
||||
free(exec->arguments.string);
|
||||
exec->arguments.string = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,13 +126,18 @@ static UINT rail_client_execute(RailClientContext* context,
|
||||
{
|
||||
char* exeOrFile;
|
||||
UINT error;
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !exec)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
exeOrFile = exec->RemoteApplicationProgram;
|
||||
|
||||
if (!exeOrFile)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (strlen(exeOrFile) >= 2)
|
||||
if (strnlen(exeOrFile, MAX_PATH) >= 2)
|
||||
{
|
||||
if (strncmp(exeOrFile, "||", 2) != 0)
|
||||
exec->flags |= RAIL_EXEC_FLAG_FILE;
|
||||
@ -155,7 +162,12 @@ static UINT rail_client_execute(RailClientContext* context,
|
||||
static UINT rail_client_activate(RailClientContext* context,
|
||||
RAIL_ACTIVATE_ORDER* activate)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !activate)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_activate_order(rail, activate);
|
||||
}
|
||||
|
||||
@ -168,10 +180,14 @@ static UINT rail_send_client_sysparam(RailClientContext* context,
|
||||
RAIL_SYSPARAM_ORDER* sysparam)
|
||||
{
|
||||
wStream* s;
|
||||
int length;
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
|
||||
railPlugin* rail;
|
||||
UINT error;
|
||||
length = RAIL_SYSPARAM_ORDER_LENGTH;
|
||||
|
||||
if (!context || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
|
||||
switch (sysparam->param)
|
||||
{
|
||||
@ -231,6 +247,9 @@ static UINT rail_client_system_param(RailClientContext* context,
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!context || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST)
|
||||
{
|
||||
sysparam->param = SPI_SET_HIGH_CONTRAST;
|
||||
@ -319,6 +338,9 @@ static UINT rail_client_system_param(RailClientContext* context,
|
||||
static UINT rail_server_system_param(RailClientContext* context,
|
||||
RAIL_SYSPARAM_ORDER* sysparam)
|
||||
{
|
||||
if (!context || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -330,7 +352,12 @@ static UINT rail_server_system_param(RailClientContext* context,
|
||||
static UINT rail_client_system_command(RailClientContext* context,
|
||||
RAIL_SYSCOMMAND_ORDER* syscommand)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !syscommand)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_syscommand_order(rail, syscommand);
|
||||
}
|
||||
|
||||
@ -342,7 +369,12 @@ static UINT rail_client_system_command(RailClientContext* context,
|
||||
static UINT rail_client_handshake(RailClientContext* context,
|
||||
RAIL_HANDSHAKE_ORDER* handshake)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !handshake)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_handshake_order(rail, handshake);
|
||||
}
|
||||
|
||||
@ -354,6 +386,9 @@ static UINT rail_client_handshake(RailClientContext* context,
|
||||
static UINT rail_server_handshake(RailClientContext* context,
|
||||
RAIL_HANDSHAKE_ORDER* handshake)
|
||||
{
|
||||
if (!context || !handshake)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -365,7 +400,12 @@ static UINT rail_server_handshake(RailClientContext* context,
|
||||
static UINT rail_client_handshake_ex(RailClientContext* context,
|
||||
RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !handshakeEx)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_handshake_ex_order(rail, handshakeEx);
|
||||
}
|
||||
|
||||
@ -377,6 +417,9 @@ static UINT rail_client_handshake_ex(RailClientContext* context,
|
||||
static UINT rail_server_handshake_ex(RailClientContext* context,
|
||||
RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
|
||||
{
|
||||
if (!context || !handshakeEx)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -388,7 +431,12 @@ static UINT rail_server_handshake_ex(RailClientContext* context,
|
||||
static UINT rail_client_notify_event(RailClientContext* context,
|
||||
RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !notifyEvent)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_notify_event_order(rail, notifyEvent);
|
||||
}
|
||||
|
||||
@ -400,7 +448,12 @@ static UINT rail_client_notify_event(RailClientContext* context,
|
||||
static UINT rail_client_window_move(RailClientContext* context,
|
||||
RAIL_WINDOW_MOVE_ORDER* windowMove)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !windowMove)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_window_move_order(rail, windowMove);
|
||||
}
|
||||
|
||||
@ -412,6 +465,9 @@ static UINT rail_client_window_move(RailClientContext* context,
|
||||
static UINT rail_server_local_move_size(RailClientContext* context,
|
||||
RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
|
||||
{
|
||||
if (!context || !localMoveSize)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -423,6 +479,9 @@ static UINT rail_server_local_move_size(RailClientContext* context,
|
||||
static UINT rail_server_min_max_info(RailClientContext* context,
|
||||
RAIL_MINMAXINFO_ORDER* minMaxInfo)
|
||||
{
|
||||
if (!context || !minMaxInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -434,7 +493,12 @@ static UINT rail_server_min_max_info(RailClientContext* context,
|
||||
static UINT rail_client_information(RailClientContext* context,
|
||||
RAIL_CLIENT_STATUS_ORDER* clientStatus)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !clientStatus)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_status_order(rail, clientStatus);
|
||||
}
|
||||
|
||||
@ -446,7 +510,12 @@ static UINT rail_client_information(RailClientContext* context,
|
||||
static UINT rail_client_system_menu(RailClientContext* context,
|
||||
RAIL_SYSMENU_ORDER* sysmenu)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !sysmenu)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_sysmenu_order(rail, sysmenu);
|
||||
}
|
||||
|
||||
@ -458,7 +527,12 @@ static UINT rail_client_system_menu(RailClientContext* context,
|
||||
static UINT rail_client_language_bar_info(RailClientContext* context,
|
||||
RAIL_LANGBAR_INFO_ORDER* langBarInfo)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !langBarInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_langbar_info_order(rail, langBarInfo);
|
||||
}
|
||||
|
||||
@ -470,6 +544,9 @@ static UINT rail_client_language_bar_info(RailClientContext* context,
|
||||
static UINT rail_server_language_bar_info(RailClientContext* context,
|
||||
RAIL_LANGBAR_INFO_ORDER* langBarInfo)
|
||||
{
|
||||
if (!context || !langBarInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -481,6 +558,9 @@ static UINT rail_server_language_bar_info(RailClientContext* context,
|
||||
static UINT rail_server_execute_result(RailClientContext* context,
|
||||
RAIL_EXEC_RESULT_ORDER* execResult)
|
||||
{
|
||||
if (!context || !execResult)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -492,7 +572,12 @@ static UINT rail_server_execute_result(RailClientContext* context,
|
||||
static UINT rail_client_get_appid_request(RailClientContext* context,
|
||||
RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) context->handle;
|
||||
railPlugin* rail;
|
||||
|
||||
if (!context || !getAppIdReq || !context->handle)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
rail = (railPlugin*) context->handle;
|
||||
return rail_send_client_get_appid_req_order(rail, getAppIdReq);
|
||||
}
|
||||
|
||||
@ -504,6 +589,9 @@ static UINT rail_client_get_appid_request(RailClientContext* context,
|
||||
static UINT rail_server_get_appid_response(RailClientContext* context,
|
||||
RAIL_GET_APPID_RESP_ORDER* getAppIdResp)
|
||||
{
|
||||
if (!context || !getAppIdResp)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return CHANNEL_RC_OK; /* stub - should be registered by client */
|
||||
}
|
||||
|
||||
@ -606,7 +694,7 @@ static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWO
|
||||
return;
|
||||
}
|
||||
|
||||
static void* rail_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -635,9 +723,9 @@ static void* rail_virtual_channel_client_thread(void* arg)
|
||||
if (message.id == 0)
|
||||
{
|
||||
data = (wStream*) message.wParam;
|
||||
|
||||
error = rail_order_recv(rail, data);
|
||||
Stream_Free(data, TRUE);
|
||||
|
||||
if (error)
|
||||
{
|
||||
WLog_ERR(TAG, "rail_order_recv failed with error %"PRIu32"!", error);
|
||||
@ -650,8 +738,8 @@ static void* rail_virtual_channel_client_thread(void* arg)
|
||||
setChannelError(rail->rdpcontext, error,
|
||||
"rail_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -682,7 +770,7 @@ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData,
|
||||
}
|
||||
|
||||
if (!(rail->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rail_virtual_channel_client_thread, (void*) rail, 0,
|
||||
rail_virtual_channel_client_thread, (void*) rail, 0,
|
||||
NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
@ -738,6 +826,7 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
|
||||
static void rail_virtual_channel_event_terminated(railPlugin* rail)
|
||||
{
|
||||
rail->InitHandle = 0;
|
||||
free(rail->context);
|
||||
free(rail);
|
||||
}
|
||||
|
||||
@ -848,7 +937,6 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
|
||||
isFreerdp = TRUE;
|
||||
}
|
||||
|
||||
WLog_Init();
|
||||
rail->log = WLog_Get("com.freerdp.channels.rail.client");
|
||||
WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
|
||||
CopyMemory(&(rail->channelEntryPoints), pEntryPoints,
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
|
||||
#include "rail_orders.h"
|
||||
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -40,6 +39,9 @@
|
||||
*/
|
||||
static UINT rail_write_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
if (!s || !unicode_string)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
@ -58,6 +60,9 @@ static UINT rail_write_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_s
|
||||
*/
|
||||
static UINT rail_write_unicode_string_value(wStream* s, RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
if (!s || !unicode_string)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (unicode_string->length > 0)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, unicode_string->length))
|
||||
@ -80,6 +85,10 @@ static UINT rail_write_unicode_string_value(wStream* s, RAIL_UNICODE_STRING* uni
|
||||
UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
|
||||
{
|
||||
UINT16 orderLength;
|
||||
|
||||
if (!rail || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
orderLength = (UINT16) Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, 0);
|
||||
rail_write_pdu_header(s, orderType, orderLength);
|
||||
@ -94,8 +103,11 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_write_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
|
||||
static UINT rail_write_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
|
||||
{
|
||||
if (!s || !highContrast)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
highContrast->colorSchemeLength = highContrast->colorScheme.length + 2;
|
||||
Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
|
||||
Stream_Write_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
|
||||
@ -107,8 +119,11 @@ UINT rail_write_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* execResult)
|
||||
static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* execResult)
|
||||
{
|
||||
if (!s || !execResult)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
||||
@ -128,10 +143,13 @@ UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* exec
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
static UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
{
|
||||
BYTE body;
|
||||
|
||||
if (!s || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 5)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
||||
@ -163,8 +181,11 @@ UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo)
|
||||
static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo)
|
||||
{
|
||||
if (!s || !minmaxinfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 20)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
||||
@ -188,10 +209,14 @@ UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmax
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_read_server_localmovesize_order(wStream* s, RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
|
||||
static UINT rail_read_server_localmovesize_order(wStream* s,
|
||||
RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
|
||||
{
|
||||
UINT16 isMoveSizeStart;
|
||||
|
||||
if (!s || !localMoveSize)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 12)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
||||
@ -212,8 +237,12 @@ UINT rail_read_server_localmovesize_order(wStream* s, RAIL_LOCALMOVESIZE_ORDER*
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_read_server_get_appid_resp_order(wStream* s, RAIL_GET_APPID_RESP_ORDER* getAppidResp)
|
||||
static UINT rail_read_server_get_appid_resp_order(wStream* s,
|
||||
RAIL_GET_APPID_RESP_ORDER* getAppidResp)
|
||||
{
|
||||
if (!s || !getAppidResp)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 516)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
||||
@ -231,8 +260,11 @@ UINT rail_read_server_get_appid_resp_order(wStream* s, RAIL_GET_APPID_RESP_ORDER
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
|
||||
static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
|
||||
{
|
||||
if (!s || !langbarInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
|
||||
@ -243,9 +275,13 @@ UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarIn
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
void rail_write_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* clientStatus)
|
||||
static UINT rail_write_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* clientStatus)
|
||||
{
|
||||
if (!s || !clientStatus)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, clientStatus->flags); /* flags (4 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,9 +289,13 @@ void rail_write_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* client
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_write_client_exec_order(wStream* s, RAIL_EXEC_ORDER* exec)
|
||||
static UINT rail_write_client_exec_order(wStream* s, RAIL_EXEC_ORDER* exec)
|
||||
{
|
||||
UINT error;
|
||||
|
||||
if (!s || !exec)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT16(s, exec->flags); /* flags (2 bytes) */
|
||||
Stream_Write_UINT16(s, exec->exeOrFile.length); /* exeOrFileLength (2 bytes) */
|
||||
Stream_Write_UINT16(s, exec->workingDir.length); /* workingDirLength (2 bytes) */
|
||||
@ -291,6 +331,10 @@ UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
{
|
||||
BYTE body;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!s || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
|
||||
|
||||
switch (sysparam->param)
|
||||
@ -344,51 +388,80 @@ UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
return error;
|
||||
}
|
||||
|
||||
void rail_write_client_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* activate)
|
||||
static UINT rail_write_client_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* activate)
|
||||
{
|
||||
BYTE enabled;
|
||||
|
||||
if (!s || !activate)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, activate->windowId); /* windowId (4 bytes) */
|
||||
enabled = activate->enabled;
|
||||
Stream_Write_UINT8(s, enabled); /* enabled (1 byte) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void rail_write_client_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysmenu)
|
||||
static UINT rail_write_client_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysmenu)
|
||||
{
|
||||
if (!s || !sysmenu)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, sysmenu->windowId); /* windowId (4 bytes) */
|
||||
Stream_Write_UINT16(s, sysmenu->left); /* left (2 bytes) */
|
||||
Stream_Write_UINT16(s, sysmenu->top); /* top (2 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void rail_write_client_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER* syscommand)
|
||||
static UINT rail_write_client_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER* syscommand)
|
||||
{
|
||||
if (!s || !syscommand)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, syscommand->windowId); /* windowId (4 bytes) */
|
||||
Stream_Write_UINT16(s, syscommand->command); /* command (2 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void rail_write_client_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
|
||||
static UINT rail_write_client_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
|
||||
{
|
||||
if (!s || !notifyEvent)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, notifyEvent->windowId); /* windowId (4 bytes) */
|
||||
Stream_Write_UINT32(s, notifyEvent->notifyIconId); /* notifyIconId (4 bytes) */
|
||||
Stream_Write_UINT32(s, notifyEvent->message); /* notifyIconId (4 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void rail_write_client_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORDER* windowMove)
|
||||
static UINT rail_write_client_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORDER* windowMove)
|
||||
{
|
||||
if (!s || !windowMove)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, windowMove->windowId); /* windowId (4 bytes) */
|
||||
Stream_Write_UINT16(s, windowMove->left); /* left (2 bytes) */
|
||||
Stream_Write_UINT16(s, windowMove->top); /* top (2 bytes) */
|
||||
Stream_Write_UINT16(s, windowMove->right); /* right (2 bytes) */
|
||||
Stream_Write_UINT16(s, windowMove->bottom); /* bottom (2 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER* getAppidReq)
|
||||
static UINT rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER* getAppidReq)
|
||||
{
|
||||
if (!s || !getAppidReq)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, getAppidReq->windowId); /* windowId (4 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
|
||||
static UINT rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
|
||||
{
|
||||
if (!s || !langbarInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -396,11 +469,14 @@ void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarI
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake, wStream* s)
|
||||
static UINT rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake, wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !handshake || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_handshake_order(s, handshake)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_handshake_order failed with error %"PRIu32"!", error);
|
||||
@ -423,12 +499,15 @@ UINT rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* handshakeEx,
|
||||
wStream* s)
|
||||
static UINT rail_recv_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* handshakeEx,
|
||||
wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !handshakeEx || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_handshake_ex_order(s, handshakeEx)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %"PRIu32"!", error);
|
||||
@ -451,10 +530,15 @@ UINT rail_recv_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* han
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER* execResult, wStream* s)
|
||||
static UINT rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER* execResult,
|
||||
wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !execResult || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
ZeroMemory(execResult, sizeof(RAIL_EXEC_RESULT_ORDER));
|
||||
|
||||
if ((error = rail_read_server_exec_result_order(s, execResult)))
|
||||
@ -479,11 +563,15 @@ UINT rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER* execR
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam, wStream* s)
|
||||
static UINT rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam,
|
||||
wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !sysparam || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_server_sysparam_order(s, sysparam)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_server_sysparam_order failed with error %"PRIu32"!", error);
|
||||
@ -506,12 +594,15 @@ UINT rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysp
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ORDER* minMaxInfo,
|
||||
wStream* s)
|
||||
static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ORDER* minMaxInfo,
|
||||
wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !minMaxInfo || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_server_minmaxinfo_order(s, minMaxInfo)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %"PRIu32"!", error);
|
||||
@ -534,12 +625,16 @@ UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ORDER*
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_server_localmovesize_order(railPlugin* rail, RAIL_LOCALMOVESIZE_ORDER* localMoveSize,
|
||||
static UINT rail_recv_server_localmovesize_order(railPlugin* rail,
|
||||
RAIL_LOCALMOVESIZE_ORDER* localMoveSize,
|
||||
wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !localMoveSize || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_server_localmovesize_order(s, localMoveSize)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %"PRIu32"!", error);
|
||||
@ -562,12 +657,15 @@ UINT rail_recv_server_localmovesize_order(railPlugin* rail, RAIL_LOCALMOVESIZE_O
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_server_get_appid_resp_order(railPlugin* rail,
|
||||
static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail,
|
||||
RAIL_GET_APPID_RESP_ORDER* getAppIdResp, wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !getAppIdResp || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_server_get_appid_resp_order(s, getAppIdResp)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %"PRIu32"!", error);
|
||||
@ -590,12 +688,15 @@ UINT rail_recv_server_get_appid_resp_order(railPlugin* rail,
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_recv_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo,
|
||||
wStream* s)
|
||||
static UINT rail_recv_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo,
|
||||
wStream* s)
|
||||
{
|
||||
RailClientContext* context = rail_get_client_interface(rail);
|
||||
UINT error;
|
||||
|
||||
if (!context || !langBarInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_langbar_info_order(s, langBarInfo)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %"PRIu32"!", error);
|
||||
@ -624,6 +725,9 @@ UINT rail_order_recv(railPlugin* rail, wStream* s)
|
||||
UINT16 orderLength;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
|
||||
{
|
||||
WLog_ERR(TAG, "rail_read_pdu_header failed with error %"PRIu32"!", error);
|
||||
@ -688,7 +792,6 @@ UINT rail_order_recv(railPlugin* rail, wStream* s)
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown RAIL PDU order reveived.");
|
||||
return ERROR_INVALID_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
@ -703,6 +806,10 @@ UINT rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !handshake)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -726,6 +833,10 @@ UINT rail_send_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* han
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !handshakeEx)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -749,6 +860,10 @@ UINT rail_send_client_status_order(railPlugin* rail, RAIL_CLIENT_STATUS_ORDER* c
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !clientStatus)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -757,8 +872,11 @@ UINT rail_send_client_status_order(railPlugin* rail, RAIL_CLIENT_STATUS_ORDER* c
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_status_order(s, clientStatus);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_CLIENTSTATUS);
|
||||
error = rail_write_client_status_order(s, clientStatus);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_CLIENTSTATUS);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -773,6 +891,10 @@ UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec)
|
||||
wStream* s;
|
||||
UINT error;
|
||||
size_t length;
|
||||
|
||||
if (!rail || !exec)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
length = RAIL_EXEC_ORDER_LENGTH +
|
||||
exec->exeOrFile.length +
|
||||
exec->workingDir.length +
|
||||
@ -806,12 +928,14 @@ UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_send_client_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
static UINT rail_send_client_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
{
|
||||
wStream* s;
|
||||
int length;
|
||||
size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
|
||||
UINT error;
|
||||
length = RAIL_SYSPARAM_ORDER_LENGTH;
|
||||
|
||||
if (!rail || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
switch (sysparam->param)
|
||||
{
|
||||
@ -866,10 +990,13 @@ UINT rail_send_client_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysp
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!rail || !sysparam)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST)
|
||||
{
|
||||
sysparam->param = SPI_SET_HIGH_CONTRAST;
|
||||
@ -959,6 +1086,10 @@ UINT rail_send_client_activate_order(railPlugin* rail, RAIL_ACTIVATE_ORDER* acti
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !activate)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -967,8 +1098,11 @@ UINT rail_send_client_activate_order(railPlugin* rail, RAIL_ACTIVATE_ORDER* acti
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_activate_order(s, activate);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_ACTIVATE);
|
||||
error = rail_write_client_activate_order(s, activate);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_ACTIVATE);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -982,6 +1116,10 @@ UINT rail_send_client_sysmenu_order(railPlugin* rail, RAIL_SYSMENU_ORDER* sysmen
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !sysmenu)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -990,8 +1128,11 @@ UINT rail_send_client_sysmenu_order(railPlugin* rail, RAIL_SYSMENU_ORDER* sysmen
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_sysmenu_order(s, sysmenu);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSMENU);
|
||||
error = rail_write_client_sysmenu_order(s, sysmenu);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSMENU);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -1005,6 +1146,10 @@ UINT rail_send_client_syscommand_order(railPlugin* rail, RAIL_SYSCOMMAND_ORDER*
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !syscommand)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -1013,8 +1158,11 @@ UINT rail_send_client_syscommand_order(railPlugin* rail, RAIL_SYSCOMMAND_ORDER*
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_syscommand_order(s, syscommand);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSCOMMAND);
|
||||
error = rail_write_client_syscommand_order(s, syscommand);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSCOMMAND);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -1028,6 +1176,10 @@ UINT rail_send_client_notify_event_order(railPlugin* rail, RAIL_NOTIFY_EVENT_ORD
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !notifyEvent)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -1036,8 +1188,11 @@ UINT rail_send_client_notify_event_order(railPlugin* rail, RAIL_NOTIFY_EVENT_ORD
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_notify_event_order(s, notifyEvent);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_NOTIFY_EVENT);
|
||||
error = rail_write_client_notify_event_order(s, notifyEvent);
|
||||
|
||||
if (ERROR_SUCCESS == error)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_NOTIFY_EVENT);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -1051,6 +1206,10 @@ UINT rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !windowMove)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -1059,8 +1218,11 @@ UINT rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_window_move_order(s, windowMove);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_WINDOWMOVE);
|
||||
error = rail_write_client_window_move_order(s, windowMove);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_WINDOWMOVE);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -1074,6 +1236,10 @@ UINT rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_O
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !getAppIdReq)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -1082,8 +1248,11 @@ UINT rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_O
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_client_get_appid_req_order(s, getAppIdReq);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_GET_APPID_REQ);
|
||||
error = rail_write_client_get_appid_req_order(s, getAppIdReq);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_GET_APPID_REQ);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
@ -1097,6 +1266,10 @@ UINT rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORD
|
||||
{
|
||||
wStream* s;
|
||||
UINT error;
|
||||
|
||||
if (!rail || !langBarInfo)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
@ -1105,8 +1278,11 @@ UINT rail_send_client_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORD
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
rail_write_langbar_info_order(s, langBarInfo);
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_LANGBARINFO);
|
||||
error = rail_write_langbar_info_order(s, langBarInfo);
|
||||
|
||||
if (ERROR_SUCCESS == error)
|
||||
error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_LANGBARINFO);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -29,23 +29,7 @@
|
||||
|
||||
#define TAG CHANNELS_TAG("rail.client")
|
||||
|
||||
UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* exec_result);
|
||||
UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam);
|
||||
UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo);
|
||||
UINT rail_read_server_localmovesize_order(wStream* s, RAIL_LOCALMOVESIZE_ORDER* localmovesize);
|
||||
UINT rail_read_server_get_appid_resp_order(wStream* s, RAIL_GET_APPID_RESP_ORDER* get_appid_resp);
|
||||
UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbar_info);
|
||||
|
||||
void rail_write_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* client_status);
|
||||
UINT rail_write_client_exec_order(wStream* s, RAIL_EXEC_ORDER* exec);
|
||||
UINT rail_write_client_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam);
|
||||
void rail_write_client_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* activate);
|
||||
void rail_write_client_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysmenu);
|
||||
void rail_write_client_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER* syscommand);
|
||||
void rail_write_client_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_ORDER* notify_event);
|
||||
void rail_write_client_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORDER* window_move);
|
||||
void rail_write_client_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER* get_appid_req);
|
||||
void rail_write_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbar_info);
|
||||
|
||||
UINT rail_order_recv(railPlugin* rail, wStream* s);
|
||||
UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType);
|
||||
@ -54,11 +38,10 @@ UINT rail_send_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake
|
||||
UINT rail_send_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* handshakeEx);
|
||||
UINT rail_send_client_status_order(railPlugin* rail, RAIL_CLIENT_STATUS_ORDER* clientStatus);
|
||||
UINT rail_send_client_exec_order(railPlugin* rail, RAIL_EXEC_ORDER* exec);
|
||||
UINT rail_send_client_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam);
|
||||
UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam);
|
||||
UINT rail_send_client_activate_order(railPlugin* rail, RAIL_ACTIVATE_ORDER* activate);
|
||||
UINT rail_send_client_sysmenu_order(railPlugin* rail, RAIL_SYSMENU_ORDER* sysmenu);
|
||||
UINT rail_send_client_syscommand_order(railPlugin* rail, RAIL_SYSCOMMAND_ORDER* syscommand);
|
||||
|
||||
UINT rail_send_client_notify_event_order(railPlugin* rail, RAIL_NOTIFY_EVENT_ORDER* notifyEvent);
|
||||
UINT rail_send_client_window_move_order(railPlugin* rail, RAIL_WINDOW_MOVE_ORDER* windowMove);
|
||||
UINT rail_send_client_get_appid_req_order(railPlugin* rail, RAIL_GET_APPID_REQ_ORDER* getAppIdReq);
|
||||
|
||||
@ -55,9 +55,7 @@ void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_st
|
||||
{
|
||||
WCHAR* buffer = NULL;
|
||||
int length = 0;
|
||||
|
||||
free(unicode_string->string);
|
||||
|
||||
unicode_string->string = NULL;
|
||||
unicode_string->length = 0;
|
||||
|
||||
@ -65,7 +63,6 @@ void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_st
|
||||
return;
|
||||
|
||||
length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0) * 2;
|
||||
|
||||
unicode_string->string = (BYTE*) buffer;
|
||||
unicode_string->length = (UINT16) length;
|
||||
}
|
||||
@ -77,12 +74,14 @@ void rail_string_to_unicode_string(char* string, RAIL_UNICODE_STRING* unicode_st
|
||||
*/
|
||||
UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength)
|
||||
{
|
||||
if (!s || !orderType || !orderLength)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */
|
||||
Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -96,8 +95,10 @@ wStream* rail_pdu_init(size_t length)
|
||||
{
|
||||
wStream* s;
|
||||
s = Stream_New(NULL, length + RAIL_PDU_HEADER_LENGTH);
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
|
||||
return s;
|
||||
}
|
||||
@ -113,7 +114,6 @@ UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -134,7 +134,6 @@ UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshake
|
||||
|
||||
Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
|
||||
Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -59,13 +59,13 @@ static UINT irp_free(IRP* irp)
|
||||
*/
|
||||
static UINT irp_complete(IRP* irp)
|
||||
{
|
||||
int pos;
|
||||
size_t pos;
|
||||
rdpdrPlugin* rdpdr;
|
||||
UINT error;
|
||||
|
||||
rdpdr = (rdpdrPlugin*) irp->devman->plugin;
|
||||
|
||||
pos = (int) Stream_GetPosition(irp->output);
|
||||
pos = Stream_GetPosition(irp->output);
|
||||
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4);
|
||||
Stream_Write_UINT32(irp->output, irp->IoStatus); /* IoStatus (4 bytes) */
|
||||
Stream_SetPosition(irp->output, pos);
|
||||
|
||||
@ -118,9 +118,9 @@ void first_hotplug(rdpdrPlugin* rdpdr)
|
||||
{
|
||||
}
|
||||
|
||||
static void* drive_hotplug_thread_func(void* arg)
|
||||
static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
|
||||
{
|
||||
return NULL;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
|
||||
@ -280,7 +280,7 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
return DefWindowProc(hWnd, Msg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void* drive_hotplug_thread_func(void* arg)
|
||||
static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
|
||||
{
|
||||
rdpdrPlugin* rdpdr;
|
||||
WNDCLASSEX wnd_cls;
|
||||
@ -331,7 +331,7 @@ static void* drive_hotplug_thread_func(void* arg)
|
||||
}
|
||||
|
||||
UnregisterDeviceNotification(hDevNotify);
|
||||
return NULL;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,6 +420,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr)
|
||||
|
||||
for (j = 0; j < count; j++)
|
||||
{
|
||||
char* path = NULL;
|
||||
BOOL dev_found = FALSE;
|
||||
device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(
|
||||
rdpdr->devman->devices, (void*)keys[j]);
|
||||
@ -430,13 +431,19 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr)
|
||||
if (device_ext->path == NULL)
|
||||
continue;
|
||||
|
||||
/* not plugable device */
|
||||
if (strstr(device_ext->path, "/Volumes/") == NULL)
|
||||
if (ConvertFromUnicode(CP_UTF8, 0, device_ext->path, 0, &path, 0, NULL, FALSE) <= 0)
|
||||
continue;
|
||||
|
||||
/* not plugable device */
|
||||
if (strstr(path, "/Volumes/") == NULL)
|
||||
{
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (strstr(device_ext->path, dev_array[i].path) != NULL)
|
||||
if (strstr(path, dev_array[i].path) != NULL)
|
||||
{
|
||||
dev_found = TRUE;
|
||||
dev_array[i].to_add = FALSE;
|
||||
@ -444,6 +451,8 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr)
|
||||
}
|
||||
}
|
||||
|
||||
free(path);
|
||||
|
||||
if (!dev_found)
|
||||
{
|
||||
devman_unregister_device(rdpdr->devman, (void*)keys[j]);
|
||||
@ -549,7 +558,7 @@ void first_hotplug(rdpdrPlugin* rdpdr)
|
||||
}
|
||||
}
|
||||
|
||||
static void* drive_hotplug_thread_func(void* arg)
|
||||
static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
|
||||
{
|
||||
rdpdrPlugin* rdpdr;
|
||||
FSEventStreamRef fsev;
|
||||
@ -570,7 +579,7 @@ static void* drive_hotplug_thread_func(void* arg)
|
||||
FSEventStreamStop(fsev);
|
||||
FSEventStreamRelease(fsev);
|
||||
ExitThread(CHANNEL_RC_OK);
|
||||
return NULL;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -914,7 +923,7 @@ static void first_hotplug(rdpdrPlugin* rdpdr)
|
||||
}
|
||||
}
|
||||
|
||||
static void* drive_hotplug_thread_func(void* arg)
|
||||
static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
|
||||
{
|
||||
rdpdrPlugin* rdpdr;
|
||||
int mfd;
|
||||
@ -985,8 +994,8 @@ out:
|
||||
"drive_hotplug_thread_func reported an error");
|
||||
|
||||
CloseHandle(rdpdr->stopEvent);
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1051,18 +1060,23 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr)
|
||||
{
|
||||
device = settings->DeviceArray[index];
|
||||
|
||||
if (device->Name && (strcmp(device->Name, "*") == 0))
|
||||
if (device->Type == RDPDR_DTYP_FILESYSTEM)
|
||||
{
|
||||
first_hotplug(rdpdr);
|
||||
RDPDR_DRIVE* drive = (RDPDR_DRIVE*)device;
|
||||
|
||||
if (!(rdpdr->hotplugThread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL)))
|
||||
if (drive->Path && (strcmp(drive->Path, "*") == 0))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
first_hotplug(rdpdr);
|
||||
|
||||
continue;
|
||||
if (!(rdpdr->hotplugThread = CreateThread(NULL, 0,
|
||||
drive_hotplug_thread_func, rdpdr, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = devman_load_device_service(rdpdr->devman, device,
|
||||
@ -1185,12 +1199,12 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr,
|
||||
{
|
||||
int i;
|
||||
BYTE c;
|
||||
int pos;
|
||||
size_t pos;
|
||||
int index;
|
||||
wStream* s;
|
||||
UINT32 count;
|
||||
int data_len;
|
||||
int count_pos;
|
||||
size_t data_len;
|
||||
size_t count_pos;
|
||||
DEVICE* device;
|
||||
int keyCount;
|
||||
ULONG_PTR* pKeys;
|
||||
@ -1204,7 +1218,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr,
|
||||
|
||||
Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */
|
||||
Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */
|
||||
count_pos = (int) Stream_GetPosition(s);
|
||||
count_pos = Stream_GetPosition(s);
|
||||
count = 0;
|
||||
Stream_Seek_UINT32(s); /* deviceCount */
|
||||
pKeys = NULL;
|
||||
@ -1225,7 +1239,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr,
|
||||
if ((rdpdr->versionMinor == 0x0005) ||
|
||||
(device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn)
|
||||
{
|
||||
data_len = (int)(device->data == NULL ? 0 : Stream_GetPosition(device->data));
|
||||
data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data));
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, 20 + data_len))
|
||||
{
|
||||
@ -1259,7 +1273,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr,
|
||||
}
|
||||
|
||||
free(pKeys);
|
||||
pos = (int) Stream_GetPosition(s);
|
||||
pos = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, count_pos);
|
||||
Stream_Write_UINT32(s, count);
|
||||
Stream_SetPosition(s, pos);
|
||||
@ -1609,7 +1623,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DW
|
||||
return;
|
||||
}
|
||||
|
||||
static void* rdpdr_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -1619,7 +1633,7 @@ static void* rdpdr_virtual_channel_client_thread(void* arg)
|
||||
if (!rdpdr)
|
||||
{
|
||||
ExitThread((DWORD) CHANNEL_RC_NULL_DATA);
|
||||
return NULL;
|
||||
return CHANNEL_RC_NULL_DATA;
|
||||
}
|
||||
|
||||
if ((error = rdpdr_process_connect(rdpdr)))
|
||||
@ -1630,8 +1644,8 @@ static void* rdpdr_virtual_channel_client_thread(void* arg)
|
||||
setChannelError(rdpdr->rdpcontext, error,
|
||||
"rdpdr_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD) error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
while (1)
|
||||
@ -1657,14 +1671,14 @@ static void* rdpdr_virtual_channel_client_thread(void* arg)
|
||||
"rdpdr_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD) error);
|
||||
return NULL;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1695,7 +1709,7 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr,
|
||||
}
|
||||
|
||||
if (!(rdpdr->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0,
|
||||
rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0,
|
||||
NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
|
||||
@ -149,12 +149,9 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext*
|
||||
Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */
|
||||
Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */
|
||||
Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */
|
||||
|
||||
if (UnicodeFlag > 1) /* must be 0x00000000 or 0x00000001 */
|
||||
{
|
||||
WLog_ERR(TAG, "invalid UnicodeFlag value: 0x%08"PRIX32"", UnicodeFlag);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
/* UnicodeFlag is either 0 or 1, the other 31 bits must be ignored.
|
||||
*/
|
||||
UnicodeFlag = UnicodeFlag & 0x00000001;
|
||||
|
||||
/**
|
||||
* Caution: ComputerNameLen is given *bytes*,
|
||||
@ -768,7 +765,6 @@ static UINT rdpdr_server_receive_device_list_announce_request(
|
||||
UINT32 DeviceId;
|
||||
char PreferredDosName[9];
|
||||
UINT32 DeviceDataLength;
|
||||
BYTE* DeviceData;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
{
|
||||
@ -800,7 +796,6 @@ static UINT rdpdr_server_receive_device_list_announce_request(
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
DeviceData = Stream_Pointer(s);
|
||||
WLog_DBG(TAG, "Device %d Name: %s Id: 0x%08"PRIX32" DataLength: %"PRIu32"",
|
||||
i, PreferredDosName, DeviceId, DeviceDataLength);
|
||||
|
||||
@ -1134,7 +1129,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s,
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* rdpdr_server_thread(void* arg)
|
||||
static DWORD WINAPI rdpdr_server_thread(LPVOID arg)
|
||||
{
|
||||
wStream* s;
|
||||
DWORD status;
|
||||
@ -1150,7 +1145,6 @@ static void* rdpdr_server_thread(void* arg)
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = NULL;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
if (!s)
|
||||
@ -1239,8 +1233,8 @@ out:
|
||||
setChannelError(context->rdpcontext, error,
|
||||
"rdpdr_server_thread reported an error");
|
||||
|
||||
ExitThread((DWORD) error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1266,7 +1260,7 @@ static UINT rdpdr_server_start(RdpdrServerContext* context)
|
||||
}
|
||||
|
||||
if (!(context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpdr_server_thread, (void*) context, 0, NULL)))
|
||||
rdpdr_server_thread, (void*) context, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(context->priv->StopEvent);
|
||||
|
||||
@ -169,7 +169,7 @@ UINT rdpei_add_frame(RdpeiClientContext* context)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void* rdpei_schedule_thread(void* arg)
|
||||
static DWORD WINAPI rdpei_schedule_thread(LPVOID arg)
|
||||
{
|
||||
DWORD status;
|
||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) arg;
|
||||
@ -228,12 +228,12 @@ static void* rdpei_schedule_thread(void* arg)
|
||||
|
||||
out:
|
||||
|
||||
if (error && rdpei->rdpcontext)
|
||||
if (error && rdpei && rdpei->rdpcontext)
|
||||
setChannelError(rdpei->rdpcontext, error,
|
||||
"rdpei_schedule_thread reported an error");
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -653,7 +653,7 @@ static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!(rdpei->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
|
||||
if (!(rdpei->thread = CreateThread(NULL, 0,
|
||||
rdpei_schedule_thread, (void*) rdpei, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
|
||||
@ -139,8 +139,8 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
|
||||
wStream* s;
|
||||
RDPGFX_AVC420_BITMAP_STREAM h264;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
s = Stream_New(cmd->data, cmd->length);
|
||||
|
||||
s = Stream_New(cmd->data, cmd->length);
|
||||
if (!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
@ -186,7 +186,6 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
|
||||
s = Stream_New(cmd->data, cmd->length);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
@ -275,7 +274,7 @@ UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
PROFILER_ENTER(context->SurfaceProfiler);
|
||||
PROFILER_ENTER(context->SurfaceProfiler)
|
||||
|
||||
switch (cmd->codecId)
|
||||
{
|
||||
@ -304,6 +303,6 @@ UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
PROFILER_EXIT(context->SurfaceProfiler);
|
||||
PROFILER_EXIT(context->SurfaceProfiler)
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -74,7 +74,10 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
||||
if (gfx->ThinClient)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT;
|
||||
|
||||
if (gfx->SmallCache)
|
||||
/* in CAPVERSION_8 the spec says that we should not have both
|
||||
* thinclient and smallcache (and thinclient implies a small cache)
|
||||
*/
|
||||
if (gfx->SmallCache && !gfx->ThinClient)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
||||
|
||||
capsSet = &capsSets[pdu.capsSetCount++];
|
||||
@ -92,27 +95,29 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
|
||||
#endif
|
||||
|
||||
capsSet = &capsSets[pdu.capsSetCount++];
|
||||
capsSet->version = RDPGFX_CAPVERSION_10;
|
||||
capsSet->flags = 0;
|
||||
if (!gfx->H264 || gfx->AVC444)
|
||||
{
|
||||
capsSet = &capsSets[pdu.capsSetCount++];
|
||||
capsSet->version = RDPGFX_CAPVERSION_10;
|
||||
capsSet->flags = 0;
|
||||
|
||||
if (gfx->SmallCache)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
||||
if (gfx->SmallCache)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
||||
|
||||
#ifdef WITH_GFX_H264
|
||||
if (!gfx->AVC444)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
||||
if (!gfx->AVC444)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
||||
#else
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
||||
#endif
|
||||
|
||||
capsSets[pdu.capsSetCount] = *capsSet;
|
||||
capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_102;
|
||||
capsSets[pdu.capsSetCount] = *capsSet;
|
||||
capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_103;
|
||||
capsSets[pdu.capsSetCount] = *capsSet;
|
||||
capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_102;
|
||||
capsSets[pdu.capsSetCount] = *capsSet;
|
||||
capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_103;
|
||||
}
|
||||
|
||||
header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount *
|
||||
RDPGFX_CAPSET_SIZE);
|
||||
header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE);
|
||||
WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount);
|
||||
s = Stream_New(NULL, header.pduLength);
|
||||
|
||||
@ -193,8 +198,8 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
||||
header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE;
|
||||
header.pduLength = RDPGFX_HEADER_SIZE + 12;
|
||||
WLog_Print(gfx->log, WLOG_DEBUG, "SendFrameAcknowledgePdu: %"PRIu32"", pdu->frameId);
|
||||
s = Stream_New(NULL, header.pduLength);
|
||||
|
||||
s = Stream_New(NULL, header.pduLength);
|
||||
if (!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
@ -228,8 +233,8 @@ static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callb
|
||||
header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE;
|
||||
header.pduLength = RDPGFX_HEADER_SIZE + 12;
|
||||
WLog_Print(gfx->log, WLOG_DEBUG, "SendQoeFrameAcknowledgePdu: %"PRIu32"", pdu->frameId);
|
||||
s = Stream_New(NULL, header.pduLength);
|
||||
|
||||
s = Stream_New(NULL, header.pduLength);
|
||||
if (!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
@ -267,6 +272,7 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
GraphicsResetEventArgs graphicsReset;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 12)
|
||||
{
|
||||
@ -284,9 +290,7 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount,
|
||||
sizeof(MONITOR_DEF));
|
||||
|
||||
pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF));
|
||||
if (!pdu.monitorDefArray)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
@ -332,6 +336,12 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "context->ResetGraphics failed with error %"PRIu32"", error);
|
||||
}
|
||||
|
||||
/* some listeners may be interested (namely the display channel) */
|
||||
EventArgsInit(&graphicsReset, "xfreerdp");
|
||||
graphicsReset.width = pdu.width;
|
||||
graphicsReset.height = pdu.height;
|
||||
PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset);
|
||||
|
||||
free(pdu.monitorDefArray);
|
||||
return error;
|
||||
}
|
||||
@ -398,7 +408,6 @@ static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback
|
||||
}
|
||||
|
||||
pdu.cacheSlots = (UINT16*) calloc(pdu.importedEntriesCount, sizeof(UINT16));
|
||||
|
||||
if (!pdu.cacheSlots)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
@ -810,8 +819,7 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea
|
||||
|
||||
Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
|
||||
|
||||
if ((error = rdpgfx_read_color32(s,
|
||||
&(pdu.fillPixel)))) /* fillPixel (4 bytes) */
|
||||
if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel)))) /* fillPixel (4 bytes) */
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_color32 failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
@ -826,7 +834,6 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea
|
||||
}
|
||||
|
||||
pdu.fillRects = (RECTANGLE_16*) calloc(pdu.fillRectCount, sizeof(RECTANGLE_16));
|
||||
|
||||
if (!pdu.fillRects)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
@ -898,9 +905,7 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK*
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount,
|
||||
sizeof(RDPGFX_POINT16));
|
||||
|
||||
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
||||
if (!pdu.destPts)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
@ -1015,9 +1020,7 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount,
|
||||
sizeof(RDPGFX_POINT16));
|
||||
|
||||
pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16));
|
||||
if (!pdu.destPts)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
@ -1135,7 +1138,7 @@ static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callb
|
||||
*/
|
||||
static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
int beg, end;
|
||||
size_t beg, end;
|
||||
RDPGFX_HEADER header;
|
||||
UINT error;
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||
@ -1148,11 +1151,9 @@ static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
return error;
|
||||
}
|
||||
|
||||
#if 1
|
||||
WLog_Print(gfx->log, WLOG_DEBUG, "cmdId: %s (0x%04"PRIX16") flags: 0x%04"PRIX16" pduLength: %"PRIu32"",
|
||||
rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
|
||||
header.pduLength);
|
||||
#endif
|
||||
|
||||
switch (header.cmdId)
|
||||
{
|
||||
@ -1305,8 +1306,8 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback*
|
||||
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
status = zgfx_decompress(gfx->zgfx, Stream_Pointer(data),
|
||||
Stream_GetRemainingLength(data), &pDstData, &DstSize, 0);
|
||||
status = zgfx_decompress(gfx->zgfx, Stream_Pointer(data), Stream_GetRemainingLength(data),
|
||||
&pDstData, &DstSize, 0);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
@ -1315,7 +1316,6 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback*
|
||||
}
|
||||
|
||||
s = Stream_New(pDstData, DstSize);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
@ -1360,6 +1360,7 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
|
||||
WLog_Print(gfx->log, WLOG_DEBUG, "OnClose");
|
||||
free(callback);
|
||||
gfx->UnacknowledgedFrames = 0;
|
||||
@ -1419,11 +1420,9 @@ static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback*
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
RDPGFX_CHANNEL_CALLBACK* callback;
|
||||
RDPGFX_LISTENER_CALLBACK* listener_callback = (RDPGFX_LISTENER_CALLBACK*)
|
||||
pListenerCallback;
|
||||
callback = (RDPGFX_CHANNEL_CALLBACK*) calloc(1,
|
||||
sizeof(RDPGFX_CHANNEL_CALLBACK));
|
||||
RDPGFX_LISTENER_CALLBACK* listener_callback = (RDPGFX_LISTENER_CALLBACK*)pListenerCallback;
|
||||
|
||||
callback = (RDPGFX_CHANNEL_CALLBACK*) calloc(1, sizeof(RDPGFX_CHANNEL_CALLBACK));
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
@ -1451,17 +1450,15 @@ static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin,
|
||||
{
|
||||
UINT error;
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) pPlugin;
|
||||
gfx->listener_callback = (RDPGFX_LISTENER_CALLBACK*) calloc(1,
|
||||
sizeof(RDPGFX_LISTENER_CALLBACK));
|
||||
|
||||
gfx->listener_callback = (RDPGFX_LISTENER_CALLBACK*) calloc(1, sizeof(RDPGFX_LISTENER_CALLBACK));
|
||||
if (!gfx->listener_callback)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
gfx->listener_callback->iface.OnNewChannelConnection =
|
||||
rdpgfx_on_new_channel_connection;
|
||||
gfx->listener_callback->iface.OnNewChannelConnection = rdpgfx_on_new_channel_connection;
|
||||
gfx->listener_callback->plugin = pPlugin;
|
||||
gfx->listener_callback->channel_mgr = pChannelMgr;
|
||||
error = pChannelMgr->CreateListener(pChannelMgr, RDPGFX_DVC_CHANNEL_NAME, 0,
|
||||
@ -1598,6 +1595,7 @@ static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context,
|
||||
if (!pSurfaceIds)
|
||||
{
|
||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
||||
free(pKeys);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -1634,7 +1632,11 @@ static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context,
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
||||
|
||||
if (cacheSlot >= gfx->MaxCacheSlot)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: invalid cache slot %"PRIu16" maxAllowed=%"PRIu16"", __FUNCTION__,
|
||||
cacheSlot, gfx->MaxCacheSlot);
|
||||
return ERROR_INVALID_INDEX;
|
||||
}
|
||||
|
||||
gfx->CacheSlots[cacheSlot] = pData;
|
||||
return CHANNEL_RC_OK;
|
||||
@ -1646,7 +1648,11 @@ static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cac
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle;
|
||||
|
||||
if (cacheSlot >= gfx->MaxCacheSlot)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: invalid cache slot %"PRIu16" maxAllowed=%"PRIu16"", __FUNCTION__,
|
||||
cacheSlot, gfx->MaxCacheSlot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pData = gfx->CacheSlots[cacheSlot];
|
||||
return pData;
|
||||
@ -1684,7 +1690,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
if (!gfx->log)
|
||||
{
|
||||
free(gfx);
|
||||
WLog_ERR(TAG, "Failed to aquire reference to WLog %s", TAG);
|
||||
WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -1693,8 +1699,9 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
gfx->iface.Connected = NULL;
|
||||
gfx->iface.Disconnected = NULL;
|
||||
gfx->iface.Terminated = rdpgfx_plugin_terminated;
|
||||
gfx->SurfaceTable = HashTable_New(TRUE);
|
||||
gfx->rdpcontext = ((freerdp *)gfx->settings->instance)->context;
|
||||
|
||||
gfx->SurfaceTable = HashTable_New(TRUE);
|
||||
if (!gfx->SurfaceTable)
|
||||
{
|
||||
free(gfx);
|
||||
@ -1713,12 +1720,9 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
if (gfx->H264)
|
||||
gfx->SmallCache = TRUE;
|
||||
|
||||
if (gfx->SmallCache)
|
||||
gfx->ThinClient = FALSE;
|
||||
|
||||
gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600;
|
||||
context = (RdpgfxClientContext*) calloc(1, sizeof(RdpgfxClientContext));
|
||||
gfx->MaxCacheSlot = gfx->SmallCache ? 4096 : 25600;
|
||||
|
||||
context = (RdpgfxClientContext *)calloc(1, sizeof(RdpgfxClientContext));
|
||||
if (!context)
|
||||
{
|
||||
free(gfx);
|
||||
|
||||
@ -508,6 +508,10 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta)
|
||||
RECTANGLE_16* regionRect;
|
||||
RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, 4 + meta->numRegionRects * 10))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
|
||||
|
||||
for (index = 0; index < meta->numRegionRects; index++)
|
||||
@ -552,6 +556,9 @@ static INLINE UINT rdpgfx_write_h264_avc420(wStream* s,
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, havc420->length))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write(s, havc420->data, havc420->length);
|
||||
return error;
|
||||
}
|
||||
@ -584,7 +591,7 @@ static UINT rdpgfx_write_surface_command(wStream* s,
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Format %s not supported!", GetColorFormatName(cmd->format));
|
||||
WLog_ERR(TAG, "Format %s not supported!", FreeRDPGetColorFormatName(cmd->format));
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
@ -623,12 +630,11 @@ static UINT rdpgfx_write_surface_command(wStream* s,
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else if (cmd->codecId == RDPGFX_CODECID_AVC444)
|
||||
else if ((cmd->codecId == RDPGFX_CODECID_AVC444) || (cmd->codecId == RDPGFX_CODECID_AVC444v2))
|
||||
{
|
||||
havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
|
||||
havc420 = &(havc444->bitstream[0]);
|
||||
/* avc420EncodedBitstreamInfo (4 bytes) */
|
||||
Stream_Write_UINT32(s, havc420->length | (havc444->LC << 30UL));
|
||||
havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
|
||||
Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 | (havc444->LC << 30UL));
|
||||
/* avc420EncodedBitstream1 */
|
||||
error = rdpgfx_write_h264_avc420(s, havc420);
|
||||
|
||||
@ -641,7 +647,7 @@ static UINT rdpgfx_write_surface_command(wStream* s,
|
||||
/* avc420EncodedBitstream2 */
|
||||
if (havc444->LC == 0)
|
||||
{
|
||||
havc420 = &(havc444->bitstream[0]);
|
||||
havc420 = &(havc444->bitstream[1]);
|
||||
error = rdpgfx_write_h264_avc420(s, havc420);
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
@ -656,7 +662,6 @@ static UINT rdpgfx_write_surface_command(wStream* s,
|
||||
Stream_Write(s, cmd->data, cmd->length);
|
||||
}
|
||||
|
||||
assert(Stream_GetPosition(s) <= Stream_Capacity(s));
|
||||
/* Fill actual bitmap data length */
|
||||
bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
|
||||
Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32));
|
||||
@ -1253,7 +1258,7 @@ static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context,
|
||||
*/
|
||||
static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
|
||||
{
|
||||
int beg, end;
|
||||
size_t beg, end;
|
||||
RDPGFX_HEADER header;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
beg = Stream_GetPosition(s);
|
||||
@ -1273,28 +1278,28 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
|
||||
case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
|
||||
if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
|
||||
WLog_ERR(TAG, "rdpgfx_recv_frame_acknowledge_pdu "
|
||||
"failed with error %"PRIu32"!", error);
|
||||
"failed with error %"PRIu32"!", error);
|
||||
|
||||
break;
|
||||
|
||||
case RDPGFX_CMDID_CACHEIMPORTOFFER:
|
||||
if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
|
||||
WLog_ERR(TAG, "rdpgfx_recv_cache_import_offer_pdu "
|
||||
"failed with error %"PRIu32"!", error);
|
||||
"failed with error %"PRIu32"!", error);
|
||||
|
||||
break;
|
||||
|
||||
case RDPGFX_CMDID_CAPSADVERTISE:
|
||||
if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
|
||||
WLog_ERR(TAG, "rdpgfx_recv_caps_advertise_pdu "
|
||||
"failed with error %"PRIu32"!", error);
|
||||
"failed with error %"PRIu32"!", error);
|
||||
|
||||
break;
|
||||
|
||||
case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
|
||||
if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
|
||||
WLog_ERR(TAG, "rdpgfx_recv_qoe_frame_acknowledge_pdu "
|
||||
"failed with error %"PRIu32"!", error);
|
||||
"failed with error %"PRIu32"!", error);
|
||||
|
||||
break;
|
||||
|
||||
@ -1322,7 +1327,7 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* rdpgfx_server_thread_func(void* arg)
|
||||
static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
|
||||
{
|
||||
RdpgfxServerContext* context = (RdpgfxServerContext*) arg;
|
||||
RdpgfxServerPrivate* priv = context->priv;
|
||||
@ -1333,7 +1338,6 @@ static void* rdpgfx_server_thread_func(void* arg)
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
buffer = NULL;
|
||||
nCount = 0;
|
||||
|
||||
events[nCount++] = priv->stopEvent;
|
||||
events[nCount++] = priv->channelEvent;
|
||||
|
||||
@ -1365,8 +1369,8 @@ static void* rdpgfx_server_thread_func(void* arg)
|
||||
setChannelError(context->rdpcontext, error,
|
||||
"rdpgfx_server_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
|
||||
@ -1433,7 +1437,6 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
|
||||
}
|
||||
|
||||
if (!(priv->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)
|
||||
rdpgfx_server_thread_func,
|
||||
(void*) context, 0, NULL)))
|
||||
{
|
||||
@ -1654,7 +1657,7 @@ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
|
||||
if ((ret = rdpgfx_server_receive_pdu(context, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpgfx_server_receive_pdu "
|
||||
"failed with error %"PRIu32"!", ret);
|
||||
"failed with error %"PRIu32"!", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,8 @@ struct rdpsnd_mac_plugin
|
||||
|
||||
UINT32 latency;
|
||||
AUDIO_FORMAT format;
|
||||
int audioBufferIndex;
|
||||
size_t lastAudioBufferIndex;
|
||||
size_t audioBufferIndex;
|
||||
|
||||
AudioQueueRef audioQueue;
|
||||
AudioStreamBasicDescription audioFormat;
|
||||
@ -70,7 +71,12 @@ typedef struct rdpsnd_mac_plugin rdpsndMacPlugin;
|
||||
|
||||
static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
{
|
||||
|
||||
rdpsndMacPlugin* mac = (rdpsndMacPlugin*)inUserData;
|
||||
|
||||
if (inBuffer == mac->audioBuffers[mac->lastAudioBufferIndex]) {
|
||||
AudioQueuePause(mac->audioQueue);
|
||||
mac->isPlaying = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
|
||||
@ -193,10 +199,16 @@ static void rdpsnd_mac_close(rdpsndDevicePlugin* device)
|
||||
|
||||
if (mac->isOpen)
|
||||
{
|
||||
size_t index;
|
||||
mac->isOpen = FALSE;
|
||||
|
||||
AudioQueueStop(mac->audioQueue, true);
|
||||
|
||||
for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++)
|
||||
{
|
||||
AudioQueueFreeBuffer(mac->audioQueue, mac->audioBuffers[index]);
|
||||
}
|
||||
|
||||
AudioQueueDispose(mac->audioQueue, true);
|
||||
mac->audioQueue = NULL;
|
||||
|
||||
@ -338,12 +350,9 @@ static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
|
||||
wave->wTimeStampB = wave->wTimeStampA + wave->wLocalTimeB - wave->wLocalTimeA;
|
||||
mac->lastStartTime = outActualStartTime.mSampleTime;
|
||||
|
||||
mac->lastAudioBufferIndex = mac->audioBufferIndex;
|
||||
mac->audioBufferIndex++;
|
||||
|
||||
if (mac->audioBufferIndex >= MAC_AUDIO_QUEUE_NUM_BUFFERS)
|
||||
{
|
||||
mac->audioBufferIndex = 0;
|
||||
}
|
||||
mac->audioBufferIndex %= MAC_AUDIO_QUEUE_NUM_BUFFERS;
|
||||
|
||||
device->Start(device);
|
||||
}
|
||||
|
||||
@ -82,22 +82,25 @@ static int rdpsnd_oss_get_format(AUDIO_FORMAT* format)
|
||||
switch (format->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_PCM:
|
||||
|
||||
switch (format->wBitsPerSample)
|
||||
{
|
||||
case 8:
|
||||
return AFMT_S8;
|
||||
|
||||
case 16:
|
||||
return AFMT_S16_LE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WAVE_FORMAT_ALAW:
|
||||
return AFMT_A_LAW;
|
||||
#if 0 /* This does not work on my desktop. */
|
||||
|
||||
case WAVE_FORMAT_MULAW:
|
||||
return AFMT_MU_LAW;
|
||||
#endif
|
||||
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
return AFMT_S16_LE;
|
||||
@ -117,20 +120,19 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT
|
||||
switch (format->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_PCM:
|
||||
|
||||
if (format->cbSize != 0 ||
|
||||
format->nSamplesPerSec > 48000 ||
|
||||
(format->wBitsPerSample != 8 && format->wBitsPerSample != 16) ||
|
||||
(format->nChannels != 1 && format->nChannels != 2))
|
||||
format->nSamplesPerSec > 48000 ||
|
||||
(format->wBitsPerSample != 8 && format->wBitsPerSample != 16) ||
|
||||
(format->nChannels != 1 && format->nChannels != 2))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
|
||||
if (format->nSamplesPerSec > 48000 ||
|
||||
format->wBitsPerSample != 4 ||
|
||||
(format->nChannels != 1 && format->nChannels != 2))
|
||||
format->wBitsPerSample != 4 ||
|
||||
(format->nChannels != 1 && format->nChannels != 2))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
@ -379,17 +381,19 @@ static BOOL rdpsnd_oss_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave
|
||||
{
|
||||
case WAVE_FORMAT_ADPCM:
|
||||
oss->dsp_context->decode_ms_adpcm(oss->dsp_context,
|
||||
wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign);
|
||||
wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign);
|
||||
wave->length = oss->dsp_context->adpcm_size;
|
||||
wave->data = oss->dsp_context->adpcm_buffer;
|
||||
break;
|
||||
|
||||
case WAVE_FORMAT_DVI_ADPCM:
|
||||
oss->dsp_context->decode_ima_adpcm(oss->dsp_context,
|
||||
wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign);
|
||||
wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign);
|
||||
wave->length = oss->dsp_context->adpcm_size;
|
||||
wave->data = oss->dsp_context->adpcm_buffer;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -442,12 +446,14 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device;
|
||||
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, rdpsnd_oss_args, flags, oss, NULL, NULL);
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, rdpsnd_oss_args, flags,
|
||||
oss, NULL, NULL);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
arg = rdpsnd_oss_args;
|
||||
errno = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@ -458,10 +464,21 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a
|
||||
CommandLineSwitchCase(arg, "dev")
|
||||
{
|
||||
str_num = _strdup(arg->Value);
|
||||
|
||||
if (!str_num)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
oss->dev_unit = strtol(str_num, &eptr, 10);
|
||||
{
|
||||
long val = strtol(str_num, &eptr, 10);
|
||||
|
||||
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
|
||||
{
|
||||
free(str_num);
|
||||
return CHANNEL_RC_NULL_DATA;
|
||||
}
|
||||
|
||||
oss->dev_unit = val;
|
||||
}
|
||||
|
||||
if (oss->dev_unit < 0 || *eptr != '\0')
|
||||
oss->dev_unit = -1;
|
||||
@ -491,8 +508,10 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
|
||||
ADDIN_ARGV* args;
|
||||
rdpsndOssPlugin* oss;
|
||||
oss = (rdpsndOssPlugin*)calloc(1, sizeof(rdpsndOssPlugin));
|
||||
|
||||
if (!oss)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
oss->device.Open = rdpsnd_oss_open;
|
||||
oss->device.FormatSupported = rdpsnd_oss_format_supported;
|
||||
oss->device.SetFormat = rdpsnd_oss_set_format;
|
||||
@ -508,6 +527,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
|
||||
args = pEntryPoints->args;
|
||||
rdpsnd_oss_parse_addin_args((rdpsndDevicePlugin*)oss, args);
|
||||
oss->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
if (!oss->dsp_context)
|
||||
{
|
||||
free(oss);
|
||||
@ -515,6 +535,5 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
|
||||
}
|
||||
|
||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)oss);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -191,6 +191,11 @@ static void rdpsnd_pulse_close(rdpsndDevicePlugin* device)
|
||||
{
|
||||
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
|
||||
|
||||
#ifdef WITH_GSM
|
||||
if (pulse->gsm_context)
|
||||
gsm_destroy(pulse->gsm_context);
|
||||
#endif
|
||||
|
||||
if (!pulse->context || !pulse->stream)
|
||||
return;
|
||||
|
||||
@ -364,6 +369,10 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
|
||||
pulse->mainloop = NULL;
|
||||
}
|
||||
|
||||
#ifdef WITH_GSM
|
||||
Stream_Free(pulse->gsmBuffer, TRUE);
|
||||
#endif
|
||||
|
||||
free(pulse->device_name);
|
||||
freerdp_dsp_context_free(pulse->dsp_context);
|
||||
free(pulse);
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/wlog.h>
|
||||
@ -102,7 +103,7 @@ struct rdpsnd_plugin
|
||||
*/
|
||||
static UINT rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave);
|
||||
|
||||
static void* rdpsnd_schedule_thread(void* arg)
|
||||
static DWORD WINAPI rdpsnd_schedule_thread(LPVOID arg)
|
||||
{
|
||||
wMessage message;
|
||||
UINT16 wTimeDiff;
|
||||
@ -182,8 +183,8 @@ static void* rdpsnd_schedule_thread(void* arg)
|
||||
setChannelError(rdpsnd->rdpcontext, error,
|
||||
"rdpsnd_schedule_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -224,8 +225,8 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
|
||||
return;
|
||||
|
||||
rdpsnd->ClientFormats = (AUDIO_FORMAT*) calloc(
|
||||
rdpsnd->NumberOfServerFormats,
|
||||
sizeof(AUDIO_FORMAT));
|
||||
rdpsnd->NumberOfServerFormats,
|
||||
sizeof(AUDIO_FORMAT));
|
||||
|
||||
if (!rdpsnd->ClientFormats)
|
||||
return;
|
||||
@ -871,6 +872,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
arg = rdpsnd_args;
|
||||
errno = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@ -890,23 +892,43 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
|
||||
}
|
||||
CommandLineSwitchCase(arg, "format")
|
||||
{
|
||||
rdpsnd->fixedFormat = atoi(arg->Value);
|
||||
unsigned long val = strtoul(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT16_MAX))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
rdpsnd->fixedFormat = val;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "rate")
|
||||
{
|
||||
rdpsnd->fixedRate = atoi(arg->Value);
|
||||
unsigned long val = strtoul(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT32_MAX))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
rdpsnd->fixedRate = val;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "channel")
|
||||
{
|
||||
rdpsnd->fixedChannel = atoi(arg->Value);
|
||||
unsigned long val = strtoul(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val > UINT16_MAX))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
rdpsnd->fixedChannel = val;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "latency")
|
||||
{
|
||||
rdpsnd->latency = atoi(arg->Value);
|
||||
unsigned long val = strtoul(arg->Value, NULL, 0);
|
||||
|
||||
if ((errno != 0) || (val > INT32_MAX))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
rdpsnd->latency = val;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "quality")
|
||||
{
|
||||
int wQualityMode = DYNAMIC_QUALITY;
|
||||
long wQualityMode = DYNAMIC_QUALITY;
|
||||
|
||||
if (_stricmp(arg->Value, "dynamic") == 0)
|
||||
wQualityMode = DYNAMIC_QUALITY;
|
||||
@ -915,7 +937,12 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
|
||||
else if (_stricmp(arg->Value, "high") == 0)
|
||||
wQualityMode = HIGH_QUALITY;
|
||||
else
|
||||
wQualityMode = atoi(arg->Value);
|
||||
{
|
||||
wQualityMode = strtol(arg->Value, NULL, 0);
|
||||
|
||||
if (errno != 0)
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
if ((wQualityMode < 0) || (wQualityMode > 2))
|
||||
wQualityMode = DYNAMIC_QUALITY;
|
||||
@ -1088,7 +1115,7 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
|
||||
}
|
||||
|
||||
rdpsnd->ScheduleThread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
|
||||
rdpsnd_schedule_thread,
|
||||
(void*) rdpsnd, 0, NULL);
|
||||
|
||||
if (!rdpsnd->ScheduleThread)
|
||||
@ -1244,7 +1271,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, D
|
||||
"rdpsnd_virtual_channel_open_event_ex reported an error");
|
||||
}
|
||||
|
||||
static void* rdpsnd_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI rdpsnd_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -1295,8 +1322,8 @@ out:
|
||||
"rdpsnd_virtual_channel_client_thread reported an error");
|
||||
|
||||
rdpsnd_process_disconnect(rdpsnd);
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1328,7 +1355,7 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd,
|
||||
}
|
||||
|
||||
rdpsnd->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpsnd_virtual_channel_client_thread, (void*) rdpsnd,
|
||||
rdpsnd_virtual_channel_client_thread, (void*) rdpsnd,
|
||||
0, NULL);
|
||||
|
||||
if (!rdpsnd->thread)
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
*/
|
||||
UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
||||
{
|
||||
int pos;
|
||||
size_t pos;
|
||||
UINT16 i;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
@ -239,7 +239,7 @@ out_free:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* rdpsnd_server_thread(void* arg)
|
||||
static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
|
||||
{
|
||||
DWORD nCount, status;
|
||||
HANDLE events[8];
|
||||
@ -293,8 +293,8 @@ out:
|
||||
setChannelError(context->rdpcontext, error,
|
||||
"rdpsnd_server_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -574,10 +574,11 @@ out:
|
||||
static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left,
|
||||
int right)
|
||||
{
|
||||
int pos;
|
||||
size_t pos;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_SETVOLUME);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
Stream_Seek_UINT16(s);
|
||||
@ -600,7 +601,7 @@ static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left,
|
||||
*/
|
||||
static UINT rdpsnd_server_close(RdpsndServerContext* context)
|
||||
{
|
||||
int pos;
|
||||
size_t pos;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
@ -700,7 +701,7 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context)
|
||||
}
|
||||
|
||||
context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL);
|
||||
rdpsnd_server_thread, (void*) context, 0, NULL);
|
||||
|
||||
if (!context->priv->Thread)
|
||||
{
|
||||
|
||||
@ -804,7 +804,7 @@ static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam,
|
||||
"remdesk_virtual_channel_open_event_ex reported an error");
|
||||
}
|
||||
|
||||
static void* remdesk_virtual_channel_client_thread(void* arg)
|
||||
static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
|
||||
{
|
||||
wStream* data;
|
||||
wMessage message;
|
||||
@ -847,8 +847,8 @@ static void* remdesk_virtual_channel_client_thread(void* arg)
|
||||
setChannelError(remdesk->rdpcontext, error,
|
||||
"remdesk_virtual_channel_client_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -882,7 +882,7 @@ static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk,
|
||||
}
|
||||
|
||||
remdesk->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) remdesk_virtual_channel_client_thread, (void*) remdesk,
|
||||
remdesk_virtual_channel_client_thread, (void*) remdesk,
|
||||
0, NULL);
|
||||
|
||||
if (!remdesk->thread)
|
||||
@ -942,6 +942,7 @@ static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
|
||||
static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
|
||||
{
|
||||
remdesk->InitHandle = 0;
|
||||
free(remdesk->context);
|
||||
free(remdesk);
|
||||
}
|
||||
|
||||
|
||||
@ -578,7 +578,7 @@ static UINT remdesk_server_receive_pdu(RemdeskServerContext* context,
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* remdesk_server_thread(void* arg)
|
||||
static DWORD WINAPI remdesk_server_thread(LPVOID arg)
|
||||
{
|
||||
wStream* s;
|
||||
DWORD status;
|
||||
@ -700,8 +700,8 @@ out:
|
||||
setChannelError(context->rdpcontext, error,
|
||||
"remdesk_server_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -727,7 +727,7 @@ static UINT remdesk_server_start(RemdeskServerContext* context)
|
||||
}
|
||||
|
||||
if (!(context->priv->Thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) remdesk_server_thread, (void*) context, 0, NULL)))
|
||||
remdesk_server_thread, (void*) context, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(context->priv->StopEvent);
|
||||
|
||||
@ -124,20 +124,27 @@ static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
DWORD DesiredAccess;
|
||||
DWORD SharedAccess;
|
||||
DWORD CreateDisposition;
|
||||
UINT32 PathLength;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */
|
||||
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
|
||||
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input,
|
||||
CreateDisposition); /* CreateDisposition (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */
|
||||
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < PathLength)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Seek(irp->input, PathLength); /* Path (variable) */
|
||||
assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */
|
||||
#ifndef _WIN32
|
||||
@ -191,18 +198,21 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
/* dcb.fBinary = TRUE; */
|
||||
/* SetCommState(serial->hComm, &dcb); */
|
||||
assert(irp->FileId == 0);
|
||||
irp->FileId =
|
||||
irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
|
||||
irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %"PRIu32", FileId: %"PRIu32") created.",
|
||||
serial->device.name, irp->device->id, irp->FileId);
|
||||
error_handle:
|
||||
Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
static UINT serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
|
||||
|
||||
if (!CloseHandle(serial->hComm))
|
||||
@ -219,6 +229,7 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
error_handle:
|
||||
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,6 +243,10 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
UINT64 Offset;
|
||||
BYTE* buffer = NULL;
|
||||
DWORD nbRead = 0;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
@ -283,11 +298,15 @@ error_handle:
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
UINT32 Length;
|
||||
UINT64 Offset;
|
||||
DWORD nbWritten = 0;
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
@ -318,6 +337,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
serial->device.name);
|
||||
Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -334,12 +354,18 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
UINT32 OutputBufferLength;
|
||||
BYTE* OutputBuffer = NULL;
|
||||
DWORD BytesReturned = 0;
|
||||
Stream_Read_UINT32(irp->input,
|
||||
OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input,
|
||||
InputBufferLength); /* InputBufferLength (4 bytes) */
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
|
||||
if (Stream_GetRemainingLength(irp->input) < InputBufferLength)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));
|
||||
|
||||
if (OutputBuffer == NULL)
|
||||
@ -381,8 +407,7 @@ error_handle:
|
||||
* BytesReturned == OutputBufferLength when
|
||||
* CommDeviceIoControl returns FALSE */
|
||||
assert(OutputBufferLength == BytesReturned);
|
||||
Stream_Write_UINT32(irp->output,
|
||||
BytesReturned); /* OutputBufferLength (4 bytes) */
|
||||
Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */
|
||||
|
||||
if (BytesReturned > 0)
|
||||
{
|
||||
@ -425,11 +450,11 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
serial_process_irp_create(serial, irp);
|
||||
error = serial_process_irp_create(serial, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLOSE:
|
||||
serial_process_irp_close(serial, irp);
|
||||
error = serial_process_irp_close(serial, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
@ -439,7 +464,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
serial_process_irp_write(serial, irp);
|
||||
error = serial_process_irp_write(serial, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
@ -458,7 +483,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
}
|
||||
|
||||
|
||||
static void* irp_thread_func(void* arg)
|
||||
static DWORD WINAPI irp_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP_THREAD_DATA* data = (IRP_THREAD_DATA*)arg;
|
||||
UINT error;
|
||||
@ -484,8 +509,8 @@ error_out:
|
||||
* the CompletionId whereas the thread is not yet
|
||||
* terminated */
|
||||
free(data);
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@ -617,7 +642,7 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp)
|
||||
/* data freed by irp_thread_func */
|
||||
irpThread = CreateThread(NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE)irp_thread_func,
|
||||
irp_thread_func,
|
||||
(void*)data,
|
||||
0,
|
||||
NULL);
|
||||
@ -672,7 +697,7 @@ static void terminate_pending_irp_threads(SERIAL_DEVICE* serial)
|
||||
}
|
||||
|
||||
|
||||
static void* serial_thread_func(void* arg)
|
||||
static DWORD WINAPI serial_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP* irp;
|
||||
wMessage message;
|
||||
@ -711,8 +736,8 @@ static void* serial_thread_func(void* arg)
|
||||
setChannelError(serial->rdpcontext, error,
|
||||
"serial_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD) error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@ -815,7 +840,6 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
if ((name && name[0]) && (path && path[0]))
|
||||
{
|
||||
wLog* log;
|
||||
WLog_Init();
|
||||
log = WLog_Get("com.freerdp.channel.serial.client");
|
||||
WLog_Print(log, WLOG_DEBUG, "initializing");
|
||||
#ifndef __linux__ /* to be removed */
|
||||
@ -827,7 +851,8 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
|
||||
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
|
||||
{
|
||||
WLog_ERR(TAG, "DefineCommDevice failed!");
|
||||
DWORD status = GetLastError();
|
||||
WLog_ERR(TAG, "DefineCommDevice failed with %08"PRIx32, status);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -927,7 +952,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
|
||||
if (!(serial->MainThread = CreateThread(NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE) serial_thread_func,
|
||||
serial_thread_func,
|
||||
(void*) serial,
|
||||
0,
|
||||
NULL)))
|
||||
|
||||
@ -34,8 +34,9 @@
|
||||
|
||||
#include "smartcard_main.h"
|
||||
|
||||
void* smartcard_context_thread(SMARTCARD_CONTEXT* pContext)
|
||||
static DWORD WINAPI smartcard_context_thread(LPVOID arg)
|
||||
{
|
||||
SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg;
|
||||
DWORD nCount;
|
||||
LONG status = 0;
|
||||
DWORD waitStatus;
|
||||
@ -107,8 +108,8 @@ void* smartcard_context_thread(SMARTCARD_CONTEXT* pContext)
|
||||
setChannelError(smartcard->rdpcontext, error,
|
||||
"smartcard_context_thread reported an error");
|
||||
|
||||
ExitThread((DWORD)status);
|
||||
return NULL;
|
||||
ExitThread(status);
|
||||
return error;
|
||||
}
|
||||
|
||||
SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard,
|
||||
@ -134,7 +135,7 @@ SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard,
|
||||
}
|
||||
|
||||
pContext->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) smartcard_context_thread,
|
||||
smartcard_context_thread,
|
||||
pContext, 0, NULL);
|
||||
|
||||
if (!pContext->thread)
|
||||
@ -385,17 +386,17 @@ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
||||
|
||||
asyncIrp = TRUE;
|
||||
|
||||
/**
|
||||
* The following matches mstsc's behavior of processing
|
||||
* only certain requests asynchronously while processing
|
||||
* those expected to return fast synchronously.
|
||||
*/
|
||||
|
||||
switch (operation->ioControlCode)
|
||||
{
|
||||
case SCARD_IOCTL_ESTABLISHCONTEXT:
|
||||
case SCARD_IOCTL_RELEASECONTEXT:
|
||||
case SCARD_IOCTL_ISVALIDCONTEXT:
|
||||
case SCARD_IOCTL_CANCEL:
|
||||
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
|
||||
case SCARD_IOCTL_RELEASESTARTEDEVENT:
|
||||
asyncIrp = FALSE;
|
||||
break;
|
||||
|
||||
case SCARD_IOCTL_LISTREADERGROUPSA:
|
||||
case SCARD_IOCTL_LISTREADERGROUPSW:
|
||||
case SCARD_IOCTL_LISTREADERSA:
|
||||
@ -416,21 +417,14 @@ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
||||
case SCARD_IOCTL_LOCATECARDSW:
|
||||
case SCARD_IOCTL_LOCATECARDSBYATRA:
|
||||
case SCARD_IOCTL_LOCATECARDSBYATRW:
|
||||
case SCARD_IOCTL_CANCEL:
|
||||
case SCARD_IOCTL_READCACHEA:
|
||||
case SCARD_IOCTL_READCACHEW:
|
||||
case SCARD_IOCTL_WRITECACHEA:
|
||||
case SCARD_IOCTL_WRITECACHEW:
|
||||
case SCARD_IOCTL_GETREADERICON:
|
||||
case SCARD_IOCTL_GETDEVICETYPEID:
|
||||
asyncIrp = FALSE;
|
||||
break;
|
||||
|
||||
case SCARD_IOCTL_GETSTATUSCHANGEA:
|
||||
case SCARD_IOCTL_GETSTATUSCHANGEW:
|
||||
asyncIrp = TRUE;
|
||||
break;
|
||||
|
||||
case SCARD_IOCTL_CONNECTA:
|
||||
case SCARD_IOCTL_CONNECTW:
|
||||
case SCARD_IOCTL_RECONNECT:
|
||||
@ -447,11 +441,6 @@ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
||||
case SCARD_IOCTL_GETTRANSMITCOUNT:
|
||||
asyncIrp = TRUE;
|
||||
break;
|
||||
|
||||
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
|
||||
case SCARD_IOCTL_RELEASESTARTEDEVENT:
|
||||
asyncIrp = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
pContext = ListDictionary_GetItemValue(smartcard->rgSCardContextList,
|
||||
@ -506,7 +495,7 @@ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void* smartcard_thread_func(void* arg)
|
||||
static DWORD WINAPI smartcard_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP* irp;
|
||||
DWORD nCount;
|
||||
@ -657,8 +646,8 @@ out:
|
||||
setChannelError(smartcard->rdpcontext, error,
|
||||
"smartcard_thread_func reported an error");
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -689,17 +678,9 @@ static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
|
||||
*/
|
||||
UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
char* name;
|
||||
char* path;
|
||||
size_t length;
|
||||
int ck;
|
||||
RDPDR_SMARTCARD* device;
|
||||
SMARTCARD_DEVICE* smartcard;
|
||||
LONG status;
|
||||
UINT error = CHANNEL_RC_NO_MEMORY;
|
||||
device = (RDPDR_SMARTCARD*) pEntryPoints->device;
|
||||
name = device->Name;
|
||||
path = device->Path;
|
||||
smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE));
|
||||
|
||||
if (!smartcard)
|
||||
@ -724,30 +705,6 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
}
|
||||
|
||||
Stream_Write(smartcard->device.data, "SCARD", 6);
|
||||
smartcard->name = NULL;
|
||||
smartcard->path = NULL;
|
||||
|
||||
if (path)
|
||||
{
|
||||
smartcard->path = path;
|
||||
smartcard->name = name;
|
||||
}
|
||||
else if (name)
|
||||
{
|
||||
if (1 == sscanf(name, "%d", &ck))
|
||||
smartcard->path = name;
|
||||
else
|
||||
smartcard->name = name;
|
||||
}
|
||||
|
||||
status = SCardAddReaderName(&smartcard->thread, (LPSTR) name);
|
||||
|
||||
if (status != SCARD_S_SUCCESS)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to add reader name!");
|
||||
goto error_device_data;
|
||||
}
|
||||
|
||||
smartcard->IrpQueue = MessageQueue_New(NULL);
|
||||
|
||||
if (!smartcard->IrpQueue)
|
||||
@ -790,7 +747,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
}
|
||||
|
||||
smartcard->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) smartcard_thread_func,
|
||||
smartcard_thread_func,
|
||||
smartcard, CREATE_SUSPENDED, NULL);
|
||||
|
||||
if (!smartcard->thread)
|
||||
|
||||
@ -110,9 +110,6 @@ struct _SMARTCARD_DEVICE
|
||||
{
|
||||
DEVICE device;
|
||||
|
||||
char* name;
|
||||
char* path;
|
||||
|
||||
HANDLE thread;
|
||||
HANDLE StartedEvent;
|
||||
wMessageQueue* IrpQueue;
|
||||
|
||||
@ -581,28 +581,23 @@ static LONG smartcard_GetStatusChangeA_Decode(SMARTCARD_DEVICE* smartcard,
|
||||
static LONG smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard,
|
||||
SMARTCARD_OPERATION* operation)
|
||||
{
|
||||
LONG status;
|
||||
UINT32 index;
|
||||
GetStatusChange_Return ret;
|
||||
LPSCARD_READERSTATEA rgReaderState = NULL;
|
||||
IRP* irp = operation->irp;
|
||||
GetStatusChangeA_Call* call = operation->call;
|
||||
status = ret.ReturnCode = SCardGetStatusChangeA(operation->hContext,
|
||||
call->dwTimeOut, call->rgReaderStates, call->cReaders);
|
||||
|
||||
if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED))
|
||||
{
|
||||
call->cReaders = 0;
|
||||
}
|
||||
|
||||
ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, call->dwTimeOut, call->rgReaderStates,
|
||||
call->cReaders);
|
||||
ret.cReaders = call->cReaders;
|
||||
ret.rgReaderStates = NULL;
|
||||
|
||||
if (ret.cReaders > 0)
|
||||
{
|
||||
ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return));
|
||||
|
||||
if (!ret.rgReaderStates)
|
||||
return STATUS_NO_MEMORY;
|
||||
if (!ret.rgReaderStates)
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (index = 0; index < ret.cReaders; index++)
|
||||
{
|
||||
@ -613,12 +608,7 @@ static LONG smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard,
|
||||
}
|
||||
|
||||
smartcard_trace_get_status_change_return(smartcard, &ret, FALSE);
|
||||
|
||||
if ((status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret)))
|
||||
{
|
||||
WLog_ERR(TAG, "smartcard_pack_get_status_change_return failed with error %"PRId32"", status);
|
||||
return status;
|
||||
}
|
||||
smartcard_pack_get_status_change_return(smartcard, irp->output, &ret);
|
||||
|
||||
if (call->rgReaderStates)
|
||||
{
|
||||
@ -657,28 +647,23 @@ static LONG smartcard_GetStatusChangeW_Decode(SMARTCARD_DEVICE* smartcard,
|
||||
static LONG smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard,
|
||||
SMARTCARD_OPERATION* operation)
|
||||
{
|
||||
LONG status;
|
||||
UINT32 index;
|
||||
GetStatusChange_Return ret;
|
||||
LPSCARD_READERSTATEW rgReaderState = NULL;
|
||||
IRP* irp = operation->irp;
|
||||
GetStatusChangeW_Call* call = operation->call;
|
||||
status = ret.ReturnCode = SCardGetStatusChangeW(operation->hContext, call->dwTimeOut,
|
||||
call->rgReaderStates, call->cReaders);
|
||||
|
||||
if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED))
|
||||
{
|
||||
call->cReaders = 0;
|
||||
}
|
||||
|
||||
ret.ReturnCode = SCardGetStatusChangeW(operation->hContext, call->dwTimeOut,
|
||||
call->rgReaderStates, call->cReaders);
|
||||
ret.cReaders = call->cReaders;
|
||||
ret.rgReaderStates = NULL;
|
||||
|
||||
if (ret.cReaders > 0)
|
||||
{
|
||||
ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return));
|
||||
|
||||
if (!ret.rgReaderStates)
|
||||
return STATUS_NO_MEMORY;
|
||||
if (!ret.rgReaderStates)
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (index = 0; index < ret.cReaders; index++)
|
||||
{
|
||||
@ -689,12 +674,7 @@ static LONG smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard,
|
||||
}
|
||||
|
||||
smartcard_trace_get_status_change_return(smartcard, &ret, TRUE);
|
||||
|
||||
if ((status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret)))
|
||||
{
|
||||
WLog_ERR(TAG, "smartcard_pack_get_status_change_return failed with error %"PRId32"", status);
|
||||
return status;
|
||||
}
|
||||
smartcard_pack_get_status_change_return(smartcard, irp->output, &ret);
|
||||
|
||||
if (call->rgReaderStates)
|
||||
{
|
||||
@ -787,17 +767,19 @@ static LONG smartcard_ConnectA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA
|
||||
if (status)
|
||||
{
|
||||
WLog_ERR(TAG, "SCardConnectA failed with error %"PRId32"", status);
|
||||
return status;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if ((status = smartcard_pack_connect_return(smartcard, irp->output, &ret)))
|
||||
{
|
||||
WLog_ERR(TAG, "smartcard_pack_connect_return failed with error %"PRId32"", status);
|
||||
return status;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
status = ret.ReturnCode;
|
||||
out_fail:
|
||||
free(call->szReader);
|
||||
return ret.ReturnCode;
|
||||
return status;
|
||||
}
|
||||
|
||||
static LONG smartcard_ConnectW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation)
|
||||
@ -843,17 +825,19 @@ static LONG smartcard_ConnectW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA
|
||||
if (status)
|
||||
{
|
||||
WLog_ERR(TAG, "SCardConnectW failed with error %"PRId32"", status);
|
||||
return status;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if ((status = smartcard_pack_connect_return(smartcard, irp->output, &ret)))
|
||||
{
|
||||
WLog_ERR(TAG, "smartcard_pack_connect_return failed with error %"PRId32"", status);
|
||||
return status;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
status = ret.ReturnCode;
|
||||
out_fail:
|
||||
free(call->szReader);
|
||||
return ret.ReturnCode;
|
||||
return status;
|
||||
}
|
||||
|
||||
static LONG smartcard_Reconnect_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation)
|
||||
@ -881,8 +865,8 @@ static LONG smartcard_Reconnect_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER
|
||||
Reconnect_Return ret;
|
||||
IRP* irp = operation->irp;
|
||||
Reconnect_Call* call = operation->call;
|
||||
status = ret.ReturnCode = SCardReconnect(operation->hCard, call->dwShareMode,
|
||||
call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol);
|
||||
ret.ReturnCode = SCardReconnect(operation->hCard, call->dwShareMode,
|
||||
call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol);
|
||||
smartcard_trace_reconnect_return(smartcard, &ret);
|
||||
|
||||
if ((status = smartcard_pack_reconnect_return(smartcard, irp->output, &ret)))
|
||||
@ -1064,23 +1048,34 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
|
||||
LONG status;
|
||||
Status_Return ret = { 0 };
|
||||
DWORD cchReaderLen = 0;
|
||||
DWORD cbAtrLen = 0;
|
||||
LPSTR mszReaderNames = NULL;
|
||||
IRP* irp = operation->irp;
|
||||
Status_Call* call = operation->call;
|
||||
|
||||
if (call->cbAtrLen > 32)
|
||||
call->cbAtrLen = 32;
|
||||
|
||||
ret.cbAtrLen = call->cbAtrLen;
|
||||
ZeroMemory(ret.pbAtr, 32);
|
||||
cchReaderLen = SCARD_AUTOALLOCATE;
|
||||
status = ret.ReturnCode = SCardStatusA(operation->hCard, (LPSTR) &mszReaderNames, &cchReaderLen,
|
||||
&ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen);
|
||||
|
||||
call->cbAtrLen = 32;
|
||||
cbAtrLen = call->cbAtrLen;
|
||||
|
||||
if (call->fmszReaderNamesIsNULL)
|
||||
cchReaderLen = 0;
|
||||
else
|
||||
cchReaderLen = SCARD_AUTOALLOCATE;
|
||||
|
||||
status = ret.ReturnCode = SCardStatusA(operation->hCard,
|
||||
call->fmszReaderNamesIsNULL ? NULL : (LPSTR) &mszReaderNames,
|
||||
&cchReaderLen, &ret.dwState, &ret.dwProtocol,
|
||||
cbAtrLen ? (BYTE*) &ret.pbAtr : NULL, &cbAtrLen);
|
||||
|
||||
if (status == SCARD_S_SUCCESS)
|
||||
{
|
||||
ret.mszReaderNames = (BYTE*) mszReaderNames;
|
||||
if (!call->fmszReaderNamesIsNULL)
|
||||
ret.mszReaderNames = (BYTE*) mszReaderNames;
|
||||
|
||||
ret.cBytes = cchReaderLen;
|
||||
|
||||
if (call->cbAtrLen)
|
||||
ret.cbAtrLen = cbAtrLen;
|
||||
}
|
||||
|
||||
smartcard_trace_status_return(smartcard, &ret, FALSE);
|
||||
@ -1092,7 +1087,9 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
|
||||
}
|
||||
|
||||
if (mszReaderNames)
|
||||
{
|
||||
SCardFreeMemory(operation->hContext, mszReaderNames);
|
||||
}
|
||||
|
||||
return ret.ReturnCode;
|
||||
}
|
||||
@ -1124,17 +1121,33 @@ static LONG smartcard_StatusW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
|
||||
LPWSTR mszReaderNames = NULL;
|
||||
IRP* irp = operation->irp;
|
||||
Status_Call* call = operation->call;
|
||||
DWORD cbAtrLen;
|
||||
|
||||
if (call->cbAtrLen > 32)
|
||||
call->cbAtrLen = 32;
|
||||
|
||||
ret.cbAtrLen = call->cbAtrLen;
|
||||
if (call->fmszReaderNamesIsNULL)
|
||||
cchReaderLen = 0;
|
||||
else
|
||||
cchReaderLen = SCARD_AUTOALLOCATE;
|
||||
|
||||
cbAtrLen = call->cbAtrLen;
|
||||
ZeroMemory(ret.pbAtr, 32);
|
||||
cchReaderLen = SCARD_AUTOALLOCATE;
|
||||
status = ret.ReturnCode = SCardStatusW(operation->hCard, (LPWSTR) &mszReaderNames, &cchReaderLen,
|
||||
&ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen);
|
||||
ret.mszReaderNames = (BYTE*) mszReaderNames;
|
||||
ret.cBytes = cchReaderLen * 2;
|
||||
status = ret.ReturnCode = SCardStatusW(operation->hCard,
|
||||
call->fmszReaderNamesIsNULL ? NULL : (LPWSTR) &mszReaderNames,
|
||||
&cchReaderLen, &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &cbAtrLen);
|
||||
|
||||
if (status == SCARD_S_SUCCESS)
|
||||
{
|
||||
if (!call->fmszReaderNamesIsNULL)
|
||||
ret.mszReaderNames = (BYTE*) mszReaderNames;
|
||||
|
||||
ret.cBytes = cchReaderLen;
|
||||
|
||||
if (call->cbAtrLen)
|
||||
ret.cbAtrLen = cbAtrLen;
|
||||
}
|
||||
|
||||
smartcard_trace_status_return(smartcard, &ret, TRUE);
|
||||
|
||||
if ((status = smartcard_pack_status_return(smartcard, irp->output, &ret)))
|
||||
@ -1190,8 +1203,8 @@ static LONG smartcard_Transmit_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA
|
||||
}
|
||||
|
||||
ret.pioRecvPci = call->pioRecvPci;
|
||||
status = ret.ReturnCode = SCardTransmit(operation->hCard, call->pioSendPci, call->pbSendBuffer,
|
||||
call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength));
|
||||
ret.ReturnCode = SCardTransmit(operation->hCard, call->pioSendPci, call->pbSendBuffer,
|
||||
call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength));
|
||||
smartcard_trace_transmit_return(smartcard, &ret);
|
||||
|
||||
if ((status = smartcard_pack_transmit_return(smartcard, irp->output, &ret)))
|
||||
@ -1238,9 +1251,9 @@ static LONG smartcard_Control_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
|
||||
if (!ret.pvOutBuffer)
|
||||
return SCARD_E_NO_MEMORY;
|
||||
|
||||
status = ret.ReturnCode = SCardControl(operation->hCard,
|
||||
call->dwControlCode, call->pvInBuffer, call->cbInBufferSize,
|
||||
ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize);
|
||||
ret.ReturnCode = SCardControl(operation->hCard,
|
||||
call->dwControlCode, call->pvInBuffer, call->cbInBufferSize,
|
||||
ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize);
|
||||
smartcard_trace_control_return(smartcard, &ret);
|
||||
|
||||
if ((status = smartcard_pack_control_return(smartcard, irp->output, &ret)))
|
||||
@ -1297,8 +1310,8 @@ static LONG smartcard_GetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER
|
||||
}
|
||||
|
||||
cbAttrLen = call->cbAttrLen;
|
||||
status = ret.ReturnCode = SCardGetAttrib(operation->hCard, call->dwAttrId,
|
||||
autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr, &cbAttrLen);
|
||||
ret.ReturnCode = SCardGetAttrib(operation->hCard, call->dwAttrId,
|
||||
autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr, &cbAttrLen);
|
||||
ret.cbAttrLen = cbAttrLen;
|
||||
smartcard_trace_get_attrib_return(smartcard, &ret, call->dwAttrId);
|
||||
|
||||
@ -1379,7 +1392,6 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard,
|
||||
SMARTCARD_OPERATION* operation)
|
||||
{
|
||||
LONG status;
|
||||
BOOL equal;
|
||||
DWORD i, j, k;
|
||||
GetStatusChange_Return ret;
|
||||
LPSCARD_READERSTATEA state = NULL;
|
||||
@ -1412,21 +1424,15 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard,
|
||||
{
|
||||
for (j = 0; j < call->cReaders; j++)
|
||||
{
|
||||
equal = TRUE;
|
||||
|
||||
for (k = 0; k < call->rgAtrMasks[i].cbAtr; k++)
|
||||
{
|
||||
if ((call->rgAtrMasks[i].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]) !=
|
||||
(states[j].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]))
|
||||
{
|
||||
equal = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (equal)
|
||||
{
|
||||
states[j].dwEventState |= SCARD_STATE_ATRMATCH;
|
||||
}
|
||||
states[j].dwEventState |= SCARD_STATE_ATRMATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2022,13 +2028,12 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP
|
||||
SCardGetErrorString(result), result);
|
||||
}
|
||||
|
||||
irp->IoStatus = 0;
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
|
||||
if ((result & 0xC0000000) == 0xC0000000)
|
||||
{
|
||||
/* NTSTATUS error */
|
||||
irp->IoStatus = (UINT32)result;
|
||||
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH);
|
||||
WLog_WARN(TAG, "IRP failure: %s (0x%08"PRIX32"), ntstatus: 0x%08"PRIX32"",
|
||||
smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result);
|
||||
}
|
||||
@ -2039,21 +2044,9 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP
|
||||
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH);
|
||||
/* Device Control Response */
|
||||
Stream_Write_UINT32(irp->output, outputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||
|
||||
if ((result = smartcard_pack_common_type_header(smartcard,
|
||||
irp->output))) /* CommonTypeHeader (8 bytes) */
|
||||
{
|
||||
WLog_ERR(TAG, "smartcard_pack_common_type_header failed with error %"PRId32"", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result = smartcard_pack_private_type_header(smartcard, irp->output,
|
||||
objectBufferLength))) /* PrivateTypeHeader (8 bytes) */
|
||||
{
|
||||
WLog_ERR(TAG, "smartcard_pack_private_type_header failed with error %"PRId32"", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
smartcard_pack_common_type_header(smartcard, irp->output); /* CommonTypeHeader (8 bytes) */
|
||||
smartcard_pack_private_type_header(smartcard, irp->output,
|
||||
objectBufferLength); /* PrivateTypeHeader (8 bytes) */
|
||||
Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */
|
||||
Stream_SetPosition(irp->output, Stream_Length(irp->output));
|
||||
return SCARD_S_SUCCESS;
|
||||
|
||||
@ -75,13 +75,12 @@ LONG smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s
|
||||
return SCARD_S_SUCCESS;
|
||||
}
|
||||
|
||||
LONG smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s)
|
||||
void smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s)
|
||||
{
|
||||
Stream_Write_UINT8(s, 1); /* Version (1 byte) */
|
||||
Stream_Write_UINT8(s, 0x10); /* Endianness (1 byte) */
|
||||
Stream_Write_UINT16(s, 8); /* CommonHeaderLength (2 bytes) */
|
||||
Stream_Write_UINT32(s, 0xCCCCCCCC); /* Filler (4 bytes), should be 0xCCCCCCCC */
|
||||
return SCARD_S_SUCCESS;
|
||||
}
|
||||
|
||||
LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s)
|
||||
@ -116,12 +115,11 @@ LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream*
|
||||
return SCARD_S_SUCCESS;
|
||||
}
|
||||
|
||||
LONG smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s,
|
||||
void smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s,
|
||||
UINT32 objectBufferLength)
|
||||
{
|
||||
Stream_Write_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */
|
||||
Stream_Write_UINT32(s, 0x00000000); /* Filler (4 bytes), should be 0x00000000 */
|
||||
return SCARD_S_SUCCESS;
|
||||
}
|
||||
|
||||
LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size,
|
||||
@ -850,7 +848,7 @@ void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, ListReader
|
||||
CopyMemory(mszA, ret->msz, ret->cBytes);
|
||||
}
|
||||
|
||||
for (index = 0; index < length - 2; index++)
|
||||
for (index = 0; index < length - 1; index++)
|
||||
{
|
||||
if (mszA[index] == '\0')
|
||||
mszA[index] = ',';
|
||||
@ -1863,32 +1861,34 @@ void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, Status_Return* r
|
||||
if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG))
|
||||
return;
|
||||
|
||||
if (unicode)
|
||||
if (ret->mszReaderNames)
|
||||
{
|
||||
length = ret->cBytes / 2;
|
||||
|
||||
if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int)length,
|
||||
&mszReaderNamesA, 0, NULL, NULL) < 1)
|
||||
if (unicode)
|
||||
{
|
||||
WLog_ERR(TAG, "ConvertFromUnicode failed");
|
||||
return;
|
||||
length = ret->cBytes / 2;
|
||||
|
||||
if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int) length,
|
||||
&mszReaderNamesA, 0, NULL, NULL) < 1)
|
||||
{
|
||||
WLog_ERR(TAG, "ConvertFromUnicode failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length = (int) ret->cBytes;
|
||||
mszReaderNamesA = (char*) malloc(length);
|
||||
|
||||
if (!mszReaderNamesA)
|
||||
{
|
||||
WLog_ERR(TAG, "malloc failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
CopyMemory(mszReaderNamesA, ret->mszReaderNames, ret->cBytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length = (int) ret->cBytes;
|
||||
mszReaderNamesA = (char*) malloc(length);
|
||||
|
||||
if (!mszReaderNamesA)
|
||||
{
|
||||
WLog_ERR(TAG, "malloc failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
CopyMemory(mszReaderNamesA, ret->mszReaderNames, ret->cBytes);
|
||||
}
|
||||
|
||||
if (!mszReaderNamesA)
|
||||
length = 0;
|
||||
|
||||
if (length > 2)
|
||||
@ -2761,7 +2761,7 @@ LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wS
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
call->rgAtrMasks = (LocateCards_ATRMask*)calloc(call->cAtrs, sizeof(SCARD_ATRMASK));
|
||||
call->rgAtrMasks = (LocateCards_ATRMask*)calloc(call->cAtrs, sizeof(LocateCards_ATRMask));
|
||||
|
||||
if (!call->rgAtrMasks)
|
||||
{
|
||||
@ -2789,7 +2789,7 @@ LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wS
|
||||
|
||||
if (call->cReaders > 0)
|
||||
{
|
||||
call->rgReaderStates = (ReaderStateA*)calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
|
||||
call->rgReaderStates = (ReaderStateA*)calloc(call->cReaders, sizeof(ReaderStateA));
|
||||
|
||||
if (!call->rgReaderStates)
|
||||
{
|
||||
|
||||
@ -452,10 +452,10 @@ void smartcard_scard_handle_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_S
|
||||
SCARDHANDLE hCard);
|
||||
|
||||
LONG smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
|
||||
LONG smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
|
||||
void smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
|
||||
|
||||
LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s);
|
||||
LONG smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s,
|
||||
void smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s,
|
||||
UINT32 objectBufferLength);
|
||||
|
||||
LONG smartcard_unpack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s,
|
||||
|
||||
27
channels/sshagent/CMakeLists.txt
Normal file
27
channels/sshagent/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2017 Ben Cohen
|
||||
#
|
||||
# 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("sshagent")
|
||||
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_CHANNELS)
|
||||
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
13
channels/sshagent/ChannelOptions.cmake
Normal file
13
channels/sshagent/ChannelOptions.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
|
||||
define_channel_options(NAME "sshagent" TYPE "dynamic"
|
||||
DESCRIPTION "SSH Agent Forwarding Extension"
|
||||
SPECIFICATIONS ""
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
||||
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||
define_channel_server_options(${OPTION_SERVER_DEFAULT})
|
||||
|
||||
34
channels/sshagent/client/CMakeLists.txt
Normal file
34
channels/sshagent/client/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2017 Ben Cohen
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
define_channel_client("sshagent")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
sshagent_main.c
|
||||
sshagent_main.h)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||
|
||||
if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
||||
408
channels/sshagent/client/sshagent_main.c
Normal file
408
channels/sshagent/client/sshagent_main.c
Normal file
@ -0,0 +1,408 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SSH Agent Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Christian Hofstaedtler
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
* Copyright 2017 Ben Cohen
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* sshagent_main.c: DVC plugin to forward queries from RDP to the ssh-agent
|
||||
*
|
||||
* This relays data to and from an ssh-agent program equivalent running on the
|
||||
* RDP server to an ssh-agent running locally. Unlike the normal ssh-agent,
|
||||
* which sends data over an SSH channel, the data is send over an RDP dynamic
|
||||
* virtual channel.
|
||||
*
|
||||
* protocol specification:
|
||||
* Forward data verbatim over RDP dynamic virtual channel named "sshagent"
|
||||
* between a ssh client on the xrdp server and the real ssh-agent where
|
||||
* the RDP client is running. Each connection by a separate client to
|
||||
* xrdp-ssh-agent gets a separate DVC invocation.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "sshagent_main.h"
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#define TAG CHANNELS_TAG("sshagent.client")
|
||||
|
||||
typedef struct _SSHAGENT_LISTENER_CALLBACK SSHAGENT_LISTENER_CALLBACK;
|
||||
struct _SSHAGENT_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
|
||||
rdpContext* rdpcontext;
|
||||
const char* agent_uds_path;
|
||||
};
|
||||
|
||||
typedef struct _SSHAGENT_CHANNEL_CALLBACK SSHAGENT_CHANNEL_CALLBACK;
|
||||
struct _SSHAGENT_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
|
||||
rdpContext* rdpcontext;
|
||||
int agent_fd;
|
||||
HANDLE thread;
|
||||
CRITICAL_SECTION lock;
|
||||
};
|
||||
|
||||
typedef struct _SSHAGENT_PLUGIN SSHAGENT_PLUGIN;
|
||||
struct _SSHAGENT_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
SSHAGENT_LISTENER_CALLBACK* listener_callback;
|
||||
|
||||
rdpContext* rdpcontext;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function to open the connection to the sshagent
|
||||
*
|
||||
* @return The fd on success, otherwise -1
|
||||
*/
|
||||
static int connect_to_sshagent(const char* udspath)
|
||||
{
|
||||
int agent_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (agent_fd == -1)
|
||||
{
|
||||
WLog_ERR(TAG, "Can't open Unix domain socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
strncpy(addr.sun_path, udspath, sizeof(addr.sun_path) - 1);
|
||||
|
||||
int rc = connect(agent_fd, (struct sockaddr*)&addr, sizeof(addr));
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Can't connect to Unix domain socket \"%s\"!",
|
||||
udspath);
|
||||
close(agent_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return agent_fd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entry point for thread to read from the ssh-agent socket and forward
|
||||
* the data to RDP
|
||||
*
|
||||
* @return NULL
|
||||
*/
|
||||
static DWORD WINAPI sshagent_read_thread(LPVOID data)
|
||||
{
|
||||
SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*)data;
|
||||
BYTE buffer[4096];
|
||||
int going = 1;
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
|
||||
while (going)
|
||||
{
|
||||
int bytes_read = read(callback->agent_fd,
|
||||
buffer,
|
||||
sizeof(buffer));
|
||||
|
||||
if (bytes_read == 0)
|
||||
{
|
||||
/* Socket closed cleanly at other end */
|
||||
going = 0;
|
||||
}
|
||||
else if (bytes_read < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"Error reading from sshagent, errno=%d",
|
||||
errno);
|
||||
status = ERROR_READ_FAULT;
|
||||
going = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something read: forward to virtual channel */
|
||||
status = callback->channel->Write(callback->channel,
|
||||
bytes_read,
|
||||
buffer,
|
||||
NULL);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
going = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(callback->agent_fd);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
setChannelError(callback->rdpcontext, status,
|
||||
"sshagent_read_thread reported an error");
|
||||
|
||||
ExitThread(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for data received from the RDP server; forward this to ssh-agent
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT sshagent_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
|
||||
{
|
||||
SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
BYTE* pBuffer = Stream_Pointer(data);
|
||||
UINT32 cbSize = Stream_GetRemainingLength(data);
|
||||
BYTE* pos = pBuffer;
|
||||
/* Forward what we have received to the ssh agent */
|
||||
UINT32 bytes_to_write = cbSize;
|
||||
errno = 0;
|
||||
|
||||
while (bytes_to_write > 0)
|
||||
{
|
||||
int bytes_written = write(callback->agent_fd, pos,
|
||||
bytes_to_write);
|
||||
|
||||
if (bytes_written < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"Error writing to sshagent, errno=%d",
|
||||
errno);
|
||||
return ERROR_WRITE_FAULT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_to_write -= bytes_written;
|
||||
pos += bytes_written;
|
||||
}
|
||||
}
|
||||
|
||||
/* Consume stream */
|
||||
Stream_Seek(data, cbSize);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the virtual channel is closed
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT sshagent_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
/* Call shutdown() to wake up the read() in sshagent_read_thread(). */
|
||||
shutdown(callback->agent_fd, SHUT_RDWR);
|
||||
EnterCriticalSection(&callback->lock);
|
||||
|
||||
if (WaitForSingleObject(callback->thread, INFINITE) == WAIT_FAILED)
|
||||
{
|
||||
UINT error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
CloseHandle(callback->thread);
|
||||
LeaveCriticalSection(&callback->lock);
|
||||
DeleteCriticalSection(&callback->lock);
|
||||
free(callback);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for when a new virtual channel is opened
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
SSHAGENT_CHANNEL_CALLBACK* callback;
|
||||
SSHAGENT_LISTENER_CALLBACK* listener_callback = (SSHAGENT_LISTENER_CALLBACK*) pListenerCallback;
|
||||
callback = (SSHAGENT_CHANNEL_CALLBACK*) calloc(1, sizeof(SSHAGENT_CHANNEL_CALLBACK));
|
||||
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Now open a connection to the local ssh-agent. Do this for each
|
||||
* connection to the plugin in case we mess up the agent session. */
|
||||
callback->agent_fd
|
||||
= connect_to_sshagent(listener_callback->agent_uds_path);
|
||||
|
||||
if (callback->agent_fd == -1)
|
||||
{
|
||||
free(callback);
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&callback->lock);
|
||||
callback->iface.OnDataReceived = sshagent_on_data_received;
|
||||
callback->iface.OnClose = sshagent_on_close;
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
callback->rdpcontext = listener_callback->rdpcontext;
|
||||
callback->thread
|
||||
= CreateThread(NULL,
|
||||
0,
|
||||
sshagent_read_thread,
|
||||
(void*) callback,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (!callback->thread)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
DeleteCriticalSection(&callback->lock);
|
||||
free(callback);
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the plugin is initialised
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT sshagent_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*) pPlugin;
|
||||
sshagent->listener_callback = (SSHAGENT_LISTENER_CALLBACK*) calloc(1,
|
||||
sizeof(SSHAGENT_LISTENER_CALLBACK));
|
||||
|
||||
if (!sshagent->listener_callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
sshagent->listener_callback->rdpcontext = sshagent->rdpcontext;
|
||||
sshagent->listener_callback->iface.OnNewChannelConnection = sshagent_on_new_channel_connection;
|
||||
sshagent->listener_callback->plugin = pPlugin;
|
||||
sshagent->listener_callback->channel_mgr = pChannelMgr;
|
||||
sshagent->listener_callback->agent_uds_path = getenv("SSH_AUTH_SOCK");
|
||||
|
||||
if (sshagent->listener_callback->agent_uds_path == NULL)
|
||||
{
|
||||
WLog_ERR(TAG, "Environment variable $SSH_AUTH_SOCK undefined!");
|
||||
free(sshagent->listener_callback);
|
||||
sshagent->listener_callback = NULL;
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
return pChannelMgr->CreateListener(pChannelMgr, "SSHAGENT", 0,
|
||||
(IWTSListenerCallback*) sshagent->listener_callback, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the plugin is terminated
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT sshagent_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
{
|
||||
SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*) pPlugin;
|
||||
free(sshagent);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_CHANNELS
|
||||
#define DVCPluginEntry sshagent_DVCPluginEntry
|
||||
#else
|
||||
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Main entry point for sshagent DVC plugin
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
SSHAGENT_PLUGIN* sshagent;
|
||||
sshagent = (SSHAGENT_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "sshagent");
|
||||
|
||||
if (!sshagent)
|
||||
{
|
||||
sshagent = (SSHAGENT_PLUGIN*) calloc(1, sizeof(SSHAGENT_PLUGIN));
|
||||
|
||||
if (!sshagent)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
sshagent->iface.Initialize = sshagent_plugin_initialize;
|
||||
sshagent->iface.Connected = NULL;
|
||||
sshagent->iface.Disconnected = NULL;
|
||||
sshagent->iface.Terminated = sshagent_plugin_terminated;
|
||||
sshagent->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(
|
||||
pEntryPoints))->instance)->context;
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "sshagent", (IWTSPlugin*) sshagent);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* vim: set sw=8:ts=8:noet: */
|
||||
42
channels/sshagent/client/sshagent_main.h
Normal file
42
channels/sshagent/client/sshagent_main.h
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SSH Agent Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Christian Hofstaedtler
|
||||
* Copyright 2017 Ben Cohen
|
||||
*
|
||||
* 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 SSHAGENT_MAIN_H
|
||||
#define SSHAGENT_MAIN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/svc.h>
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#define DVC_TAG CHANNELS_TAG("sshagent.client")
|
||||
#ifdef WITH_DEBUG_SSHAGENT
|
||||
#define DEBUG_SSHAGENT(...) WLog_DBG(DVC_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_SSHAGENT(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* SSHAGENT_MAIN_H */
|
||||
|
||||
31
channels/sshagent/server/CMakeLists.txt
Normal file
31
channels/sshagent/server/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2017 Ben Cohen
|
||||
#
|
||||
# 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("sshagent")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
sshagent_main.c)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
|
||||
|
||||
|
||||
|
||||
target_link_libraries(${MODULE_NAME} freerdp)
|
||||
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
||||
422
channels/sshagent/server/sshagent_main.c
Normal file
422
channels/sshagent/server/sshagent_main.c
Normal file
@ -0,0 +1,422 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SSH Agent Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2012-2013 Jay Sorg
|
||||
* Copyright 2012-2013 Laxmikant Rashinkar
|
||||
* Copyright 2017 Ben Cohen
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions are from OpenSSH, under the following license:
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* The authentication agent program.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* xrdp-ssh-agent.c: program to forward ssh-agent protocol from xrdp session
|
||||
*
|
||||
* This performs the equivalent function of ssh-agent on a server you connect
|
||||
* to via ssh, but the ssh-agent protocol is over an RDP dynamic virtual
|
||||
* channel and not an SSH channel.
|
||||
*
|
||||
* This will print out variables to set in your environment (specifically,
|
||||
* $SSH_AUTH_SOCK) for ssh clients to find the agent's socket, then it will
|
||||
* run in the background. This is suitable to run just as you would run the
|
||||
* normal ssh-agent, e.g. in your Xsession or /etc/xrdp/startwm.sh.
|
||||
*
|
||||
* Your RDP client needs to be running a compatible client-side plugin
|
||||
* that can see a local ssh-agent.
|
||||
*
|
||||
* usage (from within an xrdp session):
|
||||
* xrdp-ssh-agent
|
||||
*
|
||||
* build instructions:
|
||||
* gcc xrdp-ssh-agent.c -o xrdp-ssh-agent -L./.libs -lxrdpapi -Wall
|
||||
*
|
||||
* protocol specification:
|
||||
* Forward data verbatim over RDP dynamic virtual channel named "sshagent"
|
||||
* between a ssh client on the xrdp server and the real ssh-agent where
|
||||
* the RDP client is running. Each connection by a separate client to
|
||||
* xrdp-ssh-agent gets a separate DVC invocation.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <mstsapi.h>
|
||||
#endif
|
||||
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
|
||||
char socket_name[PATH_MAX];
|
||||
char socket_dir[PATH_MAX];
|
||||
static int sa_uds_fd = -1;
|
||||
static int is_going = 1;
|
||||
|
||||
|
||||
/* Make a template filename for mk[sd]temp() */
|
||||
/* This is from mktemp_proto() in misc.c from openssh */
|
||||
void
|
||||
mktemp_proto(char* s, size_t len)
|
||||
{
|
||||
const char* tmpdir;
|
||||
int r;
|
||||
|
||||
if ((tmpdir = getenv("TMPDIR")) != NULL)
|
||||
{
|
||||
r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
|
||||
|
||||
if (r > 0 && (size_t)r < len)
|
||||
return;
|
||||
}
|
||||
|
||||
r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
|
||||
|
||||
if (r < 0 || (size_t)r >= len)
|
||||
{
|
||||
fprintf(stderr, "%s: template string too short", __func__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This uses parts of main() in ssh-agent.c from openssh */
|
||||
static void
|
||||
setup_ssh_agent(struct sockaddr_un* addr)
|
||||
{
|
||||
int rc;
|
||||
/* Create private directory for agent socket */
|
||||
mktemp_proto(socket_dir, sizeof(socket_dir));
|
||||
|
||||
if (mkdtemp(socket_dir) == NULL)
|
||||
{
|
||||
perror("mkdtemp: private socket dir");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
|
||||
(long)getpid());
|
||||
/* Create unix domain socket */
|
||||
unlink(socket_name);
|
||||
sa_uds_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (sa_uds_fd == -1)
|
||||
{
|
||||
fprintf(stderr, "sshagent: socket creation failed");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
memset(addr, 0, sizeof(struct sockaddr_un));
|
||||
addr->sun_family = AF_UNIX;
|
||||
strncpy(addr->sun_path, socket_name, sizeof(addr->sun_path));
|
||||
addr->sun_path[sizeof(addr->sun_path) - 1] = 0;
|
||||
/* Create with privileges rw------- so other users can't access the UDS */
|
||||
mode_t umask_sav = umask(0177);
|
||||
rc = bind(sa_uds_fd, (struct sockaddr*)addr, sizeof(struct sockaddr_un));
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf(stderr, "sshagent: bind failed");
|
||||
close(sa_uds_fd);
|
||||
unlink(socket_name);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
umask(umask_sav);
|
||||
rc = listen(sa_uds_fd, /* backlog = */ 5);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf(stderr, "listen failed\n");
|
||||
close(sa_uds_fd);
|
||||
unlink(socket_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now fork: the child becomes the ssh-agent daemon and the parent prints
|
||||
* out the pid and socket name. */
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
else if (pid != 0)
|
||||
{
|
||||
/* Parent */
|
||||
close(sa_uds_fd);
|
||||
printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n", socket_name);
|
||||
printf("SSH_AGENT_PID=%d; export SSH_AGENT_PID;\n", pid);
|
||||
printf("echo Agent pid %d;\n", pid);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Child */
|
||||
|
||||
if (setsid() == -1)
|
||||
{
|
||||
fprintf(stderr, "setsid failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
(void)chdir("/");
|
||||
int devnullfd;
|
||||
|
||||
if ((devnullfd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1)
|
||||
{
|
||||
/* XXX might close listen socket */
|
||||
(void)dup2(devnullfd, STDIN_FILENO);
|
||||
(void)dup2(devnullfd, STDOUT_FILENO);
|
||||
(void)dup2(devnullfd, STDERR_FILENO);
|
||||
|
||||
if (devnullfd > 2)
|
||||
close(devnullfd);
|
||||
}
|
||||
|
||||
/* deny core dumps, since memory contains unencrypted private keys */
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = rlim.rlim_max = 0;
|
||||
|
||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||
{
|
||||
fprintf(stderr, "setrlimit RLIMIT_CORE: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handle_connection(int client_fd)
|
||||
{
|
||||
int rdp_fd = -1;
|
||||
int rc;
|
||||
void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION,
|
||||
"SSHAGENT",
|
||||
WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED);
|
||||
|
||||
if (channel == NULL)
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelOpenEx() failed\n");
|
||||
}
|
||||
|
||||
unsigned int retlen;
|
||||
int* retdata;
|
||||
rc = WTSVirtualChannelQuery(channel,
|
||||
WTSVirtualFileHandle,
|
||||
(void**)&retdata,
|
||||
&retlen);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelQuery() failed\n");
|
||||
}
|
||||
|
||||
if (retlen != sizeof(rdp_fd))
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %d\n",
|
||||
retlen);
|
||||
}
|
||||
|
||||
rdp_fd = *retdata;
|
||||
int client_going = 1;
|
||||
|
||||
while (client_going)
|
||||
{
|
||||
/* Wait for data from RDP or the client */
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(client_fd, &readfds);
|
||||
FD_SET(rdp_fd, &readfds);
|
||||
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(rdp_fd, &readfds))
|
||||
{
|
||||
/* Read from RDP and write to the client */
|
||||
char buffer[4096];
|
||||
unsigned int bytes_to_write;
|
||||
rc = WTSVirtualChannelRead(channel,
|
||||
/* TimeOut = */ 5000,
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
&bytes_to_write);
|
||||
|
||||
if (rc == 1)
|
||||
{
|
||||
char* pos = buffer;
|
||||
errno = 0;
|
||||
|
||||
while (bytes_to_write > 0)
|
||||
{
|
||||
int bytes_written = send(client_fd, pos, bytes_to_write, 0);
|
||||
|
||||
if (bytes_written > 0)
|
||||
{
|
||||
bytes_to_write -= bytes_written;
|
||||
pos += bytes_written;
|
||||
}
|
||||
else if (bytes_written == 0)
|
||||
{
|
||||
fprintf(stderr, "send() returned 0!\n");
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
/* Error */
|
||||
fprintf(stderr, "Error %d on recv\n", errno);
|
||||
client_going = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error */
|
||||
fprintf(stderr, "WTSVirtualChannelRead() failed: %d\n", errno);
|
||||
client_going = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(client_fd, &readfds))
|
||||
{
|
||||
/* Read from the client and write to RDP */
|
||||
char buffer[4096];
|
||||
ssize_t bytes_to_write = recv(client_fd, buffer, sizeof(buffer), 0);
|
||||
|
||||
if (bytes_to_write > 0)
|
||||
{
|
||||
char* pos = buffer;
|
||||
|
||||
while (bytes_to_write > 0)
|
||||
{
|
||||
unsigned int bytes_written;
|
||||
int rc = WTSVirtualChannelWrite(channel,
|
||||
pos,
|
||||
bytes_to_write,
|
||||
&bytes_written);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelWrite() failed: %d\n",
|
||||
errno);
|
||||
client_going = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_to_write -= bytes_written;
|
||||
pos += bytes_written;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bytes_to_write == 0)
|
||||
{
|
||||
/* Client has closed connection */
|
||||
client_going = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error */
|
||||
fprintf(stderr, "Error %d on recv\n", errno);
|
||||
client_going = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelClose(channel);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
/* Setup the Unix domain socket and daemon process */
|
||||
struct sockaddr_un addr;
|
||||
setup_ssh_agent(&addr);
|
||||
|
||||
/* Wait for a client to connect to the socket */
|
||||
while (is_going)
|
||||
{
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(sa_uds_fd, &readfds);
|
||||
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
|
||||
|
||||
/* If something connected then get it...
|
||||
* (You can test this using "socat - UNIX-CONNECT:<udspath>".) */
|
||||
if (FD_ISSET(sa_uds_fd, &readfds))
|
||||
{
|
||||
socklen_t addrsize = sizeof(addr);
|
||||
int client_fd = accept(sa_uds_fd,
|
||||
(struct sockaddr*)&addr,
|
||||
&addrsize);
|
||||
handle_connection(client_fd);
|
||||
close(client_fd);
|
||||
}
|
||||
}
|
||||
|
||||
close(sa_uds_fd);
|
||||
unlink(socket_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vim: set sw=4:ts=4:et: */
|
||||
@ -72,7 +72,7 @@ static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device)
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(alsa->device, device, sizeof(alsa->device));
|
||||
strncpy(alsa->device, device, sizeof(alsa->device) - 1);
|
||||
}
|
||||
return tsmf_alsa_open_device(alsa);
|
||||
}
|
||||
|
||||
@ -61,6 +61,11 @@
|
||||
#define AV_CODEC_ID_AC3 CODEC_ID_AC3
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 34, 2)
|
||||
#define AV_CODEC_CAP_TRUNCATED CODEC_CAP_TRUNCATED
|
||||
#define AV_CODEC_FLAG_TRUNCATED CODEC_FLAG_TRUNCATED
|
||||
#endif
|
||||
|
||||
#if LIBAVUTIL_VERSION_MAJOR < 52
|
||||
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
|
||||
#endif
|
||||
@ -75,12 +80,12 @@ typedef struct _TSMFFFmpegDecoder
|
||||
#else
|
||||
enum AVCodecID codec_id;
|
||||
#endif
|
||||
AVCodecContext *codec_context;
|
||||
AVCodec *codec;
|
||||
AVFrame *frame;
|
||||
AVCodecContext* codec_context;
|
||||
AVCodec* codec;
|
||||
AVFrame* frame;
|
||||
int prepared;
|
||||
|
||||
BYTE *decoded_data;
|
||||
BYTE* decoded_data;
|
||||
UINT32 decoded_size;
|
||||
UINT32 decoded_size_max;
|
||||
} TSMFFFmpegDecoder;
|
||||
@ -89,15 +94,17 @@ static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec_context = avcodec_alloc_context3(NULL);
|
||||
|
||||
if (!mdecoder->codec_context)
|
||||
{
|
||||
WLog_ERR(TAG, "avcodec_alloc_context failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec_context->width = media_type->Width;
|
||||
@ -113,7 +120,7 @@ static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MED
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator;
|
||||
@ -140,14 +147,14 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MED
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
{
|
||||
BYTE *p;
|
||||
BYTE* p;
|
||||
UINT32 size;
|
||||
const BYTE *s;
|
||||
const BYTE* s;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id);
|
||||
|
||||
if (!mdecoder->codec)
|
||||
{
|
||||
WLog_ERR(TAG, "avcodec_find_decoder failed.");
|
||||
@ -156,16 +163,21 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
|
||||
|
||||
mdecoder->codec_context->codec_id = mdecoder->codec_id;
|
||||
mdecoder->codec_context->codec_type = mdecoder->media_type;
|
||||
switch(mdecoder->media_type)
|
||||
|
||||
switch (mdecoder->media_type)
|
||||
{
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
if (!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
if (!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown media_type %d", mdecoder->media_type);
|
||||
break;
|
||||
@ -176,11 +188,12 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
|
||||
/* Add a padding to avoid invalid memory read in some codec */
|
||||
mdecoder->codec_context->extradata_size = media_type->ExtraDataSize + 8;
|
||||
mdecoder->codec_context->extradata = calloc(1, mdecoder->codec_context->extradata_size);
|
||||
|
||||
if (!mdecoder->codec_context->extradata)
|
||||
return FALSE;
|
||||
|
||||
if (media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
{
|
||||
/* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
|
||||
See http://haali.su/mkv/codecs.pdf */
|
||||
@ -207,62 +220,77 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
|
||||
}
|
||||
}
|
||||
|
||||
if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED;
|
||||
if (mdecoder->codec->capabilities & AV_CODEC_CAP_TRUNCATED)
|
||||
mdecoder->codec_context->flags |= AV_CODEC_FLAG_TRUNCATED;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "avcodec_open2 failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mdecoder->prepared = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE *media_type)
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
switch(media_type->MajorType)
|
||||
|
||||
switch (media_type->MajorType)
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
mdecoder->media_type = AVMEDIA_TYPE_VIDEO;
|
||||
break;
|
||||
|
||||
case TSMF_MAJOR_TYPE_AUDIO:
|
||||
mdecoder->media_type = AVMEDIA_TYPE_AUDIO;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
switch(media_type->SubType)
|
||||
|
||||
switch (media_type->SubType)
|
||||
{
|
||||
case TSMF_SUB_TYPE_WVC1:
|
||||
mdecoder->codec_id = AV_CODEC_ID_VC1;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_WMA2:
|
||||
mdecoder->codec_id = AV_CODEC_ID_WMAV2;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_WMA9:
|
||||
mdecoder->codec_id = AV_CODEC_ID_WMAPRO;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_MP3:
|
||||
mdecoder->codec_id = AV_CODEC_ID_MP3;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_MP2A:
|
||||
mdecoder->codec_id = AV_CODEC_ID_MP2;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_MP2V:
|
||||
mdecoder->codec_id = AV_CODEC_ID_MPEG2VIDEO;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_WMV3:
|
||||
mdecoder->codec_id = AV_CODEC_ID_WMV3;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_AAC:
|
||||
mdecoder->codec_id = AV_CODEC_ID_AAC;
|
||||
|
||||
/* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data
|
||||
is at the end of it. See
|
||||
http://msdn.microsoft.com/en-us/library/dd757806.aspx */
|
||||
@ -271,32 +299,41 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE *medi
|
||||
media_type->ExtraData += 12;
|
||||
media_type->ExtraDataSize -= 12;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_H264:
|
||||
case TSMF_SUB_TYPE_AVC1:
|
||||
mdecoder->codec_id = AV_CODEC_ID_H264;
|
||||
break;
|
||||
|
||||
case TSMF_SUB_TYPE_AC3:
|
||||
mdecoder->codec_id = AV_CODEC_ID_AC3;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!tsmf_ffmpeg_init_context(decoder))
|
||||
return FALSE;
|
||||
|
||||
if (!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
|
||||
if (!tsmf_ffmpeg_prepare(decoder))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size,
|
||||
UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
int decoded;
|
||||
int len;
|
||||
AVFrame *frame;
|
||||
AVFrame* frame;
|
||||
BOOL ret = TRUE;
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
|
||||
len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size);
|
||||
@ -304,13 +341,16 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE *data, UI
|
||||
{
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE *) data;
|
||||
pkt.data = (BYTE*) data;
|
||||
pkt.size = data_size;
|
||||
|
||||
if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
pkt.flags |= AV_PKT_FLAG_KEY;
|
||||
|
||||
len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "data_size %"PRIu32", avcodec_decode_video failed (%d)", data_size, len);
|
||||
@ -324,14 +364,15 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE *data, UI
|
||||
else
|
||||
{
|
||||
DEBUG_TSMF("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
|
||||
"pix_fmt %d width %d height %d",
|
||||
mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
|
||||
mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
"pix_fmt %d width %d height %d",
|
||||
mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
|
||||
mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_data = calloc(1, mdecoder->decoded_size);
|
||||
|
||||
if (!mdecoder->decoded_data)
|
||||
return FALSE;
|
||||
|
||||
@ -341,151 +382,172 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE *data, UI
|
||||
frame = av_frame_alloc();
|
||||
#endif
|
||||
avpicture_fill((AVPicture*) frame, mdecoder->decoded_data,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
av_picture_copy((AVPicture*) frame, (AVPicture*) mdecoder->frame,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
av_free(frame);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size,
|
||||
UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
int len;
|
||||
int frame_size;
|
||||
UINT32 src_size;
|
||||
const BYTE *src;
|
||||
BYTE *dst;
|
||||
const BYTE* src;
|
||||
BYTE* dst;
|
||||
int dst_offset;
|
||||
#if 0
|
||||
WLog_DBG(TAG, ("tsmf_ffmpeg_decode_audio: data_size %"PRIu32"", data_size));
|
||||
int i;
|
||||
for(i = 0; i < data_size; i++)
|
||||
|
||||
for (i = 0; i < data_size; i++)
|
||||
{
|
||||
WLog_DBG(TAG, ("%02"PRIX8"", data[i]));
|
||||
|
||||
if (i % 16 == 15)
|
||||
WLog_DBG(TAG, ("\n"));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (mdecoder->decoded_size_max == 0)
|
||||
mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16;
|
||||
|
||||
mdecoder->decoded_data = calloc(1, mdecoder->decoded_size_max);
|
||||
|
||||
if (!mdecoder->decoded_data)
|
||||
return FALSE;
|
||||
|
||||
/* align the memory for SSE2 needs */
|
||||
dst = (BYTE *)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
dst = (BYTE*)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
dst_offset = dst - mdecoder->decoded_data;
|
||||
src = data;
|
||||
src_size = data_size;
|
||||
while(src_size > 0)
|
||||
|
||||
while (src_size > 0)
|
||||
{
|
||||
/* Ensure enough space for decoding */
|
||||
if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
{
|
||||
BYTE *tmp_data;
|
||||
|
||||
BYTE* tmp_data;
|
||||
tmp_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max * 2 + 16);
|
||||
|
||||
if (!tmp_data)
|
||||
return FALSE;
|
||||
|
||||
mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16;
|
||||
mdecoder->decoded_data = tmp_data;
|
||||
dst = (BYTE*)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
|
||||
dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
if (dst - mdecoder->decoded_data != dst_offset)
|
||||
{
|
||||
/* re-align the memory if the alignment has changed after realloc */
|
||||
memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
dst_offset = dst - mdecoder->decoded_data;
|
||||
}
|
||||
|
||||
dst += mdecoder->decoded_size;
|
||||
}
|
||||
|
||||
frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size;
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
|
||||
len = avcodec_decode_audio2(mdecoder->codec_context,
|
||||
(int16_t *) dst, &frame_size, src, src_size);
|
||||
(int16_t*) dst, &frame_size, src, src_size);
|
||||
#else
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 55
|
||||
AVFrame *decoded_frame = avcodec_alloc_frame();
|
||||
AVFrame* decoded_frame = avcodec_alloc_frame();
|
||||
#else
|
||||
AVFrame *decoded_frame = av_frame_alloc();
|
||||
AVFrame* decoded_frame = av_frame_alloc();
|
||||
#endif
|
||||
int got_frame = 0;
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE *) src;
|
||||
pkt.data = (BYTE*) src;
|
||||
pkt.size = src_size;
|
||||
len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt);
|
||||
|
||||
if (len >= 0 && got_frame)
|
||||
{
|
||||
frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels,
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
memcpy(dst, decoded_frame->data[0], frame_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_size = 0;
|
||||
}
|
||||
|
||||
av_free(decoded_frame);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
src += len;
|
||||
src_size -= len;
|
||||
}
|
||||
if(frame_size > 0)
|
||||
|
||||
if (frame_size > 0)
|
||||
{
|
||||
mdecoder->decoded_size += frame_size;
|
||||
dst += frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (mdecoder->decoded_size == 0)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
else
|
||||
if (dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
}
|
||||
else if (dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
}
|
||||
|
||||
DEBUG_TSMF("data_size %"PRIu32" decoded_size %"PRIu32"",
|
||||
data_size, mdecoder->decoded_size);
|
||||
data_size, mdecoder->decoded_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size,
|
||||
UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->decoded_data)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
|
||||
mdecoder->decoded_size = 0;
|
||||
switch(mdecoder->media_type)
|
||||
|
||||
switch (mdecoder->media_type)
|
||||
{
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
return tsmf_ffmpeg_decode_video(decoder, data, data_size, extensions);
|
||||
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
return tsmf_ffmpeg_decode_audio(decoder, data, data_size, extensions);
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown media type.");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32 *size)
|
||||
static BYTE* tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32* size)
|
||||
{
|
||||
BYTE *buf;
|
||||
BYTE* buf;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
*size = mdecoder->decoded_size;
|
||||
buf = mdecoder->decoded_data;
|
||||
@ -502,14 +564,15 @@ static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder)
|
||||
{
|
||||
case AV_PIX_FMT_YUV420P:
|
||||
return RDP_PIXFMT_I420;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unsupported pixel format %u",
|
||||
mdecoder->codec_context->pix_fmt);
|
||||
return (UINT32) -1;
|
||||
mdecoder->codec_context->pix_fmt);
|
||||
return (UINT32) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32 *width, UINT32 *height)
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* width, UINT32* height)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
@ -528,6 +591,7 @@ static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32 *wid
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->frame)
|
||||
av_free(mdecoder->frame);
|
||||
|
||||
@ -541,10 +605,16 @@ static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
|
||||
free(mdecoder->codec_context->extradata);
|
||||
av_free(mdecoder->codec_context);
|
||||
}
|
||||
|
||||
free(decoder);
|
||||
}
|
||||
|
||||
static BOOL initialized = FALSE;
|
||||
static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT;
|
||||
static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
avcodec_register_all();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_CHANNELS
|
||||
#define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry
|
||||
@ -555,15 +625,8 @@ static BOOL initialized = FALSE;
|
||||
ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void)
|
||||
{
|
||||
TSMFFFmpegDecoder* decoder;
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
avcodec_register_all();
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
InitOnceExecuteOnce(&g_Initialized, InitializeAvCodecs, NULL, NULL);
|
||||
WLog_DBG(TAG, "TSMFDecoderEntry FFMPEG");
|
||||
|
||||
decoder = (TSMFFFmpegDecoder*) calloc(1, sizeof(TSMFFFmpegDecoder));
|
||||
|
||||
if (!decoder)
|
||||
@ -575,6 +638,5 @@ ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void)
|
||||
decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format;
|
||||
decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension;
|
||||
decoder->iface.Free = tsmf_ffmpeg_free;
|
||||
|
||||
return (ITSMFDecoder*) decoder;
|
||||
}
|
||||
|
||||
@ -33,7 +33,15 @@
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wparentheses-equality"
|
||||
#endif /* __clang__ */
|
||||
#include <gst/gst.h>
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif /* __clang__ */
|
||||
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
#include <gst/video/videooverlay.h>
|
||||
#else
|
||||
|
||||
@ -33,7 +33,15 @@
|
||||
|
||||
#include <winpr/string.h>
|
||||
|
||||
#if __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wparentheses-equality"
|
||||
#endif /* __clang__ */
|
||||
#include <gst/gst.h>
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif /* __clang__ */
|
||||
|
||||
#include <gst/app/gstappsrc.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ static BOOL tsmf_oss_open(ITSMFAudioDevice* audio, const char* device)
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(oss->dev_name, device, sizeof(oss->dev_name));
|
||||
strncpy(oss->dev_name, device, sizeof(oss->dev_name) - 1);
|
||||
}
|
||||
|
||||
if ((oss->pcm_handle = open(oss->dev_name, O_WRONLY)) < 0)
|
||||
|
||||
@ -115,7 +115,7 @@ static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device)
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
if(device)
|
||||
{
|
||||
strcpy(pulse->device, device);
|
||||
strncpy(pulse->device, device, sizeof(pulse->device) - 1);
|
||||
}
|
||||
pulse->mainloop = pa_threaded_mainloop_new();
|
||||
if(!pulse->mainloop)
|
||||
|
||||
@ -482,7 +482,7 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
|
||||
int num_rects = 0;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
int i;
|
||||
int pos;
|
||||
size_t pos;
|
||||
|
||||
if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 32)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
@ -123,7 +123,7 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback,
|
||||
*/
|
||||
static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
int length;
|
||||
size_t length;
|
||||
wStream *input;
|
||||
wStream *output;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
@ -737,7 +737,7 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* tsmf_stream_ack_func(void* arg)
|
||||
static DWORD WINAPI tsmf_stream_ack_func(LPVOID arg)
|
||||
{
|
||||
HANDLE hdl[2];
|
||||
TSMF_STREAM* stream = (TSMF_STREAM*) arg;
|
||||
@ -817,11 +817,11 @@ static void* tsmf_stream_ack_func(void* arg)
|
||||
"tsmf_stream_ack_func reported an error");
|
||||
|
||||
DEBUG_TSMF("out %"PRIu32"", stream->stream_id);
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void* tsmf_stream_playback_func(void* arg)
|
||||
static DWORD WINAPI tsmf_stream_playback_func(LPVOID arg)
|
||||
{
|
||||
HANDLE hdl[2];
|
||||
TSMF_SAMPLE* sample = NULL;
|
||||
@ -907,8 +907,8 @@ static void* tsmf_stream_playback_func(void* arg)
|
||||
"tsmf_stream_playback_func reported an error");
|
||||
|
||||
DEBUG_TSMF("out %"PRIu32"", stream->stream_id);
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static BOOL tsmf_stream_start(TSMF_STREAM* stream)
|
||||
@ -1259,13 +1259,13 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id,
|
||||
goto error_sample_ack_list;
|
||||
|
||||
stream->sample_ack_list->object.fnObjectFree = tsmf_sample_free;
|
||||
stream->play_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func,
|
||||
stream->play_thread = CreateThread(NULL, 0, tsmf_stream_playback_func,
|
||||
stream, CREATE_SUSPENDED, NULL);
|
||||
|
||||
if (!stream->play_thread)
|
||||
goto error_play_thread;
|
||||
|
||||
stream->ack_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream,
|
||||
stream->ack_thread = CreateThread(NULL, 0, tsmf_stream_ack_func, stream,
|
||||
CREATE_SUSPENDED, NULL);
|
||||
|
||||
if (!stream->ack_thread)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -35,16 +35,16 @@
|
||||
int libusb_debug;
|
||||
|
||||
#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \
|
||||
static _type udevman_get_##_arg (IUDEVMAN* idevman) \
|
||||
{ \
|
||||
UDEVMAN * udevman = (UDEVMAN *) idevman; \
|
||||
return udevman->_arg; \
|
||||
} \
|
||||
static void udevman_set_##_arg (IUDEVMAN* idevman, _type _t) \
|
||||
{ \
|
||||
UDEVMAN * udevman = (UDEVMAN *) idevman; \
|
||||
udevman->_arg = _t; \
|
||||
}
|
||||
static _type udevman_get_##_arg (IUDEVMAN* idevman) \
|
||||
{ \
|
||||
UDEVMAN * udevman = (UDEVMAN *) idevman; \
|
||||
return udevman->_arg; \
|
||||
} \
|
||||
static void udevman_set_##_arg (IUDEVMAN* idevman, _type _t) \
|
||||
{ \
|
||||
UDEVMAN * udevman = (UDEVMAN *) idevman; \
|
||||
udevman->_arg = _t; \
|
||||
}
|
||||
|
||||
#define BASIC_STATE_FUNC_REGISTER(_arg, _man) \
|
||||
_man->iface.get_##_arg = udevman_get_##_arg; \
|
||||
@ -90,17 +90,14 @@ static IUDEVICE* udevman_get_next(IUDEVMAN* idevman)
|
||||
{
|
||||
UDEVMAN* udevman = (UDEVMAN*) idevman;
|
||||
IUDEVICE* pdev;
|
||||
|
||||
pdev = udevman->idev;
|
||||
udevman->idev = (IUDEVICE*) ((UDEVICE*) udevman->idev)->next;
|
||||
|
||||
udevman->idev = (IUDEVICE*)((UDEVICE*) udevman->idev)->next;
|
||||
return pdev;
|
||||
}
|
||||
|
||||
static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, int bus_number, int dev_number)
|
||||
{
|
||||
IUDEVICE* pdev;
|
||||
|
||||
idevman->loading_lock(idevman);
|
||||
idevman->rewind(idevman);
|
||||
|
||||
@ -117,23 +114,22 @@ static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, int bus_number,
|
||||
|
||||
idevman->loading_unlock(idevman);
|
||||
WLog_WARN(TAG, "bus:%d dev:%d not exist in udevman",
|
||||
bus_number, dev_number);
|
||||
bus_number, dev_number);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_number,
|
||||
int UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag)
|
||||
int UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag)
|
||||
{
|
||||
UDEVMAN* udevman = (UDEVMAN*) idevman;
|
||||
IUDEVICE* pdev = NULL;
|
||||
IUDEVICE** devArray;
|
||||
int i, num, addnum = 0;
|
||||
|
||||
pdev = (IUDEVICE*) udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
|
||||
|
||||
if (pdev != NULL)
|
||||
return 0;
|
||||
|
||||
|
||||
if (flag == UDEVMAN_FLAG_ADD_BY_ADDR)
|
||||
{
|
||||
pdev = udev_new_by_addr(bus_number, dev_number);
|
||||
@ -171,8 +167,8 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n
|
||||
{
|
||||
pdev = devArray[i];
|
||||
|
||||
if (udevman_get_udevice_by_addr(idevman,
|
||||
pdev->get_bus_number(pdev), pdev->get_dev_number(pdev)) != NULL)
|
||||
if (udevman_get_udevice_by_addr(idevman,
|
||||
pdev->get_bus_number(pdev), pdev->get_dev_number(pdev)) != NULL)
|
||||
{
|
||||
zfree(pdev);
|
||||
continue;
|
||||
@ -215,11 +211,9 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n
|
||||
static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev_number)
|
||||
{
|
||||
UDEVMAN* udevman = (UDEVMAN*) idevman;
|
||||
UDEVICE * pdev, * dev;
|
||||
UDEVICE* pdev, * dev;
|
||||
int ret = 0, err = 0;
|
||||
|
||||
dev = (UDEVICE*) udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
|
||||
|
||||
idevman->loading_lock(idevman);
|
||||
idevman->rewind(idevman);
|
||||
|
||||
@ -230,7 +224,6 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev
|
||||
if (pdev == dev) /* device exists */
|
||||
{
|
||||
/* set previous device to point to next device */
|
||||
|
||||
if (dev->prev != NULL)
|
||||
{
|
||||
/* unregistered device is not the head */
|
||||
@ -248,7 +241,7 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev
|
||||
if (dev->next != NULL)
|
||||
{
|
||||
/* unregistered device is not the tail */
|
||||
pdev = (UDEVICE *)dev->next;
|
||||
pdev = (UDEVICE*)dev->next;
|
||||
pdev->prev = dev->prev;
|
||||
}
|
||||
else
|
||||
@ -256,11 +249,12 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev
|
||||
/* unregistered device is the tail, update tail */
|
||||
udevman->tail = (IUDEVICE*)dev->prev;
|
||||
}
|
||||
|
||||
udevman->device_num--;
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
idevman->loading_unlock(idevman);
|
||||
|
||||
if (dev)
|
||||
@ -269,28 +263,31 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev
|
||||
if (err != LIBUSB_ERROR_NO_DEVICE)
|
||||
{
|
||||
ret = libusb_reset_device(dev->libusb_handle);
|
||||
if (ret<0)
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "libusb_reset_device: ERROR!!ret:%d", ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* release all interface and attach kernel driver */
|
||||
dev->iface.attach_kernel_driver((IUDEVICE*)dev);
|
||||
|
||||
if(dev->request_queue) zfree(dev->request_queue);
|
||||
dev->iface.attach_kernel_driver((IUDEVICE*)dev);
|
||||
|
||||
if (dev->request_queue) zfree(dev->request_queue);
|
||||
|
||||
/* free the config descriptor that send from windows */
|
||||
msusb_msconfig_free(dev->MsConfig);
|
||||
|
||||
libusb_close (dev->libusb_handle);
|
||||
libusb_close (dev->hub_handle);
|
||||
|
||||
libusb_close(dev->libusb_handle);
|
||||
libusb_close(dev->hub_handle);
|
||||
sem_destroy(&dev->sem_id);
|
||||
|
||||
/* free device info */
|
||||
if (dev->devDescriptor)
|
||||
zfree(dev->devDescriptor);
|
||||
|
||||
if (dev)
|
||||
zfree(dev);
|
||||
zfree(dev);
|
||||
|
||||
return 1; /* unregistration successful */
|
||||
}
|
||||
|
||||
@ -302,28 +299,22 @@ static void udevman_parse_device_addr(char* str, int* id1, int* id2, char sign)
|
||||
{
|
||||
char s1[8];
|
||||
char* s2;
|
||||
|
||||
ZeroMemory(s1, sizeof(s1));
|
||||
|
||||
s2 = (strchr(str, sign)) + 1;
|
||||
s2 = (strchr(str, sign)) + 1;
|
||||
strncpy(s1, str, strlen(str) - (strlen(s2) + 1));
|
||||
|
||||
*id1 = atoi(s1);
|
||||
*id2 = atoi(s2);
|
||||
*id1 = strtol(s1, NULL, 0);
|
||||
*id2 = strtol(s2, NULL, 0);
|
||||
}
|
||||
|
||||
static void udevman_parse_device_pid_vid(char* str, int* id1, int* id2, char sign)
|
||||
{
|
||||
char s1[8];
|
||||
char* s2;
|
||||
|
||||
ZeroMemory(s1, sizeof(s1));
|
||||
|
||||
s2 = (strchr(str, sign)) + 1;
|
||||
s2 = (strchr(str, sign)) + 1;
|
||||
strncpy(s1, str, strlen(str) - (strlen(s2) + 1));
|
||||
|
||||
*id1 = (int) strtol(s1, NULL, 16);
|
||||
*id2 = (int) strtol(s2, NULL, 16);
|
||||
*id1 = strtol(s1, NULL, 16);
|
||||
*id2 = strtol(s2, NULL, 16);
|
||||
}
|
||||
|
||||
static int udevman_check_device_exist_by_id(IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct)
|
||||
@ -358,7 +349,6 @@ static IUDEVICE* udevman_get_udevice_by_UsbDevice_try_again(IUDEVMAN* idevman, U
|
||||
}
|
||||
|
||||
idevman->loading_unlock(idevman);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -380,9 +370,7 @@ static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbD
|
||||
}
|
||||
|
||||
idevman->loading_unlock(idevman);
|
||||
|
||||
/* try again */
|
||||
|
||||
pdev = (UDEVICE*) idevman->get_udevice_by_UsbDevice_try_again(idevman, UsbDevice);
|
||||
|
||||
if (pdev)
|
||||
@ -425,10 +413,8 @@ BASIC_STATE_FUNC_DEFINED(sem_timeout, int)
|
||||
static void udevman_free(IUDEVMAN* idevman)
|
||||
{
|
||||
UDEVMAN* udevman = (UDEVMAN*) idevman;
|
||||
|
||||
pthread_mutex_destroy(&udevman->devman_loading);
|
||||
sem_destroy(&udevman->sem_urb_lock);
|
||||
|
||||
libusb_exit(NULL);
|
||||
|
||||
/* free udevman */
|
||||
@ -437,11 +423,10 @@ static void udevman_free(IUDEVMAN* idevman)
|
||||
zfree(udevman);
|
||||
}
|
||||
|
||||
static void udevman_load_interface(UDEVMAN * udevman)
|
||||
static void udevman_load_interface(UDEVMAN* udevman)
|
||||
{
|
||||
/* standard */
|
||||
udevman->iface.free = udevman_free;
|
||||
|
||||
/* manage devices */
|
||||
udevman->iface.rewind = udevman_rewind;
|
||||
udevman->iface.get_next = udevman_get_next;
|
||||
@ -449,18 +434,15 @@ static void udevman_load_interface(UDEVMAN * udevman)
|
||||
udevman->iface.register_udevice = udevman_register_udevice;
|
||||
udevman->iface.unregister_udevice = udevman_unregister_udevice;
|
||||
udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
|
||||
udevman->iface.get_udevice_by_UsbDevice_try_again =
|
||||
udevman_get_udevice_by_UsbDevice_try_again;
|
||||
|
||||
udevman->iface.get_udevice_by_UsbDevice_try_again =
|
||||
udevman_get_udevice_by_UsbDevice_try_again;
|
||||
/* Extension */
|
||||
udevman->iface.check_device_exist_by_id = udevman_check_device_exist_by_id;
|
||||
udevman->iface.isAutoAdd = udevman_is_auto_add;
|
||||
|
||||
/* Basic state */
|
||||
BASIC_STATE_FUNC_REGISTER(defUsbDevice, udevman);
|
||||
BASIC_STATE_FUNC_REGISTER(device_num, udevman);
|
||||
BASIC_STATE_FUNC_REGISTER(sem_timeout, udevman);
|
||||
|
||||
/* control semaphore or mutex lock */
|
||||
udevman->iface.loading_lock = udevman_loading_lock;
|
||||
udevman->iface.loading_unlock = udevman_loading_unlock;
|
||||
@ -502,7 +484,6 @@ static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices)
|
||||
dev_number = 0;
|
||||
idVendor = 0;
|
||||
idProduct = 0;
|
||||
|
||||
strcpy(hardware_id, token);
|
||||
token = strtok(NULL, "#");
|
||||
|
||||
@ -510,14 +491,13 @@ static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices)
|
||||
{
|
||||
udevman_parse_device_pid_vid(hardware_id, &idVendor, &idProduct, ':');
|
||||
success = udevman->iface.register_udevice((IUDEVMAN*) udevman,
|
||||
0, 0, UsbDevice, (UINT16) idVendor, (UINT16) idProduct, UDEVMAN_FLAG_ADD_BY_VID_PID);
|
||||
0, 0, UsbDevice, (UINT16) idVendor, (UINT16) idProduct, UDEVMAN_FLAG_ADD_BY_VID_PID);
|
||||
}
|
||||
else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR)
|
||||
{
|
||||
udevman_parse_device_addr(hardware_id, &bus_number, &dev_number, ':');
|
||||
|
||||
success = udevman->iface.register_udevice((IUDEVMAN*) udevman,
|
||||
bus_number, dev_number, UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR);
|
||||
bus_number, dev_number, UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR);
|
||||
}
|
||||
|
||||
if (success)
|
||||
@ -532,12 +512,9 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
|
||||
int status;
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
|
||||
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
|
||||
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv,
|
||||
urbdrc_udevman_args, flags, udevman, NULL, NULL);
|
||||
|
||||
urbdrc_udevman_args, flags, udevman, NULL, NULL);
|
||||
arg = urbdrc_udevman_args;
|
||||
|
||||
do
|
||||
@ -546,7 +523,6 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
|
||||
continue;
|
||||
|
||||
CommandLineSwitchStart(arg)
|
||||
|
||||
CommandLineSwitchCase(arg, "dbg")
|
||||
{
|
||||
WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE);
|
||||
@ -569,9 +545,7 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
@ -587,34 +561,26 @@ int freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS p
|
||||
{
|
||||
UDEVMAN* udevman;
|
||||
ADDIN_ARGV* args = pEntryPoints->args;
|
||||
|
||||
libusb_init(NULL);
|
||||
|
||||
udevman = (PUDEVMAN) malloc(sizeof(UDEVMAN));
|
||||
|
||||
if (!udevman)
|
||||
return -1;
|
||||
|
||||
udevman->device_num = 0;
|
||||
udevman->idev = NULL;
|
||||
udevman->head = NULL;
|
||||
udevman->tail = NULL;
|
||||
udevman->tail = NULL;
|
||||
udevman->sem_timeout = 0;
|
||||
udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
|
||||
|
||||
pthread_mutex_init(&udevman->devman_loading, NULL);
|
||||
sem_init(&udevman->sem_urb_lock, 0, MAX_URB_REQUSET_NUM);
|
||||
|
||||
/* load usb device service management */
|
||||
udevman_load_interface(udevman);
|
||||
|
||||
/* set debug flag, to enable Debug message for usb data transfer */
|
||||
|
||||
libusb_debug = 10;
|
||||
|
||||
urbdrc_udevman_parse_addin_args(udevman, args);
|
||||
|
||||
pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*) udevman);
|
||||
|
||||
WLog_DBG(TAG, "UDEVMAN device registered.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
22
channels/video/CMakeLists.txt
Normal file
22
channels/video/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2017 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("video")
|
||||
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
12
channels/video/ChannelOptions.cmake
Normal file
12
channels/video/ChannelOptions.cmake
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
|
||||
define_channel_options(NAME "video" TYPE "dynamic"
|
||||
DESCRIPTION "Video optimized remoting Virtual Channel Extension"
|
||||
SPECIFICATIONS "[MS-RDPEVOR]"
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
||||
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||
|
||||
39
channels/video/client/CMakeLists.txt
Normal file
39
channels/video/client/CMakeLists.txt
Normal file
@ -0,0 +1,39 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2018 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_client("video")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
video_main.c
|
||||
video_main.h)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||
|
||||
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
||||
if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
||||
1168
channels/video/client/video_main.c
Executable file
1168
channels/video/client/video_main.c
Executable file
File diff suppressed because it is too large
Load Diff
35
channels/video/client/video_main.h
Normal file
35
channels/video/client/video_main.h
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Optimized Remoting Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_VIDEO_CLIENT_MAIN_H
|
||||
#define FREERDP_CHANNEL_VIDEO_CLIENT_MAIN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/addin.h>
|
||||
|
||||
#include <freerdp/channels/video.h>
|
||||
|
||||
|
||||
#endif /* FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H */
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
message("PRELOADING android cache")
|
||||
set(CMAKE_TOOLCHAIN_FILE "cmake/AndroidToolchain.cmake" CACHE PATH "ToolChain file")
|
||||
set(WITH_SANITIZE_ADDRESS ON)
|
||||
set(FREERDP_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl")
|
||||
# ANDROID_NDK and ANDROID_SDK must be set as environment variable
|
||||
#set(ANDROID_NDK $ENV{ANDROID_SDK} CACHE PATH "Android NDK")
|
||||
|
||||
@ -2,9 +2,10 @@ message("PRELOADING cache")
|
||||
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_CUPS OFF CACHE BOOL "CUPS printing")
|
||||
set (WITH_KRB5 ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_ALSA OFF CACHE BOOL "alsa audio")
|
||||
set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support")
|
||||
set (WITH_XV OFF CACHE BOOL "xvideo support")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_XSHM OFF CACHE BOOL "build with xshm support")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
message("PRELOADING android cache")
|
||||
set(CMAKE_TOOLCHAIN_FILE "cmake/iOSToolchain.cmake" CACHE PATH "ToolChain file")
|
||||
set(FREERDP_IOS_EXTERNAL_SSL_PATH $ENV{FREERDP_IOS_EXTERNAL_SSL_PATH} CACHE PATH "android ssl")
|
||||
set (CMAKE_TOOLCHAIN_FILE "cmake/iOSToolchain.cmake" CACHE PATH "ToolChain file")
|
||||
set (FREERDP_IOS_EXTERNAL_SSL_PATH $ENV{FREERDP_IOS_EXTERNAL_SSL_PATH} CACHE PATH "android ssl")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set(IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build")
|
||||
set (IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
|
||||
@ -7,7 +7,7 @@ set (WITH_PULSE ON CACHE BOOL "pulse")
|
||||
set (WITH_CHANNELS ON CACHE BOOL "channels")
|
||||
set (BUILTIN_CHANNELS ON CACHE BOOL "static channels")
|
||||
set (WITH_CUPS ON CACHE BOOL "cups")
|
||||
set (WITH_KRB5 ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_PCSC ON CACHE BOOL "PCSC")
|
||||
set (WITH_JPEG ON CACHE BOOL "jepg")
|
||||
set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer")
|
||||
@ -47,3 +47,4 @@ set (WITH_DEBUG_X11_LOCAL_MOVESIZE OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_XV OFF CACHE BOOL "enable debug")
|
||||
set (WITH_SAMPLE ON CACHE BOOL "samples")
|
||||
set (WITH_NO_UNDEFINED ON CACHE BOOL "don't link with undefined symbols")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
|
||||
@ -4,3 +4,4 @@ set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_CUPS ON CACHE BOOL "CUPS printing")
|
||||
set (WITH_X11 ON CACHE BOOL "Enable X11")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
|
||||
@ -2,9 +2,10 @@ message("PRELOADING cache")
|
||||
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_CUPS OFF CACHE BOOL "CUPS printing")
|
||||
set (WITH_KRB5 ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_ALSA OFF CACHE BOOL "alsa audio")
|
||||
set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support")
|
||||
set (WITH_XV OFF CACHE BOOL "xvideo support")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_XSHM OFF CACHE BOOL "build with xshm support")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
message("PRELOADING windows cache")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set(WITH_SERVER "ON" CACHE BOOL "Build server binaries")
|
||||
set (WITH_SERVER "ON" CACHE BOOL "Build server binaries")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
|
||||
@ -220,7 +220,7 @@ BOOL df_verify_certificate(freerdp* instance, char* subject, char* issuer,
|
||||
WLog_INFO(TAG,
|
||||
"The above X.509 certificate could not be verified, possibly because you do not have "
|
||||
"the CA certificate in your certificate store, or the certificate has expired. "
|
||||
"Please look at the documentation on how to create local certificate store for a private CA.");
|
||||
"Please look at the OpenSSL documentation on how to add a private CA to the store.");
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -422,7 +422,7 @@ int main(int argc, char* argv[])
|
||||
if (!(g_sem = CreateSemaphore(NULL, 0, 1, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create semaphore");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
instance = freerdp_new();
|
||||
@ -437,7 +437,7 @@ int main(int argc, char* argv[])
|
||||
if (!freerdp_context_new(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create FreeRDP context");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
context = (dfContext*) instance->context;
|
||||
@ -449,11 +449,11 @@ int main(int argc, char* argv[])
|
||||
argv, FALSE);
|
||||
|
||||
if (status < 0)
|
||||
exit(0);
|
||||
return 0;
|
||||
|
||||
if (!freerdp_client_load_addins(instance->context->channels,
|
||||
instance->settings))
|
||||
exit(-1);
|
||||
return -1;
|
||||
|
||||
data = (struct thread_data*) malloc(sizeof(struct thread_data));
|
||||
ZeroMemory(data, sizeof(sizeof(struct thread_data)));
|
||||
|
||||
@ -113,8 +113,9 @@ static BOOL tf_post_connect(freerdp* instance)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void* tf_client_thread_proc(freerdp* instance)
|
||||
static DWORD WINAPI tf_client_thread_proc(LPVOID arg)
|
||||
{
|
||||
freerdp* instance = (freerdp*)arg;
|
||||
DWORD nCount;
|
||||
DWORD status;
|
||||
HANDLE handles[64];
|
||||
@ -122,7 +123,7 @@ static void* tf_client_thread_proc(freerdp* instance)
|
||||
if (!freerdp_connect(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "connection failure");
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!freerdp_shall_disconnect(instance))
|
||||
@ -146,14 +147,16 @@ static void* tf_client_thread_proc(freerdp* instance)
|
||||
|
||||
if (!freerdp_check_event_handles(instance->context))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP event handles");
|
||||
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP event handles");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_disconnect(instance);
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@ -166,7 +169,7 @@ int main(int argc, char* argv[])
|
||||
if (!instance)
|
||||
{
|
||||
WLog_ERR(TAG, "Couldn't create instance");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
instance->PreConnect = tf_pre_connect;
|
||||
@ -174,13 +177,12 @@ int main(int argc, char* argv[])
|
||||
instance->ContextSize = sizeof(tfContext);
|
||||
instance->ContextNew = tf_context_new;
|
||||
instance->ContextFree = tf_context_free;
|
||||
|
||||
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
|
||||
|
||||
if (!freerdp_context_new(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Couldn't create context");
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = freerdp_client_settings_parse_command_line(instance->settings, argc,
|
||||
@ -188,16 +190,14 @@ int main(int argc, char* argv[])
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (!freerdp_client_load_addins(instance->context->channels,
|
||||
instance->settings))
|
||||
exit(-1);
|
||||
return -1;
|
||||
|
||||
if (!(thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
|
||||
tf_client_thread_proc, instance, 0, NULL)))
|
||||
if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create client thread");
|
||||
}
|
||||
|
||||
@ -56,11 +56,11 @@ static void wlf_encomsp_uninit(wlfContext* wlf, EncomspClientContext* encomsp)
|
||||
}
|
||||
|
||||
|
||||
void wlf_OnChannelConnectedEventHandler(rdpContext* context,
|
||||
void wlf_OnChannelConnectedEventHandler(void* context,
|
||||
ChannelConnectedEventArgs* e)
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*) context;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpSettings* settings = wlf->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@ -72,7 +72,7 @@ void wlf_OnChannelConnectedEventHandler(rdpContext* context,
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
gdi_graphics_pipeline_init(wlf->context.gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@ -86,11 +86,11 @@ void wlf_OnChannelConnectedEventHandler(rdpContext* context,
|
||||
}
|
||||
}
|
||||
|
||||
void wlf_OnChannelDisconnectedEventHandler(rdpContext* context,
|
||||
void wlf_OnChannelDisconnectedEventHandler(void* context,
|
||||
ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*) context;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpSettings* settings = wlf->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@ -102,7 +102,7 @@ void wlf_OnChannelDisconnectedEventHandler(rdpContext* context,
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_uninit(context->gdi,
|
||||
gdi_graphics_pipeline_uninit(wlf->context.gdi,
|
||||
(RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
|
||||
@ -34,9 +34,9 @@ int wlf_on_channel_connected(freerdp* instance, const char* name,
|
||||
int wlf_on_channel_disconnected(freerdp* instance, const char* name,
|
||||
void* pInterface);
|
||||
|
||||
void wlf_OnChannelConnectedEventHandler(rdpContext* context,
|
||||
void wlf_OnChannelConnectedEventHandler(void* context,
|
||||
ChannelConnectedEventArgs* e);
|
||||
void wlf_OnChannelDisconnectedEventHandler(rdpContext* context,
|
||||
void wlf_OnChannelDisconnectedEventHandler(void* context,
|
||||
ChannelDisconnectedEventArgs* e);
|
||||
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_CHANNELS_H */
|
||||
|
||||
@ -92,7 +92,7 @@ BOOL wlf_handle_key(freerdp *instance, UwacKeyEvent *ev) {
|
||||
rdpInput* input = instance->input;
|
||||
DWORD rdp_scancode;
|
||||
|
||||
rdp_scancode = (DWORD) ev->raw_key;
|
||||
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(ev->raw_key + 8);
|
||||
|
||||
if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
|
||||
return TRUE;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
.de URL
|
||||
\\$2 \(laURL: \\$1 \(ra\\$3
|
||||
..
|
||||
.if \n[.g] .mso www.tmac))
|
||||
.if \n[.g] .mso www.tmac
|
||||
.TH wlfreerdp 1 2017-01-12 "@FREERDP_VERSION_FULL@" "FreeRDP"
|
||||
.SH NAME
|
||||
wlfreerdp \- FreeRDP wayland client
|
||||
|
||||
@ -103,6 +103,8 @@ static BOOL wl_pre_connect(freerdp* instance)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
wlfContext* context;
|
||||
UwacOutput* output;
|
||||
UwacSize resolution;
|
||||
|
||||
if (!instance)
|
||||
return FALSE;
|
||||
@ -142,9 +144,25 @@ static BOOL wl_pre_connect(freerdp* instance)
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
||||
PubSub_SubscribeChannelConnected(instance->context->pubSub,
|
||||
(pChannelConnectedEventHandler) wlf_OnChannelConnectedEventHandler);
|
||||
wlf_OnChannelConnectedEventHandler);
|
||||
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
|
||||
(pChannelDisconnectedEventHandler) wlf_OnChannelDisconnectedEventHandler);
|
||||
wlf_OnChannelDisconnectedEventHandler);
|
||||
|
||||
if (settings->Fullscreen)
|
||||
{
|
||||
// Use the resolution of the first display output
|
||||
output = UwacDisplayGetOutput(context->display, 1);
|
||||
|
||||
if (output != NULL && UwacOutputGetResolution(output, &resolution) == UWAC_SUCCESS)
|
||||
{
|
||||
settings->DesktopWidth = (UINT32) resolution.width;
|
||||
settings->DesktopHeight = (UINT32) resolution.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_WARN(TAG, "Failed to get output resolution! Check your display settings");
|
||||
}
|
||||
}
|
||||
|
||||
if (!freerdp_client_load_addins(instance->context->channels,
|
||||
instance->settings))
|
||||
@ -176,15 +194,14 @@ static BOOL wl_post_connect(freerdp* instance)
|
||||
|
||||
UwacWindowSetFullscreenState(window, NULL, instance->context->settings->Fullscreen);
|
||||
UwacWindowSetTitle(window, "FreeRDP");
|
||||
UwacWindowSetOpaqueRegion(context->window, 0, 0, gdi->width, gdi->height);
|
||||
instance->update->BeginPaint = wl_begin_paint;
|
||||
instance->update->EndPaint = wl_end_paint;
|
||||
memcpy(UwacWindowGetDrawingBuffer(context->window), gdi->primary_buffer,
|
||||
gdi->width * gdi->height * 4);
|
||||
UwacWindowAddDamage(context->window, 0, 0, gdi->width, gdi->height);
|
||||
context->haveDamage = TRUE;
|
||||
|
||||
freerdp_keyboard_init(instance->context->settings->KeyboardLayout);
|
||||
|
||||
return wl_update_content(context);
|
||||
}
|
||||
|
||||
@ -328,7 +345,9 @@ static int wlfreerdp_run(freerdp* instance)
|
||||
//if (WaitForMultipleObjects(count, &handles[1], FALSE, INFINITE)) {
|
||||
if (freerdp_check_event_handles(instance->context) != TRUE)
|
||||
{
|
||||
printf("Failed to check FreeRDP file descriptor\n");
|
||||
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
|
||||
printf("Failed to check FreeRDP file descriptor\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -44,10 +44,14 @@ set(${MODULE_PREFIX}_SRCS
|
||||
xf_cliprdr.h
|
||||
xf_monitor.c
|
||||
xf_monitor.h
|
||||
xf_disp.c
|
||||
xf_disp.h
|
||||
xf_graphics.c
|
||||
xf_graphics.h
|
||||
xf_keyboard.c
|
||||
xf_keyboard.h
|
||||
xf_video.c
|
||||
xf_video.h
|
||||
xf_window.c
|
||||
xf_window.h
|
||||
xf_client.c
|
||||
@ -86,13 +90,19 @@ if(WITH_MANPAGES)
|
||||
|
||||
configure_file(xfreerdp.1.xml.in xfreerdp.1.xml @ONLY IMMEDIATE)
|
||||
|
||||
add_executable(generate_argument_docbook generate_argument_docbook.c)
|
||||
|
||||
set(GAD_LIBS freerdp-client)
|
||||
target_link_libraries(generate_argument_docbook ${GAD_LIBS} freerdp winpr)
|
||||
# Compile the helper tool with default compiler settings.
|
||||
# We need the include paths though.
|
||||
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
|
||||
set(GENERATE_INCLUDES "")
|
||||
foreach(dir ${dirs})
|
||||
set(GENERATE_INCLUDES ${GENERATE_INCLUDES} -I${dir})
|
||||
endforeach(dir)
|
||||
|
||||
add_custom_command(OUTPUT xfreerdp.1
|
||||
COMMAND generate_argument_docbook
|
||||
COMMAND ${CMAKE_C_COMPILER} ${GENERATE_INCLUDES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/generate_argument_docbook.c
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/generate_argument_docbook
|
||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/generate_argument_docbook
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
@ -101,12 +111,11 @@ if(WITH_MANPAGES)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-envvar.1.xml ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND ${XSLTPROC_EXECUTABLE} ${DOCBOOKXSL_DIR}/manpages/docbook.xsl xfreerdp.1.xml
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/xfreerdp.1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-examples.1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-envvar.1.xml
|
||||
generate_argument_docbook)
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/xfreerdp.1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-examples.1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-envvar.1.xml)
|
||||
|
||||
add_custom_target(xfreerdp.manpage ALL
|
||||
DEPENDS xfreerdp.1)
|
||||
@ -145,6 +154,10 @@ set(XRENDER_FEATURE_TYPE "RECOMMENDED")
|
||||
set(XRENDER_FEATURE_PURPOSE "rendering")
|
||||
set(XRENDER_FEATURE_DESCRIPTION "X11 render extension")
|
||||
|
||||
set(XRANDR_FEATURE_TYPE "RECOMMENDED")
|
||||
set(XRANDR_FEATURE_PURPOSE "tracking output configuration")
|
||||
set(XRANDR_FEATURE_DESCRIPTION "X11 randr extension")
|
||||
|
||||
set(XFIXES_FEATURE_TYPE "RECOMMENDED")
|
||||
set(XFIXES_FEATURE_PURPOSE "X11 xfixes extension")
|
||||
set(XFIXES_FEATURE_DESCRIPTION "Useful additions to the X11 core protocol")
|
||||
@ -156,6 +169,7 @@ find_feature(Xcursor ${XCURSOR_FEATURE_TYPE} ${XCURSOR_FEATURE_PURPOSE} ${XCURSO
|
||||
find_feature(Xv ${XV_FEATURE_TYPE} ${XV_FEATURE_PURPOSE} ${XV_FEATURE_DESCRIPTION})
|
||||
find_feature(Xi ${XI_FEATURE_TYPE} ${XI_FEATURE_PURPOSE} ${XI_FEATURE_DESCRIPTION})
|
||||
find_feature(Xrender ${XRENDER_FEATURE_TYPE} ${XRENDER_FEATURE_PURPOSE} ${XRENDER_FEATURE_DESCRIPTION})
|
||||
find_feature(XRandR ${XRANDR_FEATURE_TYPE} ${XRANDR_FEATURE_PURPOSE} ${XRANDR_FEATURE_DESCRIPTION})
|
||||
find_feature(Xfixes ${XFIXES_FEATURE_TYPE} ${XFIXES_FEATURE_PURPOSE} ${XFIXES_FEATURE_DESCRIPTION})
|
||||
|
||||
if(WITH_XINERAMA)
|
||||
@ -194,6 +208,12 @@ if(WITH_XRENDER)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XRENDER_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WITH_XRANDR)
|
||||
add_definitions(-DWITH_XRANDR)
|
||||
include_directories(${XRANDR_INCLUDE_DIRS})
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XRANDR_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WITH_XFIXES)
|
||||
add_definitions(-DWITH_XFIXES)
|
||||
include_directories(${XFIXES_INCLUDE_DIRS})
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/cmdline.h>
|
||||
#include "../common/cmdline.h"
|
||||
|
||||
/* We need to include the command line c file to get access to
|
||||
* the argument struct. */
|
||||
#include "../common/cmdline.c"
|
||||
|
||||
LPSTR tr_esc_str(LPCSTR arg)
|
||||
#define TAG FREERDP_TAG("generate_argument_docbook")
|
||||
LPSTR tr_esc_str(LPCSTR arg, bool format)
|
||||
{
|
||||
LPSTR tmp = NULL;
|
||||
size_t cs = 0, x, ds;
|
||||
size_t cs = 0, x, ds, len;
|
||||
size_t s;
|
||||
if(NULL == arg)
|
||||
return NULL;
|
||||
@ -26,7 +23,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not allocate string buffer.");
|
||||
fprintf(stderr, "Could not allocate string buffer.\n");
|
||||
exit(-2);
|
||||
}
|
||||
/* Copy character for character and check, if it is necessary to escape. */
|
||||
@ -36,37 +33,41 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
switch(arg[x])
|
||||
{
|
||||
case '<':
|
||||
ds += 3;
|
||||
len = format ? 13 : 4;
|
||||
ds += len - 1;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not reallocate string buffer.");
|
||||
fprintf(stderr, "Could not reallocate string buffer.\n");
|
||||
exit(-3);
|
||||
}
|
||||
tmp[cs++] = '&';
|
||||
tmp[cs++] = 'l';
|
||||
tmp[cs++] = 't';
|
||||
tmp[cs++] = ';';
|
||||
if (format)
|
||||
strncpy (&tmp[cs], "<replaceable>", len);
|
||||
else
|
||||
strncpy (&tmp[cs], "<", len);
|
||||
cs += len;
|
||||
break;
|
||||
case '>':
|
||||
ds += 3;
|
||||
len = format ? 14 : 4;
|
||||
ds += len - 1;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not reallocate string buffer.");
|
||||
fprintf(stderr, "Could not reallocate string buffer.\n");
|
||||
exit(-4);
|
||||
}
|
||||
tmp[cs++] = '&';
|
||||
tmp[cs++] = 'g';
|
||||
tmp[cs++] = 't';
|
||||
tmp[cs++] = ';';
|
||||
if (format)
|
||||
strncpy (&tmp[cs], "</replaceable>", len);
|
||||
else
|
||||
strncpy (&tmp[cs], "<", len);
|
||||
cs += len;
|
||||
break;
|
||||
case '\'':
|
||||
ds += 5;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not reallocate string buffer.");
|
||||
fprintf(stderr, "Could not reallocate string buffer.\n");
|
||||
exit(-5);
|
||||
}
|
||||
tmp[cs++] = '&';
|
||||
@ -81,7 +82,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not reallocate string buffer.");
|
||||
fprintf(stderr, "Could not reallocate string buffer.\n");
|
||||
exit(-6);
|
||||
}
|
||||
tmp[cs++] = '&';
|
||||
@ -96,7 +97,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not reallocate string buffer.");
|
||||
fprintf(stderr, "Could not reallocate string buffer.\n");
|
||||
exit(-7);
|
||||
}
|
||||
tmp[cs++] = '&';
|
||||
@ -125,7 +126,7 @@ int main(int argc, char *argv[])
|
||||
fp = fopen(fname, "w");
|
||||
if(NULL == fp)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not open '%s' for writing.", fname);
|
||||
fprintf(stderr, "Could not open '%s' for writing.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
/* The tag used as header in the manpage */
|
||||
@ -136,39 +137,71 @@ int main(int argc, char *argv[])
|
||||
* compatible XML */
|
||||
if(elements < 2)
|
||||
{
|
||||
WLog_ERR(TAG, "The argument array 'args' is empty, writing an empty file.");
|
||||
fprintf(stderr, "The argument array 'args' is empty, writing an empty file.\n");
|
||||
elements = 1;
|
||||
}
|
||||
for(x=0; x<elements - 1; x++)
|
||||
{
|
||||
const COMMAND_LINE_ARGUMENT_A *arg = &args[x];
|
||||
const char *name = tr_esc_str((LPSTR) arg->Name);
|
||||
const char *format = tr_esc_str(arg->Format);
|
||||
const char *text = tr_esc_str((LPSTR) arg->Text);
|
||||
char *name = tr_esc_str((LPSTR) arg->Name, FALSE);
|
||||
char *alias = tr_esc_str((LPSTR) arg->Alias, FALSE);
|
||||
char *format = tr_esc_str(arg->Format, TRUE);
|
||||
char *text = tr_esc_str((LPSTR) arg->Text, FALSE);
|
||||
|
||||
fprintf(fp, "\t\t\t<varlistentry>\n");
|
||||
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option>", name);
|
||||
if ((arg->Flags == COMMAND_LINE_VALUE_REQUIRED) && format)
|
||||
fprintf(fp, " <replaceable>%s</replaceable>\n", format);
|
||||
fprintf(fp, "</term>\n");
|
||||
do
|
||||
{
|
||||
fprintf(fp, "\t\t\t\t<term><option>");
|
||||
if (arg->Flags == COMMAND_LINE_VALUE_BOOL)
|
||||
fprintf(fp, "%s", arg->Default ? "-" : "+");
|
||||
else
|
||||
fprintf(fp, "/");
|
||||
fprintf(fp, "%s</option>", name);
|
||||
|
||||
if (format || text)
|
||||
if (format)
|
||||
{
|
||||
if (arg->Flags == COMMAND_LINE_VALUE_OPTIONAL)
|
||||
fprintf(fp, "[");
|
||||
fprintf(fp, ":%s", format);
|
||||
if (arg->Flags == COMMAND_LINE_VALUE_OPTIONAL)
|
||||
fprintf(fp, "]");
|
||||
}
|
||||
|
||||
fprintf(fp, "</term>\n");
|
||||
|
||||
if (alias == name)
|
||||
break;
|
||||
|
||||
free (name);
|
||||
name = alias;
|
||||
}
|
||||
while (alias);
|
||||
|
||||
if (text)
|
||||
{
|
||||
fprintf(fp, "\t\t\t\t<listitem>\n");
|
||||
fprintf(fp, "\t\t\t\t\t<para>%s\n", format ? format : "");
|
||||
fprintf(fp, "\t\t\t\t\t<para>");
|
||||
|
||||
if (text)
|
||||
{
|
||||
if (format)
|
||||
fprintf(fp, " - ");
|
||||
fprintf(fp, "%s", text);
|
||||
|
||||
if (arg->Flags == COMMAND_LINE_VALUE_BOOL)
|
||||
fprintf(fp, " (default:%s)", arg->Default ? "on" : "off");
|
||||
else if (arg->Default)
|
||||
{
|
||||
char *value = tr_esc_str((LPSTR) arg->Default, FALSE);
|
||||
fprintf(fp, " (default:%s)", value);
|
||||
free (value);
|
||||
}
|
||||
|
||||
fprintf(fp, "</para>\n");
|
||||
fprintf(fp, "\t\t\t\t</listitem>\n");
|
||||
}
|
||||
fprintf(fp, "\t\t\t</varlistentry>\n");
|
||||
free((void*) name);
|
||||
free((void*) format);
|
||||
free((void*) text);
|
||||
free(name);
|
||||
free(format);
|
||||
free(text);
|
||||
}
|
||||
fprintf(fp, "\t\t</variablelist>\n");
|
||||
fprintf(fp, "\t</refsect1>\n");
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <freerdp/gdi/video.h>
|
||||
#include "xf_channels.h"
|
||||
|
||||
#include "xf_client.h"
|
||||
@ -30,11 +31,13 @@
|
||||
#include "xf_tsmf.h"
|
||||
#include "xf_rail.h"
|
||||
#include "xf_cliprdr.h"
|
||||
#include "xf_disp.h"
|
||||
#include "xf_video.h"
|
||||
|
||||
void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e)
|
||||
void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@ -47,7 +50,7 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
gdi_graphics_pipeline_init(xfc->context.gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
else
|
||||
xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
@ -63,12 +66,31 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven
|
||||
{
|
||||
xf_encomsp_init(xfc, (EncomspClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_disp_init(xfc, (DispClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
gdi_video_geometry_init(xfc->context.gdi, (GeometryClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_video_control_init(xfc->context.gdi, (VideoClientContext*)e->pInterface);
|
||||
else
|
||||
xf_video_control_init(xfc, (VideoClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
gdi_video_data_init(xfc->context.gdi, (VideoClientContext*)e->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e)
|
||||
void xf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
@ -81,7 +103,7 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
gdi_graphics_pipeline_uninit(xfc->context.gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
else
|
||||
xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
@ -97,4 +119,19 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect
|
||||
{
|
||||
xf_encomsp_uninit(xfc, (EncomspClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
gdi_video_geometry_uninit(xfc->context.gdi, (GeometryClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_video_control_uninit(xfc->context.gdi, (VideoClientContext*)e->pInterface);
|
||||
else
|
||||
xf_video_control_uninit(xfc, (VideoClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
gdi_video_data_uninit(xfc->context.gdi, (VideoClientContext*)e->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,11 +28,14 @@
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/client/encomsp.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
#include <freerdp/client/geometry.h>
|
||||
#include <freerdp/client/video.h>
|
||||
|
||||
int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface);
|
||||
int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface);
|
||||
|
||||
void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e);
|
||||
void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e);
|
||||
void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e);
|
||||
void xf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_CHANNELS_H */
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#ifdef WITH_XRENDER
|
||||
#include <X11/extensions/Xrender.h>
|
||||
@ -86,6 +87,7 @@
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <X11/XKBlib.h>
|
||||
|
||||
#include "xf_gdi.h"
|
||||
@ -94,6 +96,8 @@
|
||||
#include "xf_event.h"
|
||||
#include "xf_input.h"
|
||||
#include "xf_cliprdr.h"
|
||||
#include "xf_disp.h"
|
||||
#include "xf_video.h"
|
||||
#include "xf_monitor.h"
|
||||
#include "xf_graphics.h"
|
||||
#include "xf_keyboard.h"
|
||||
@ -222,8 +226,7 @@ void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h)
|
||||
}
|
||||
|
||||
#endif
|
||||
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h,
|
||||
x, y);
|
||||
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
|
||||
}
|
||||
|
||||
static BOOL xf_desktop_resize(rdpContext* context)
|
||||
@ -259,8 +262,7 @@ static BOOL xf_desktop_resize(rdpContext* context)
|
||||
|
||||
if (!xfc->fullscreen)
|
||||
{
|
||||
xf_ResizeDesktopWindow(xfc, xfc->window, settings->DesktopWidth,
|
||||
settings->DesktopHeight);
|
||||
xf_ResizeDesktopWindow(xfc, xfc->window, settings->DesktopWidth, settings->DesktopHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -287,9 +289,6 @@ static BOOL xf_desktop_resize(rdpContext* context)
|
||||
|
||||
static BOOL xf_sw_begin_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
gdi->primary->hdc->hwnd->ninvalid = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -302,6 +301,10 @@ static BOOL xf_sw_end_paint(rdpContext* context)
|
||||
HGDI_RGN cinvalid;
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
if (gdi->suppressOutput)
|
||||
return TRUE;
|
||||
|
||||
x = gdi->primary->hdc->hwnd->invalid->x;
|
||||
y = gdi->primary->hdc->hwnd->invalid->y;
|
||||
w = gdi->primary->hdc->hwnd->invalid->w;
|
||||
@ -354,6 +357,8 @@ static BOOL xf_sw_end_paint(rdpContext* context)
|
||||
xf_unlock_x11(xfc, FALSE);
|
||||
}
|
||||
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
gdi->primary->hdc->hwnd->ninvalid = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -381,6 +386,8 @@ static BOOL xf_sw_desktop_resize(rdpContext* context)
|
||||
goto out;
|
||||
}
|
||||
|
||||
xfc->image->byte_order = LSBFirst;
|
||||
xfc->image->bitmap_bit_order = LSBFirst;
|
||||
ret = xf_desktop_resize(context);
|
||||
out:
|
||||
xf_unlock_x11(xfc, TRUE);
|
||||
@ -389,9 +396,6 @@ out:
|
||||
|
||||
static BOOL xf_hw_begin_paint(rdpContext* context)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
xfc->hdc->hwnd->invalid->null = TRUE;
|
||||
xfc->hdc->hwnd->ninvalid = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -401,6 +405,9 @@ static BOOL xf_hw_end_paint(rdpContext* context)
|
||||
UINT32 w, h;
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
|
||||
if (xfc->context.gdi->suppressOutput)
|
||||
return TRUE;
|
||||
|
||||
if (!xfc->remote_app)
|
||||
{
|
||||
if (!xfc->complex_regions)
|
||||
@ -456,6 +463,8 @@ static BOOL xf_hw_end_paint(rdpContext* context)
|
||||
xf_unlock_x11(xfc, FALSE);
|
||||
}
|
||||
|
||||
xfc->hdc->hwnd->invalid->null = TRUE;
|
||||
xfc->hdc->hwnd->ninvalid = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -628,6 +637,8 @@ BOOL xf_create_window(xfContext* xfc)
|
||||
ZPixmap, 0, (char*) gdi->primary_buffer,
|
||||
settings->DesktopWidth, settings->DesktopHeight,
|
||||
xfc->scanline_pad, gdi->stride);
|
||||
xfc->image->byte_order = LSBFirst;
|
||||
xfc->image->bitmap_bit_order = LSBFirst;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -635,12 +646,6 @@ BOOL xf_create_window(xfContext* xfc)
|
||||
|
||||
static void xf_window_free(xfContext* xfc)
|
||||
{
|
||||
if (xfc->gc_mono)
|
||||
{
|
||||
XFreeGC(xfc->display, xfc->gc_mono);
|
||||
xfc->gc_mono = 0;
|
||||
}
|
||||
|
||||
if (xfc->window)
|
||||
{
|
||||
xf_DestroyDesktopWindow(xfc, xfc->window);
|
||||
@ -672,6 +677,12 @@ static void xf_window_free(xfContext* xfc)
|
||||
xfc->bitmap_mono = 0;
|
||||
}
|
||||
|
||||
if (xfc->gc_mono)
|
||||
{
|
||||
XFreeGC(xfc->display, xfc->gc_mono);
|
||||
xfc->gc_mono = 0;
|
||||
}
|
||||
|
||||
if (xfc->primary)
|
||||
{
|
||||
XFreePixmap(xfc->display, xfc->primary);
|
||||
@ -772,15 +783,6 @@ void xf_unlock_x11(xfContext* xfc, BOOL display)
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_calculate_color_shifts(UINT32 mask, UINT8* rsh, UINT8* lsh)
|
||||
{
|
||||
for (*lsh = 0; !(mask & 1); mask >>= 1)
|
||||
(*lsh)++;
|
||||
|
||||
for (*rsh = 8; mask; mask >>= 1)
|
||||
(*rsh)--;
|
||||
}
|
||||
|
||||
static BOOL xf_get_pixmap_info(xfContext* xfc)
|
||||
{
|
||||
int i;
|
||||
@ -849,20 +851,13 @@ static BOOL xf_get_pixmap_info(xfContext* xfc)
|
||||
if (xfc->visual)
|
||||
{
|
||||
/*
|
||||
* Detect if the server visual has an inverted colormap
|
||||
* (BGR vs RGB, or red being the least significant byte)
|
||||
*/
|
||||
* Detect if the server visual has an inverted colormap
|
||||
* (BGR vs RGB, or red being the least significant byte)
|
||||
*/
|
||||
if (vi->red_mask & 0xFF)
|
||||
{
|
||||
xfc->invert = TRUE;
|
||||
xfc->invert = FALSE;
|
||||
}
|
||||
|
||||
/* calculate color shifts required for rdp order color conversion */
|
||||
xf_calculate_color_shifts(vi->red_mask, &xfc->red_shift_r, &xfc->red_shift_l);
|
||||
xf_calculate_color_shifts(vi->green_mask, &xfc->green_shift_r,
|
||||
&xfc->green_shift_l);
|
||||
xf_calculate_color_shifts(vi->blue_mask, &xfc->blue_shift_r,
|
||||
&xfc->blue_shift_l);
|
||||
}
|
||||
|
||||
XFree(vis);
|
||||
@ -1124,9 +1119,9 @@ static BOOL xf_pre_connect(freerdp* instance)
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
||||
PubSub_SubscribeChannelConnected(instance->context->pubSub,
|
||||
(pChannelConnectedEventHandler) xf_OnChannelConnectedEventHandler);
|
||||
xf_OnChannelConnectedEventHandler);
|
||||
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
|
||||
(pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler);
|
||||
xf_OnChannelDisconnectedEventHandler);
|
||||
|
||||
if (!freerdp_client_load_addins(channels, instance->settings))
|
||||
return FALSE;
|
||||
@ -1278,15 +1273,19 @@ static BOOL xf_post_connect(freerdp* instance)
|
||||
update->SetKeyboardIndicators = xf_keyboard_set_indicators;
|
||||
update->SetKeyboardImeStatus = xf_keyboard_set_ime_status;
|
||||
|
||||
|
||||
if (!(xfc->clipboard = xf_clipboard_new(xfc)))
|
||||
return FALSE;
|
||||
|
||||
if (!(xfc->xfDisp = xf_disp_new(xfc)))
|
||||
{
|
||||
xf_clipboard_free(xfc->clipboard);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EventArgsInit(&e, "xfreerdp");
|
||||
e.width = settings->DesktopWidth;
|
||||
e.height = settings->DesktopHeight;
|
||||
PubSub_OnResizeWindow(context->pubSub, xfc, &e);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -1308,6 +1307,17 @@ static void xf_post_disconnect(freerdp* instance)
|
||||
xfc->clipboard = NULL;
|
||||
}
|
||||
|
||||
if (xfc->xfDisp)
|
||||
{
|
||||
xf_disp_free(xfc->xfDisp);
|
||||
xfc->xfDisp = NULL;
|
||||
}
|
||||
|
||||
if ((xfc->window != NULL) && (xfc->drawable == xfc->window->handle))
|
||||
xfc->drawable = 0;
|
||||
else
|
||||
xf_DestroyDummyWindow(xfc, xfc->drawable);
|
||||
|
||||
xf_window_free(xfc);
|
||||
xf_keyboard_free(xfc);
|
||||
}
|
||||
@ -1315,15 +1325,14 @@ static void xf_post_disconnect(freerdp* instance)
|
||||
static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) instance->context;
|
||||
const char *str_data = freerdp_get_logon_error_info_data(data);
|
||||
const char *str_type = freerdp_get_logon_error_info_type(type);
|
||||
const char* str_data = freerdp_get_logon_error_info_data(data);
|
||||
const char* str_type = freerdp_get_logon_error_info_type(type);
|
||||
WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
|
||||
|
||||
xf_rail_disable_remoteapp_mode(xfc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void* xf_input_thread(void* arg)
|
||||
static DWORD WINAPI xf_input_thread(LPVOID arg)
|
||||
{
|
||||
BOOL running = TRUE;
|
||||
DWORD status;
|
||||
@ -1402,7 +1411,7 @@ static void* xf_input_thread(void* arg)
|
||||
|
||||
MessageQueue_PostQuit(queue, 0);
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL xf_auto_reconnect(freerdp* instance)
|
||||
@ -1454,10 +1463,10 @@ static BOOL xf_auto_reconnect(freerdp* instance)
|
||||
* @param instance - pointer to the rdp_freerdp structure that contains the session's settings
|
||||
* @return A code from the enum XF_EXIT_CODE (0 if successful)
|
||||
*/
|
||||
static void* xf_client_thread(void* param)
|
||||
static DWORD WINAPI xf_client_thread(LPVOID param)
|
||||
{
|
||||
BOOL status;
|
||||
int exit_code;
|
||||
DWORD exit_code = 0;
|
||||
DWORD nCount;
|
||||
DWORD waitStatus;
|
||||
HANDLE handles[64];
|
||||
@ -1466,29 +1475,34 @@ static void* xf_client_thread(void* param)
|
||||
rdpContext* context;
|
||||
HANDLE inputEvent = NULL;
|
||||
HANDLE inputThread = NULL;
|
||||
HANDLE timer = NULL;
|
||||
LARGE_INTEGER due;
|
||||
rdpSettings* settings;
|
||||
exit_code = 0;
|
||||
TimerEventArgs timerEvent;
|
||||
EventArgsInit(&timerEvent, "xfreerdp");
|
||||
instance = (freerdp*) param;
|
||||
context = instance->context;
|
||||
status = freerdp_connect(instance);
|
||||
xfc = (xfContext*) instance->context;
|
||||
|
||||
if (!status)
|
||||
{
|
||||
if (freerdp_get_last_error(instance->context) ==
|
||||
FREERDP_ERROR_AUTHENTICATION_FAILED)
|
||||
exit_code = XF_EXIT_AUTH_FAILURE;
|
||||
else
|
||||
exit_code = XF_EXIT_CONN_FAILED;
|
||||
}
|
||||
else
|
||||
exit_code = XF_EXIT_SUCCESS;
|
||||
|
||||
if (!status)
|
||||
goto end;
|
||||
|
||||
/* --authonly ? */
|
||||
if (instance->settings->AuthenticationOnly)
|
||||
{
|
||||
WLog_ERR(TAG, "Authentication only, exit status %"PRId32"", !status);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
if (freerdp_get_last_error(instance->context) ==
|
||||
FREERDP_ERROR_AUTHENTICATION_FAILED)
|
||||
exit_code = XF_EXIT_AUTH_FAILURE;
|
||||
else
|
||||
exit_code = XF_EXIT_CONN_FAILED;
|
||||
}
|
||||
else
|
||||
exit_code = XF_EXIT_SUCCESS;
|
||||
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
@ -1507,16 +1521,31 @@ static void* xf_client_thread(void* param)
|
||||
}
|
||||
|
||||
settings = context->settings;
|
||||
timer = CreateWaitableTimerA(NULL, FALSE, "mainloop-periodic-timer");
|
||||
|
||||
if (!timer)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to create timer");
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
due.QuadPart = 0;
|
||||
|
||||
if (!SetWaitableTimer(timer, &due, 20, NULL, NULL, FALSE))
|
||||
{
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
handles[0] = timer;
|
||||
|
||||
if (!settings->AsyncInput)
|
||||
{
|
||||
inputEvent = xfc->x11event;
|
||||
handles[0] = inputEvent;
|
||||
handles[1] = inputEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(inputThread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) xf_input_thread, instance, 0, NULL)))
|
||||
if (!(inputThread = CreateThread(NULL, 0, xf_input_thread, instance, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "async input: failed to create input thread");
|
||||
exit_code = XF_EXIT_UNKNOWN;
|
||||
@ -1527,17 +1556,17 @@ static void* xf_client_thread(void* param)
|
||||
while (!freerdp_shall_disconnect(instance))
|
||||
{
|
||||
/*
|
||||
* win8 and server 2k12 seem to have some timing issue/race condition
|
||||
* when a initial sync request is send to sync the keyboard indicators
|
||||
* sending the sync event twice fixed this problem
|
||||
*/
|
||||
* win8 and server 2k12 seem to have some timing issue/race condition
|
||||
* when a initial sync request is send to sync the keyboard indicators
|
||||
* sending the sync event twice fixed this problem
|
||||
*/
|
||||
if (freerdp_focus_required(instance))
|
||||
{
|
||||
xf_keyboard_focus_in(xfc);
|
||||
xf_keyboard_focus_in(xfc);
|
||||
}
|
||||
|
||||
nCount = (settings->AsyncInput) ? 0 : 1;
|
||||
nCount = (settings->AsyncInput) ? 1 : 2;
|
||||
|
||||
if (!settings->AsyncTransport)
|
||||
{
|
||||
@ -1552,7 +1581,7 @@ static void* xf_client_thread(void* param)
|
||||
nCount += tmp;
|
||||
}
|
||||
|
||||
waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, 100);
|
||||
waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
|
||||
|
||||
if (waitStatus == WAIT_FAILED)
|
||||
break;
|
||||
@ -1564,7 +1593,9 @@ static void* xf_client_thread(void* param)
|
||||
if (xf_auto_reconnect(instance))
|
||||
continue;
|
||||
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1577,6 +1608,12 @@ static void* xf_client_thread(void* param)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((status != WAIT_TIMEOUT) && (waitStatus == WAIT_OBJECT_0))
|
||||
{
|
||||
timerEvent.now = GetTickCount64();
|
||||
PubSub_OnTimer(context->pubSub, context, &timerEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings->AsyncInput)
|
||||
@ -1589,9 +1626,14 @@ static void* xf_client_thread(void* param)
|
||||
exit_code = freerdp_error_info(instance);
|
||||
|
||||
disconnect:
|
||||
|
||||
if (timer)
|
||||
CloseHandle(timer);
|
||||
|
||||
freerdp_disconnect(instance);
|
||||
end:
|
||||
ExitThread(exit_code);
|
||||
return NULL;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
DWORD xf_exit_code_from_disconnect_reason(DWORD reason)
|
||||
@ -1612,17 +1654,18 @@ DWORD xf_exit_code_from_disconnect_reason(DWORD reason)
|
||||
return reason;
|
||||
}
|
||||
|
||||
static void xf_TerminateEventHandler(rdpContext* context, TerminateEventArgs* e)
|
||||
static void xf_TerminateEventHandler(void* context, TerminateEventArgs* e)
|
||||
{
|
||||
freerdp_abort_connect(context->instance);
|
||||
rdpContext* ctx = (rdpContext*)context;
|
||||
freerdp_abort_connect(ctx->instance);
|
||||
}
|
||||
|
||||
#ifdef WITH_XRENDER
|
||||
static void xf_ZoomingChangeEventHandler(rdpContext* context,
|
||||
static void xf_ZoomingChangeEventHandler(void* context,
|
||||
ZoomingChangeEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
int w = xfc->scaledWidth + e->dx;
|
||||
int h = xfc->scaledHeight + e->dy;
|
||||
|
||||
@ -1643,11 +1686,11 @@ static void xf_ZoomingChangeEventHandler(rdpContext* context,
|
||||
xf_draw_screen(xfc, 0, 0, settings->DesktopWidth, settings->DesktopHeight);
|
||||
}
|
||||
|
||||
static void xf_PanningChangeEventHandler(rdpContext* context,
|
||||
static void xf_PanningChangeEventHandler(void* context,
|
||||
PanningChangeEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
|
||||
if (e->dx == 0 && e->dy == 0)
|
||||
return;
|
||||
@ -1688,8 +1731,7 @@ static int xfreerdp_client_start(rdpContext* context)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(xfc->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) xf_client_thread,
|
||||
if (!(xfc->thread = CreateThread(NULL, 0, xf_client_thread,
|
||||
context->instance, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to create client thread");
|
||||
@ -1714,6 +1756,19 @@ static int xfreerdp_client_stop(rdpContext* context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Atom get_supported_atom(xfContext* xfc, const char* atomName)
|
||||
{
|
||||
unsigned long i;
|
||||
const Atom atom = XInternAtom(xfc->display, atomName, False);
|
||||
|
||||
for (i = 0; i < xfc->supportedAtomCount; i++)
|
||||
{
|
||||
if (xfc->supportedAtoms[i] == atom)
|
||||
return atom;
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) instance->context;
|
||||
@ -1731,12 +1786,12 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
instance->VerifyChangedCertificate = client_cli_verify_changed_certificate;
|
||||
instance->LogonErrorInfo = xf_logon_error_info;
|
||||
PubSub_SubscribeTerminate(context->pubSub,
|
||||
(pTerminateEventHandler) xf_TerminateEventHandler);
|
||||
xf_TerminateEventHandler);
|
||||
#ifdef WITH_XRENDER
|
||||
PubSub_SubscribeZoomingChange(context->pubSub,
|
||||
(pZoomingChangeEventHandler) xf_ZoomingChangeEventHandler);
|
||||
xf_ZoomingChangeEventHandler);
|
||||
PubSub_SubscribePanningChange(context->pubSub,
|
||||
(pPanningChangeEventHandler) xf_PanningChangeEventHandler);
|
||||
xf_PanningChangeEventHandler);
|
||||
#endif
|
||||
xfc->UseXThreads = TRUE;
|
||||
//xfc->debug = TRUE;
|
||||
@ -1768,20 +1823,49 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
goto fail_create_mutex;
|
||||
}
|
||||
|
||||
xfc->xfds = ConnectionNumber(xfc->display);
|
||||
xfc->screen_number = DefaultScreen(xfc->display);
|
||||
xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number);
|
||||
xfc->depth = DefaultDepthOfScreen(xfc->screen);
|
||||
xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst);
|
||||
xfc->invert = TRUE;
|
||||
xfc->complex_regions = TRUE;
|
||||
xfc->_NET_SUPPORTED = XInternAtom(xfc->display, "_NET_SUPPORTED", True);
|
||||
xfc->_NET_SUPPORTING_WM_CHECK = XInternAtom(xfc->display, "_NET_SUPPORTING_WM_CHECK", True);
|
||||
|
||||
if ((xfc->_NET_SUPPORTED != None) && (xfc->_NET_SUPPORTING_WM_CHECK != None))
|
||||
{
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, after;
|
||||
unsigned char* data = NULL;
|
||||
int status = XGetWindowProperty(xfc->display, RootWindowOfScreen(xfc->screen),
|
||||
xfc->_NET_SUPPORTED, 0, 1024, False, XA_ATOM,
|
||||
&actual_type, &actual_format, &nitems, &after, &data);
|
||||
|
||||
if ((status == Success) && (actual_type == XA_ATOM) && (actual_format == 32))
|
||||
{
|
||||
xfc->supportedAtomCount = nitems;
|
||||
xfc->supportedAtoms = calloc(nitems, sizeof(Atom));
|
||||
memcpy(xfc->supportedAtoms, data, nitems * sizeof(Atom));
|
||||
}
|
||||
|
||||
if (data)
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
xfc->_NET_WM_ICON = XInternAtom(xfc->display, "_NET_WM_ICON", False);
|
||||
xfc->_MOTIF_WM_HINTS = XInternAtom(xfc->display, "_MOTIF_WM_HINTS", False);
|
||||
xfc->_NET_CURRENT_DESKTOP = XInternAtom(xfc->display, "_NET_CURRENT_DESKTOP",
|
||||
False);
|
||||
xfc->_NET_WORKAREA = XInternAtom(xfc->display, "_NET_WORKAREA", False);
|
||||
xfc->_NET_WM_STATE = XInternAtom(xfc->display, "_NET_WM_STATE", False);
|
||||
xfc->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfc->display,
|
||||
"_NET_WM_STATE_FULLSCREEN", False);
|
||||
xfc->_NET_WM_STATE = get_supported_atom(xfc, "_NET_WM_STATE");
|
||||
xfc->_NET_WM_STATE_FULLSCREEN = get_supported_atom(xfc, "_NET_WM_STATE_FULLSCREEN");
|
||||
xfc->_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(xfc->display,
|
||||
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
||||
xfc->_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(xfc->display,
|
||||
"_NET_WM_STATE_MAXIMIZED_VERT", False);
|
||||
xfc->_NET_WM_FULLSCREEN_MONITORS = XInternAtom(xfc->display,
|
||||
"_NET_WM_FULLSCREEN_MONITORS", False);
|
||||
xfc->_NET_WM_FULLSCREEN_MONITORS = get_supported_atom(xfc, "_NET_WM_FULLSCREEN_MONITORS");
|
||||
xfc->_NET_WM_NAME = XInternAtom(xfc->display, "_NET_WM_NAME", False);
|
||||
xfc->_NET_WM_PID = XInternAtom(xfc->display, "_NET_WM_PID", False);
|
||||
xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE",
|
||||
@ -1808,13 +1892,6 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False);
|
||||
xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False);
|
||||
xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
|
||||
xfc->xfds = ConnectionNumber(xfc->display);
|
||||
xfc->screen_number = DefaultScreen(xfc->display);
|
||||
xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number);
|
||||
xfc->depth = DefaultDepthOfScreen(xfc->screen);
|
||||
xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst);
|
||||
xfc->invert = (ImageByteOrder(xfc->display) == MSBFirst) ? FALSE : TRUE;
|
||||
xfc->complex_regions = TRUE;
|
||||
xfc->x11event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds,
|
||||
WINPR_FD_READ);
|
||||
|
||||
@ -1891,6 +1968,8 @@ static void xfreerdp_client_free(freerdp* instance, rdpContext* context)
|
||||
free(xfc->vscreen.monitors);
|
||||
xfc->vscreen.monitors = NULL;
|
||||
}
|
||||
|
||||
free(xfc->supportedAtoms);
|
||||
}
|
||||
|
||||
int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
|
||||
|
||||
@ -320,7 +320,10 @@ static wStream* xf_cliprdr_serialize_server_format_list(xfClipboard* clipboard)
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(s, format->formatId);
|
||||
Stream_Write(s, format->formatName, name_length);
|
||||
|
||||
if (format->formatName)
|
||||
Stream_Write(s, format->formatName, name_length);
|
||||
|
||||
Stream_Write_UINT8(s, '\0');
|
||||
}
|
||||
|
||||
@ -436,7 +439,8 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard,
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"failed to retrieve raw format list: data=%p, length=%lu, format=%d, type=%lu (expected=%lu)",
|
||||
(void*) data, length, format, (unsigned long) type, (unsigned long) clipboard->raw_format_list_atom);
|
||||
(void*) data, length, format, (unsigned long) type,
|
||||
(unsigned long) clipboard->raw_format_list_atom);
|
||||
}
|
||||
|
||||
if (data)
|
||||
@ -630,15 +634,13 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard,
|
||||
* to not process CF_RAW as a file list in case WinPR does not support file transfers.
|
||||
*/
|
||||
if (dstFormatId &&
|
||||
(dstFormatId == ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW")))
|
||||
(dstFormatId == ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW")))
|
||||
{
|
||||
UINT error = NO_ERROR;
|
||||
FILEDESCRIPTOR* file_array = (FILEDESCRIPTOR*) pDstData;
|
||||
UINT32 file_count = DstSize / sizeof(FILEDESCRIPTOR);
|
||||
|
||||
pDstData = NULL;
|
||||
DstSize = 0;
|
||||
|
||||
error = cliprdr_serialize_file_list(file_array, file_count, &pDstData, &DstSize);
|
||||
|
||||
if (error)
|
||||
@ -817,6 +819,7 @@ static void xf_cliprdr_clear_cached_data(xfClipboard* clipboard)
|
||||
free(clipboard->data);
|
||||
clipboard->data = NULL;
|
||||
}
|
||||
|
||||
clipboard->data_length = 0;
|
||||
|
||||
if (clipboard->data_raw)
|
||||
@ -824,6 +827,7 @@ static void xf_cliprdr_clear_cached_data(xfClipboard* clipboard)
|
||||
free(clipboard->data_raw);
|
||||
clipboard->data_raw = NULL;
|
||||
}
|
||||
|
||||
clipboard->data_raw_length = 0;
|
||||
}
|
||||
|
||||
@ -904,7 +908,7 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard,
|
||||
/* We can compare format names by pointer value here as they are both
|
||||
* taken from the same clipboard->serverFormats array */
|
||||
matchingFormat = (formatId == clipboard->data_format_id)
|
||||
&& (formatName == clipboard->data_format_name);
|
||||
&& (formatName == clipboard->data_format_name);
|
||||
|
||||
if (matchingFormat && (clipboard->data != 0) && !rawTransfer)
|
||||
{
|
||||
@ -930,7 +934,6 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard,
|
||||
* Response will be postponed after receiving the data
|
||||
*/
|
||||
xf_cliprdr_clear_cached_data(clipboard);
|
||||
|
||||
respond->xselection.property = xevent->xselectionrequest.property;
|
||||
clipboard->respond = respond;
|
||||
clipboard->data_format_id = formatId;
|
||||
@ -1078,7 +1081,7 @@ static UINT xf_cliprdr_send_client_capabilities(xfClipboard* clipboard)
|
||||
|
||||
if (clipboard->streams_supported && clipboard->file_formats_registered)
|
||||
generalCapabilitySet.generalFlags |=
|
||||
CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS;
|
||||
CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS;
|
||||
|
||||
return clipboard->context->ClientCapabilities(clipboard->context,
|
||||
&capabilities);
|
||||
@ -1180,7 +1183,6 @@ static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context,
|
||||
const CLIPRDR_GENERAL_CAPABILITY_SET* generalCaps;
|
||||
const BYTE* capsPtr = (const BYTE*) capabilities->capabilitySets;
|
||||
xfClipboard* clipboard = (xfClipboard*) context->custom;
|
||||
|
||||
clipboard->streams_supported = FALSE;
|
||||
|
||||
for (i = 0; i < capabilities->cCapabilitiesSets; i++)
|
||||
@ -1211,21 +1213,19 @@ static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context,
|
||||
static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_LIST* formatList)
|
||||
{
|
||||
int i, j;
|
||||
CLIPRDR_FORMAT* format;
|
||||
UINT32 i;
|
||||
int j;
|
||||
xfClipboard* clipboard = (xfClipboard*) context->custom;
|
||||
xfContext* xfc = clipboard->xfc;
|
||||
UINT ret;
|
||||
|
||||
xf_cliprdr_clear_cached_data(clipboard);
|
||||
|
||||
clipboard->data_format_id = -1;
|
||||
clipboard->data_format_name = NULL;
|
||||
|
||||
if (clipboard->serverFormats)
|
||||
{
|
||||
for (i = 0; i < clipboard->numServerFormats; i++)
|
||||
free(clipboard->serverFormats[i].formatName);
|
||||
for (j = 0; j < clipboard->numServerFormats; j++)
|
||||
free(clipboard->serverFormats[j].formatName);
|
||||
|
||||
free(clipboard->serverFormats);
|
||||
clipboard->serverFormats = NULL;
|
||||
@ -1244,7 +1244,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
|
||||
for (i = 0; i < formatList->numFormats; i++)
|
||||
{
|
||||
format = &formatList->formats[i];
|
||||
CLIPRDR_FORMAT* format = &formatList->formats[i];
|
||||
clipboard->serverFormats[i].formatId = format->formatId;
|
||||
|
||||
if (format->formatName)
|
||||
@ -1253,8 +1253,10 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
|
||||
if (!clipboard->serverFormats[i].formatName)
|
||||
{
|
||||
for (--i; i >= 0; --i)
|
||||
free(clipboard->serverFormats[i].formatName);
|
||||
UINT32 k;
|
||||
|
||||
for (k = 0; k < i; k++)
|
||||
free(clipboard->serverFormats[k].formatName);
|
||||
|
||||
clipboard->numServerFormats = 0;
|
||||
free(clipboard->serverFormats);
|
||||
@ -1265,15 +1267,17 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
}
|
||||
|
||||
/* CF_RAW is always implicitly supported by the server */
|
||||
format = &clipboard->serverFormats[formatList->numFormats];
|
||||
format->formatId = CF_RAW;
|
||||
format->formatName = NULL;
|
||||
{
|
||||
CLIPRDR_FORMAT* format = &clipboard->serverFormats[formatList->numFormats];
|
||||
format->formatId = CF_RAW;
|
||||
format->formatName = NULL;
|
||||
}
|
||||
xf_cliprdr_provide_server_format_list(clipboard);
|
||||
clipboard->numTargets = 2;
|
||||
|
||||
for (i = 0; i < formatList->numFormats; i++)
|
||||
{
|
||||
format = &formatList->formats[i];
|
||||
CLIPRDR_FORMAT* format = &formatList->formats[i];
|
||||
|
||||
for (j = 0; j < clipboard->numClientFormats; j++)
|
||||
{
|
||||
@ -1362,7 +1366,6 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext*
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
xf_cliprdr_clear_cached_data(clipboard);
|
||||
|
||||
pDstData = NULL;
|
||||
DstSize = 0;
|
||||
srcFormatId = 0;
|
||||
@ -1430,11 +1433,11 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext*
|
||||
* conversion again on subsequent requests */
|
||||
clipboard->data = pDstData;
|
||||
clipboard->data_length = DstSize;
|
||||
|
||||
/* We have to copy the original data again, as pSrcData is now owned
|
||||
* by clipboard->system. Memory allocation failure is not fatal here
|
||||
* as this is only a cached value. */
|
||||
clipboard->data_raw = (BYTE*) malloc(size);
|
||||
|
||||
if (clipboard->data_raw)
|
||||
{
|
||||
CopyMemory(clipboard->data_raw, data, size);
|
||||
@ -1455,56 +1458,48 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext*
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_server_file_size_request(xfClipboard* clipboard,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wClipboardFileSizeRequest request;
|
||||
|
||||
ZeroMemory(&request, sizeof(request));
|
||||
|
||||
request.streamId = fileContentsRequest->streamId;
|
||||
request.listIndex = fileContentsRequest->listIndex;
|
||||
|
||||
if (fileContentsRequest->cbRequested != sizeof(UINT64))
|
||||
{
|
||||
WLog_WARN(TAG, "unexpected FILECONTENTS_SIZE request: %"PRIu32" bytes",
|
||||
fileContentsRequest->cbRequested);
|
||||
fileContentsRequest->cbRequested);
|
||||
}
|
||||
|
||||
return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request);
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wClipboardFileRangeRequest request;
|
||||
|
||||
ZeroMemory(&request, sizeof(request));
|
||||
|
||||
request.streamId = fileContentsRequest->streamId;
|
||||
request.listIndex = fileContentsRequest->listIndex;
|
||||
request.nPositionLow = fileContentsRequest->nPositionLow;
|
||||
request.nPositionHigh = fileContentsRequest->nPositionHigh;
|
||||
request.cbRequested = fileContentsRequest->cbRequested;
|
||||
|
||||
return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request);
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = fileContentsRequest->streamId;
|
||||
response.dwFlags = fileContentsRequest->dwFlags;
|
||||
|
||||
return context->ClientFileContentsResponse(context, &response);
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
|
||||
CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
UINT error = NO_ERROR;
|
||||
xfClipboard* clipboard = context->custom;
|
||||
@ -1514,10 +1509,9 @@ static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* contex
|
||||
* The FILECONTENTS_SIZE and FILECONTENTS_RANGE flags MUST NOT be set at the same time.
|
||||
*/
|
||||
if ((fileContentsRequest->dwFlags & (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) ==
|
||||
(FILECONTENTS_SIZE | FILECONTENTS_RANGE))
|
||||
(FILECONTENTS_SIZE | FILECONTENTS_RANGE))
|
||||
{
|
||||
WLog_ERR(TAG, "invalid CLIPRDR_FILECONTENTS_REQUEST.dwFlags");
|
||||
|
||||
return xf_cliprdr_send_file_contents_failure(context, fileContentsRequest);
|
||||
}
|
||||
|
||||
@ -1530,7 +1524,6 @@ static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* contex
|
||||
if (error)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to handle CLIPRDR_FILECONTENTS_REQUEST: 0x%08X", error);
|
||||
|
||||
return xf_cliprdr_send_file_contents_failure(context, fileContentsRequest);
|
||||
}
|
||||
|
||||
@ -1538,66 +1531,54 @@ static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* contex
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate,
|
||||
const wClipboardFileSizeRequest* request, UINT64 fileSize)
|
||||
const wClipboardFileSizeRequest* request, UINT64 fileSize)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_SIZE;
|
||||
response.cbRequested = sizeof(UINT64);
|
||||
response.requestedData = (BYTE*) &fileSize;
|
||||
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate,
|
||||
const wClipboardFileSizeRequest* request, UINT errorCode)
|
||||
const wClipboardFileSizeRequest* request, UINT errorCode)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_SIZE;
|
||||
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate,
|
||||
const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size)
|
||||
const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_RANGE;
|
||||
response.cbRequested = size;
|
||||
response.requestedData = (BYTE*) data;
|
||||
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate,
|
||||
const wClipboardFileRangeRequest* request, UINT errorCode)
|
||||
const wClipboardFileRangeRequest* request, UINT errorCode)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_RANGE;
|
||||
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
@ -1631,12 +1612,11 @@ xfClipboard* xf_clipboard_new(xfContext* xfc)
|
||||
clipboard->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE);
|
||||
clipboard->raw_transfer_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_RAW", FALSE);
|
||||
clipboard->raw_format_list_atom =
|
||||
XInternAtom(xfc->display, "_FREERDP_CLIPRDR_FORMATS", FALSE);
|
||||
XInternAtom(xfc->display, "_FREERDP_CLIPRDR_FORMATS", FALSE);
|
||||
xf_cliprdr_set_raw_transfer_enabled(clipboard, TRUE);
|
||||
|
||||
XSelectInput(xfc->display, clipboard->root_window, PropertyChangeMask);
|
||||
|
||||
#ifdef WITH_XFIXES
|
||||
|
||||
if (XFixesQueryExtension(xfc->display, &clipboard->xfixes_event_base,
|
||||
&clipboard->xfixes_error_base))
|
||||
{
|
||||
@ -1662,40 +1642,34 @@ xfClipboard* xf_clipboard_new(xfContext* xfc)
|
||||
WLog_ERR(TAG,
|
||||
"Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!");
|
||||
#endif
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "_FREERDP_RAW", False);
|
||||
clipboard->clientFormats[n].formatId = CF_RAW;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "UTF8_STRING", False);
|
||||
clipboard->clientFormats[n].formatId = CF_UNICODETEXT;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XA_STRING;
|
||||
clipboard->clientFormats[n].formatId = CF_TEXT;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/png", False);
|
||||
clipboard->clientFormats[n].formatId = CB_FORMAT_PNG;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/jpeg", False);
|
||||
clipboard->clientFormats[n].formatId = CB_FORMAT_JPEG;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/gif", False);
|
||||
clipboard->clientFormats[n].formatId = CB_FORMAT_GIF;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/bmp", False);
|
||||
clipboard->clientFormats[n].formatId = CF_DIB;
|
||||
n++;
|
||||
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "text/html", False);
|
||||
clipboard->clientFormats[n].formatId = CB_FORMAT_HTML;
|
||||
clipboard->clientFormats[n].formatName = _strdup("HTML Format");
|
||||
|
||||
if (!clipboard->clientFormats[n].formatName)
|
||||
goto error;
|
||||
|
||||
n++;
|
||||
|
||||
/*
|
||||
@ -1710,8 +1684,10 @@ xfClipboard* xf_clipboard_new(xfContext* xfc)
|
||||
clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "text/uri-list", False);
|
||||
clipboard->clientFormats[n].formatId = CB_FORMAT_TEXTURILIST;
|
||||
clipboard->clientFormats[n].formatName = _strdup("FileGroupDescriptorW");
|
||||
|
||||
if (!clipboard->clientFormats[n].formatName)
|
||||
goto error;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
@ -1720,24 +1696,20 @@ xfClipboard* xf_clipboard_new(xfContext* xfc)
|
||||
clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE);
|
||||
clipboard->numTargets = 2;
|
||||
clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE);
|
||||
|
||||
clipboard->delegate = ClipboardGetDelegate(clipboard->system);
|
||||
clipboard->delegate->custom = clipboard;
|
||||
clipboard->delegate->ClipboardFileSizeSuccess = xf_cliprdr_clipboard_file_size_success;
|
||||
clipboard->delegate->ClipboardFileSizeFailure = xf_cliprdr_clipboard_file_size_failure;
|
||||
clipboard->delegate->ClipboardFileRangeSuccess = xf_cliprdr_clipboard_file_range_success;
|
||||
clipboard->delegate->ClipboardFileRangeFailure = xf_cliprdr_clipboard_file_range_failure;
|
||||
|
||||
return clipboard;
|
||||
|
||||
error:
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
free(clipboard->clientFormats[i].formatName);
|
||||
|
||||
ClipboardDestroy(clipboard->system);
|
||||
|
||||
free(clipboard);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
333
client/X11/xf_disp.c
Normal file
333
client/X11/xf_disp.c
Normal file
@ -0,0 +1,333 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Display Control channel
|
||||
*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#ifdef WITH_XRANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/randr.h>
|
||||
|
||||
#if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
|
||||
# define USABLE_XRANDR
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "xf_disp.h"
|
||||
#include "xf_monitor.h"
|
||||
|
||||
|
||||
#define TAG CLIENT_TAG("x11disp")
|
||||
#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
|
||||
|
||||
struct _xfDispContext
|
||||
{
|
||||
xfContext *xfc;
|
||||
BOOL haveXRandr;
|
||||
int eventBase, errorBase;
|
||||
int lastSentWidth, lastSentHeight;
|
||||
UINT64 lastSentDate;
|
||||
int targetWidth, targetHeight;
|
||||
BOOL activated;
|
||||
BOOL waitingResize;
|
||||
};
|
||||
|
||||
|
||||
static BOOL xf_disp_sendResize(xfDispContext *xfDisp, int width, int height)
|
||||
{
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT layout;
|
||||
xfContext *xfc = xfDisp->xfc;
|
||||
rdpSettings *settings = xfc->context.settings;
|
||||
|
||||
xfDisp->lastSentDate = GetTickCount64();
|
||||
xfDisp->lastSentWidth = width;
|
||||
xfDisp->lastSentHeight = height;
|
||||
xfDisp->waitingResize = TRUE;
|
||||
|
||||
layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
|
||||
layout.Top = layout.Left = 0;
|
||||
layout.Width = width;
|
||||
layout.Height = height;
|
||||
layout.Orientation = ORIENTATION_LANDSCAPE;
|
||||
layout.DesktopScaleFactor = settings->DesktopScaleFactor;
|
||||
layout.DeviceScaleFactor = settings->DeviceScaleFactor;
|
||||
layout.PhysicalWidth = width;
|
||||
layout.PhysicalHeight = height;
|
||||
|
||||
return xfc->disp->SendMonitorLayout(xfc->disp, 1, &layout) == CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
static BOOL xf_disp_set_window_resizable(xfDispContext *xfDisp)
|
||||
{
|
||||
XSizeHints *size_hints;
|
||||
|
||||
if (!(size_hints = XAllocSizeHints()))
|
||||
return FALSE;
|
||||
|
||||
size_hints->flags = PMinSize | PMaxSize | PWinGravity;
|
||||
size_hints->win_gravity = NorthWestGravity;
|
||||
size_hints->min_width = size_hints->min_height = 320;
|
||||
size_hints->max_width = size_hints->max_height = 8192;
|
||||
if (xfDisp->xfc->window)
|
||||
XSetWMNormalHints(xfDisp->xfc->display, xfDisp->xfc->window->handle, size_hints);
|
||||
XFree(size_hints);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void xf_disp_OnActivated(void* context, ActivatedEventArgs* e)
|
||||
{
|
||||
xfContext *xfc = (xfContext *)context;
|
||||
xfDispContext *xfDisp = xfc->xfDisp;
|
||||
rdpSettings *settings = xfc->context.settings;
|
||||
|
||||
xfDisp->waitingResize = FALSE;
|
||||
|
||||
if (xfDisp->activated && !settings->Fullscreen)
|
||||
{
|
||||
xf_disp_set_window_resizable(xfDisp);
|
||||
|
||||
if (e->firstActivation)
|
||||
return;
|
||||
|
||||
/* if a resize has been done recently don't do anything and let the timer
|
||||
* perform the resize */
|
||||
if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY)
|
||||
return;
|
||||
|
||||
if ((xfDisp->lastSentWidth != xfDisp->targetWidth) || (xfDisp->lastSentHeight != xfDisp->targetHeight))
|
||||
{
|
||||
WLog_DBG(TAG, "performing delayed resize to %dx%d", xfDisp->targetWidth, xfDisp->targetHeight);
|
||||
xf_disp_sendResize(xfDisp, xfDisp->targetWidth, xfDisp->targetHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void xf_disp_OnGraphicsReset(void* context, GraphicsResetEventArgs* e)
|
||||
{
|
||||
xfContext *xfc = (xfContext *)context;
|
||||
xfDispContext *xfDisp = xfc->xfDisp;
|
||||
rdpSettings *settings = xfc->context.settings;
|
||||
|
||||
xfDisp->waitingResize = FALSE;
|
||||
|
||||
if (xfDisp->activated && !settings->Fullscreen)
|
||||
{
|
||||
xf_disp_set_window_resizable(xfDisp);
|
||||
|
||||
/* if a resize has been done recently don't do anything and let the timer
|
||||
* perform the resize */
|
||||
if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY)
|
||||
return;
|
||||
|
||||
if ((xfDisp->lastSentWidth != xfDisp->targetWidth) || (xfDisp->lastSentHeight != xfDisp->targetHeight))
|
||||
{
|
||||
WLog_DBG(TAG, "performing delayed resize to %dx%d", xfDisp->targetWidth, xfDisp->targetHeight);
|
||||
xf_disp_sendResize(xfDisp, xfDisp->targetWidth, xfDisp->targetHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_disp_OnTimer(void* context, TimerEventArgs* e)
|
||||
{
|
||||
xfContext *xfc = (xfContext *)context;
|
||||
xfDispContext *xfDisp = xfc->xfDisp;
|
||||
rdpSettings *settings = xfc->context.settings;
|
||||
|
||||
if (!xfDisp->activated || settings->Fullscreen)
|
||||
return;
|
||||
|
||||
if (e->now - xfDisp->lastSentDate < RESIZE_MIN_DELAY)
|
||||
return;
|
||||
|
||||
if ((xfDisp->lastSentWidth != xfDisp->targetWidth) || (xfDisp->lastSentHeight != xfDisp->targetHeight))
|
||||
{
|
||||
WLog_DBG(TAG, "timer performing delayed resize to %dx%d", xfDisp->targetWidth, xfDisp->targetHeight);
|
||||
xf_disp_sendResize(xfDisp, xfDisp->targetWidth, xfDisp->targetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
xfDispContext *xf_disp_new(xfContext* xfc)
|
||||
{
|
||||
xfDispContext *ret = calloc(1, sizeof(xfDispContext));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
ret->xfc = xfc;
|
||||
#ifdef USABLE_XRANDR
|
||||
if (XRRQueryExtension(xfc->display, &ret->eventBase, &ret->errorBase))
|
||||
{
|
||||
ret->haveXRandr = TRUE;
|
||||
}
|
||||
#endif
|
||||
ret->lastSentWidth = ret->targetWidth = xfc->context.settings->DesktopWidth;
|
||||
ret->lastSentHeight = ret->targetHeight = xfc->context.settings->DesktopHeight;
|
||||
|
||||
PubSub_SubscribeActivated(xfc->context.pubSub, xf_disp_OnActivated);
|
||||
PubSub_SubscribeGraphicsReset(xfc->context.pubSub, xf_disp_OnGraphicsReset);
|
||||
PubSub_SubscribeTimer(xfc->context.pubSub, xf_disp_OnTimer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xf_disp_free(xfDispContext *disp)
|
||||
{
|
||||
PubSub_UnsubscribeActivated(disp->xfc->context.pubSub, xf_disp_OnActivated);
|
||||
PubSub_UnsubscribeTimer(disp->xfc->context.pubSub, xf_disp_OnTimer);
|
||||
free(disp);
|
||||
}
|
||||
|
||||
static UINT xf_disp_sendLayout(DispClientContext *disp, rdpMonitor *monitors, int nmonitors)
|
||||
{
|
||||
UINT ret = CHANNEL_RC_OK;
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT *layouts;
|
||||
int i;
|
||||
xfDispContext *xfDisp = (xfDispContext *)disp->custom;
|
||||
rdpSettings *settings = xfDisp->xfc->context.settings;
|
||||
|
||||
layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
|
||||
if (!layouts)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
for (i = 0; i < nmonitors; i++)
|
||||
{
|
||||
layouts[i].Flags = (monitors[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
|
||||
layouts[i].Left = monitors[i].x;
|
||||
layouts[i].Top = monitors[i].y;
|
||||
layouts[i].Width = monitors[i].width;
|
||||
layouts[i].Height = monitors[i].height;
|
||||
layouts[i].Orientation = ORIENTATION_LANDSCAPE;
|
||||
layouts[i].PhysicalWidth = monitors[i].attributes.physicalWidth;
|
||||
layouts[i].PhysicalHeight = monitors[i].attributes.physicalHeight;
|
||||
|
||||
switch(monitors[i].attributes.orientation)
|
||||
{
|
||||
case 90:
|
||||
layouts[i].Orientation = ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
case 180:
|
||||
layouts[i].Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
case 270:
|
||||
layouts[i].Orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
/* MS-RDPEDISP - 2.2.2.2.1:
|
||||
* Orientation (4 bytes): A 32-bit unsigned integer that specifies the
|
||||
* orientation of the monitor in degrees. Valid values are 0, 90, 180
|
||||
* or 270
|
||||
*
|
||||
* So we default to ORIENTATION_LANDSCAPE
|
||||
*/
|
||||
layouts[i].Orientation = ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
}
|
||||
layouts[i].DesktopScaleFactor = settings->DesktopScaleFactor;
|
||||
layouts[i].DeviceScaleFactor = settings->DeviceScaleFactor;
|
||||
}
|
||||
|
||||
ret = disp->SendMonitorLayout(disp, nmonitors, layouts);
|
||||
|
||||
free(layouts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL xf_disp_handle_xevent(xfContext *xfc, XEvent *event)
|
||||
{
|
||||
xfDispContext *xfDisp = xfc->xfDisp;
|
||||
rdpSettings *settings = xfc->context.settings;
|
||||
UINT32 maxWidth, maxHeight;
|
||||
|
||||
if (!xfDisp->haveXRandr)
|
||||
return TRUE;
|
||||
|
||||
#ifdef USABLE_XRANDR
|
||||
if (event->type != xfDisp->eventBase + RRScreenChangeNotify)
|
||||
return TRUE;
|
||||
#endif
|
||||
|
||||
xf_detect_monitors(xfc, &maxWidth, &maxHeight);
|
||||
return xf_disp_sendLayout(xfc->disp, settings->MonitorDefArray, settings->MonitorCount) == CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL xf_disp_handle_configureNotify(xfContext *xfc, int width, int height)
|
||||
{
|
||||
xfDispContext *xfDisp = xfc->xfDisp;
|
||||
|
||||
if (xfDisp->lastSentWidth == width && xfDisp->lastSentHeight == height)
|
||||
return TRUE;
|
||||
|
||||
if (xfDisp->waitingResize || !xfDisp->activated ||
|
||||
(GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY))
|
||||
{
|
||||
WLog_DBG(TAG, "delaying resize to %dx%d", width, height);
|
||||
xfDisp->targetWidth = width;
|
||||
xfDisp->targetHeight = height;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "resizing on ConfigureNotify to %dx%d", width, height);
|
||||
return xf_disp_sendResize(xfDisp, width, height);
|
||||
}
|
||||
|
||||
|
||||
UINT xf_DisplayControlCaps(DispClientContext *disp, UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
|
||||
{
|
||||
/* we're called only if dynamic resolution update is activated */
|
||||
xfDispContext *xfDisp = (xfDispContext *)disp->custom;
|
||||
rdpSettings *settings = xfDisp->xfc->context.settings;
|
||||
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: MaxNumMonitors: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"",
|
||||
maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
|
||||
|
||||
xfDisp->activated = TRUE;
|
||||
|
||||
if (settings->Fullscreen)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizeable");
|
||||
return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
BOOL xf_disp_init(xfContext* xfc, DispClientContext *disp)
|
||||
{
|
||||
rdpSettings *settings = xfc->context.settings;
|
||||
xfc->disp = disp;
|
||||
disp->custom = (void*) xfc->xfDisp;
|
||||
|
||||
if (settings->DynamicResolutionUpdate)
|
||||
{
|
||||
disp->DisplayControlCaps = xf_DisplayControlCaps;
|
||||
#ifdef USABLE_XRANDR
|
||||
if (settings->Fullscreen)
|
||||
{
|
||||
/* ask X11 to notify us of screen changes */
|
||||
XRRSelectInput(xfc->display, DefaultRootWindow(xfc->display), RRScreenChangeNotifyMask);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
36
client/X11/xf_disp.h
Normal file
36
client/X11/xf_disp.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Display Control channel
|
||||
*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
#ifndef FREERDP_CLIENT_X11_DISP_H
|
||||
#define FREERDP_CLIENT_X11_DISP_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
FREERDP_API BOOL xf_disp_init(xfContext* xfc, DispClientContext *disp);
|
||||
|
||||
xfDispContext *xf_disp_new(xfContext* xfc);
|
||||
void xf_disp_free(xfDispContext *disp);
|
||||
BOOL xf_disp_handle_xevent(xfContext *xfc, XEvent *event);
|
||||
BOOL xf_disp_handle_configureNotify(xfContext *xfc, int width, int height);
|
||||
void xf_disp_resized(xfDispContext *disp);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_DISP_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user