Compare commits

..

49 Commits

Author SHA1 Message Date
Tobias Frost
a62ef46b9b Fix typo found post upload. 2023-11-17 18:38:48 +01:00
Tobias Frost
528ad1ee7f Prepare changelog for upload. 2023-11-17 17:29:55 +01:00
Tobias Frost
9c2cb890eb Import fix for CVE-2022-39283 - closes also #1021659 2023-11-12 13:08:09 +01:00
Tobias Frost
1cddd4643a Import fix for CVE-2022-39282 (Closes: #1021659) 2023-11-12 12:44:19 +01:00
Tobias Frost
ad925990b3 Fix changelog date. 2023-11-12 12:24:32 +01:00
Tobias Frost
cb0fee7d81 Prepare changelog for upload to LTS. 2023-11-12 12:23:35 +01:00
Tobias Frost
343a6e9965 Fixing whitespaces in d/changelog and a typo in a patch. 2023-11-12 12:08:01 +01:00
Tobias Frost
180fc8f332 fix 0052-CVE-2022-24883.patch -- it stopped applying after dropping patch 0051. 2023-10-29 14:23:10 +01:00
Tobias Frost
326341043d Drop patch for CVE-2022-24882
the patch does not work with 2.3.0, needs more investiagion.
2023-10-29 14:22:13 +01:00
Tobias Frost
b7fad42bde CVE-2022-41877 - Missing input length validation in drive channel 2023-10-29 00:12:43 +02:00
Tobias Frost
eb2c3e598e CVE-2022-39347 - Missing path sanitation with drive channel 2023-10-28 23:26:25 +02:00
Tobias Frost
ae332a9e65 CVE-2022-39319 - Missing length validation in urbdrc channel 2023-10-29 10:45:28 +01:00
Tobias Frost
9abf5f033b Import fix for CVE-2022-39318 - Division by zero in urbdrc channel 2023-10-29 10:14:56 +01:00
Tobias Frost
56d1291988 Import fix for CVE-2022-39316 - Out of bound read in zgfx decoder 2023-10-29 10:12:55 +01:00
Tobias Frost
3f665697f0 Import fix for CVE-2022-24883 - FreeRDP Server authentication might allow invalid credentials to pass. 2023-10-29 10:09:48 +01:00
Tobias Frost
a8d9578fb9 Import fix for CVE-2022-24882 - Server side NTLM does not properly check parameters. 2023-10-28 20:16:13 +02:00
Tobias Frost
14442af9ac Import fix for CVE-2021-41160 - Improper region checks in all clients allow out of bound write to memory (Closes: #1001062) 2023-10-28 18:36:39 +02:00
Tobias Frost
8f234906e9 Fix wrong number CVE changelog entry. 2023-10-07 20:03:39 +02:00
Tobias Frost
6ebfab5ec1 Prepare changelog for upload. 2023-10-07 17:31:07 +02:00
Tobias Frost
bb305bcdf7 Fix segfault in CVE-2023-39355.patch
(and use posix_memalign instead of memalign)
2023-10-07 17:08:05 +02:00
Tobias Frost
f1641af0fd Touch changelog timestamp. 2023-10-07 13:29:57 +02:00
Tobias Frost
b743b819c0 CVE-2023-40589 2023-10-07 13:29:15 +02:00
Tobias Frost
d9179e0766 CVE-2023-40569 2023-10-07 13:27:15 +02:00
Tobias Frost
24c51f4ed8 CVE-2023-40188.patch 2023-10-07 13:17:33 +02:00
Tobias Frost
f6f2bf7896 CVE-2023-40186 2023-10-07 13:11:23 +02:00
Tobias Frost
0f3fd7d339 0045-CVE-2023-40181.patch 2023-10-07 12:53:23 +02:00
Tobias Frost
d1217c6dad Apply upstream patch for CVE-2023-40567. 2023-10-07 12:53:18 +02:00
Tobias Frost
09055cabae Backport upstream patch for CVE-2023-39356. 2023-10-07 12:33:20 +02:00
Tobias Frost
ab18013d96 Backport CVE-2023-39354. 2023-10-07 12:07:10 +02:00
Tobias Frost
2dacc519e5 Backport patch for CVE-2023-39353. 2023-10-07 11:28:59 +02:00
Tobias Frost
792f6a14d1 Backport patch for CVE-2023-39352. 2023-10-07 11:10:12 +02:00
Tobias Frost
a4c483bc30 Cherry-pick upstream patch for CVE-2023-39351. 2023-10-07 10:58:09 +02:00
Tobias Frost
43cbb16760 Revisit CVE-2023-39350 after updates/clarifactions from upstream. 2023-10-07 10:51:05 +02:00
Tobias Frost
500b4499a7 Backport CVE-2023-40589.
replaced WINPR_ASSERT with plain assert, as this macro is defined only in later versions and if verbose asserting is disabled it will actually do assert() itself.
2023-10-03 11:14:37 +02:00
Tobias Frost
6ae95183f4 Backport of CVE-2023-39355
upstream is using in later version aligned memory allocation, so using memaling to simulate that.
That of course required to memset it afterwards, as upstream used calloc for the allocation before.
2023-10-03 10:57:01 +02:00
Tobias Frost
21305b53c4 Disable piuparts and blhc
piuparts is broken for buster
blhc is failing, but not going to fix that for the DLA.
2023-10-03 10:15:50 +02:00
Tobias Frost
efc916e1a4 CVE-2023-39354 2023-10-03 10:08:48 +02:00
Tobias Frost
b6e609f697 CVE-2023-39350 2023-10-03 10:07:13 +02:00
Tobias Frost
0333c99067 Enable Salsa CI 2023-10-03 09:35:54 +02:00
Tobias Frost
6e4db706a5 Debian release 2.3.0+dfsg1-2+deb11u1
-----BEGIN PGP SIGNATURE-----
 
 iQJVBAABCAA/FiEEm/uu6GwKpf+/IgeCmvRrMCV3GzEFAmInCfghHG1pa2UuZ2Fi
 cmllbEBkYXMtbmV0endlcmt0ZWFtLmRlAAoJEJr0azAldxsxnVsP/iCyxT55ot9U
 DP/mn1sY4R10wEu306RiSHYpIHdhoI5zmpwywq936DC/J7WUebZD0PZfANv5lioX
 VwoJSVXUhsvk67VTR77zFsTwU66E4mtvruh6rP0SO6ooRRbqQedVFsZAAMbugHAL
 3bMPMbJ1jklWsIui/x3ggmEQ5wy8c1kOIttn8PXmo/h4P3cOuuHDSJM1y0BpoqIs
 P7MsK3TTycobUg1sgrtrj/rKrIeqiS3NRZQ0VSiHunSCQdPYPm5CChSaVsgyAenC
 VmnU5+pLSgBYunMh7OFUQCgdBQzKnUIZ9BSxc3ybRnW5hqREpdcwMZ8Nf8oLluEw
 1FYSaqNKpfP0CkwkjWO0qPXiWIoqZIhGC1xA5SivNf2poWkmhhwLH+PXZFHCmlFc
 ba8iFrG9gt4tSM45mVbpJTHbNTHjwsQpbHB+V9zyWt5VC5zsdzsIn1Kxl8obGdvD
 JN+3oo9yTrVw4Mh5fmN52aRtmrd/QVeJKTBv8zN9L7LFi/8Bwb5P7lsqlArNOpQi
 oL1xt6Uv2nHowCteue75DKEt3Q7hxKUrZFtjTPjbuv2ZJk2TSJ27rv9RQ4dhj7hO
 RCDg2sa/AMnyrj0pK9wtaRpUrhAuKEHRfs+8n39z2aqi6CMbMM3p3P8DB2bjhpcc
 v1IXrs60cxRvsg1zhL2bhk1KCAVJrkZc
 =01RW
 -----END PGP SIGNATURE-----

Merge tag 'debian/2.3.0+dfsg1-2+deb11u1' into debian/buster to prepare a
backport for buster.

Debian release 2.3.0+dfsg1-2+deb11u1

Adapt to buster.
2023-10-03 01:16:50 +02:00
Mike Gabriel
0359d79a4b upload to bullseye (debian/2.3.0+dfsg1-2+deb11u1) 2022-03-08 08:46:53 +01:00
Mike Gabriel
6dd3e7854d debian/patches: Trivial rebase of 1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch against v2.3.0. 2022-03-08 08:45:25 +01:00
Mike Gabriel
03201de47f debian/patches: Add 1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch. Keep DumpThreadHandles as a symbol even if WITH_DEBUG_THREADS is OFF.
(cherry picked from commit f726052dd4)
2022-03-08 08:44:42 +01:00
Bernhard Miklautz
4db4aa6d33 debian/rules: Disable additional debug logging. (Closes: #1006683).
(cherry picked from commit a90b67e6c0)
2022-03-08 08:15:32 +01:00
Mike Gabriel
0553695929 upload to buster (debian/2.0.0~git20190204.1.2693389a+dfsg1-1+deb10u2) 2020-06-01 13:13:06 +02:00
Mike Gabriel
bdab8340a1 debian/patches: Add 0002_fix-channels-smartcard-fix-statusw-call.patch. Fix smartcard login failures. (Closes: #919281). 2020-06-01 13:05:53 +02:00
Bernhard Miklautz
163efd4c7d debian/patches: add security related patches from upstream
Back ported patches of multiple security issues were added.
Including the following CVEs:
*  CVE-2020-11521
*  CVE-2020-11522
*  CVE-2020-11523
*  CVE-2020-11524
*  CVE-2020-11525
*  CVE-2020-11526
2020-06-01 13:02:33 +02:00
Mike Gabriel
85341458bc upload to buster (debian/2.0.0~git20190204.1.2693389a+dfsg1-1+deb10u1) 2019-12-18 22:59:52 +01:00
Mike Gabriel
c6fe442da0 debian/patches: Add 0001_CVE-2019-17177.patch. Fix realloc return handling. (CVE-2019-17177). 2019-12-16 11:35:50 +01:00
523 changed files with 17916 additions and 25755 deletions

View File

@ -104,6 +104,7 @@ ForEachMacros:
...
Language: ObjC
PointerBindsToType: false
ObjCSpaceAfterProperty: true
SortIncludes: false
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false

View File

@ -41,6 +41,7 @@ addons:
- libgsm1-dev
- libavcodec-dev
- libavutil-dev
- libx264-dev
- libxext-dev
- ninja-build
- libsystemd-dev

View File

@ -34,9 +34,9 @@ if(NOT DEFINED FREERDP_VENDOR)
set(FREERDP_VENDOR 1)
endif()
option(CMAKE_COLOR_MAKEFILE "colorful CMake makefile" ON)
option(CMAKE_VERBOSE_MAKEFILE "verbose CMake makefile" ON)
option(CMAKE_POSITION_INDEPENDENT_CODE "build with position independent code (-fPIC or -fPIE)" ON)
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Include our extra modules
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
@ -74,10 +74,6 @@ include(InstallFreeRDPMan)
include(GetGitRevisionDescription)
include(SetFreeRDPCMakeInstallDir)
if (DEFINE_NO_DEPRECATED)
add_definitions(-DDEFINE_NO_DEPRECATED)
endif()
# Soname versioning
set(BUILD_NUMBER 0)
if ($ENV{BUILD_NUMBER})
@ -85,7 +81,7 @@ if ($ENV{BUILD_NUMBER})
endif()
set(WITH_LIBRARY_VERSIONING "ON")
set(RAW_VERSION_STRING "2.11.7")
set(RAW_VERSION_STRING "2.3.0")
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
elseif(USE_VERSION_FROM_GIT_TAG)
@ -111,24 +107,6 @@ else()
endif()
message("FREERDP_VERSION=${FREERDP_VERSION_FULL}")
if(EXISTS "${PROJECT_SOURCE_DIR}/.source_version" )
file(READ ${PROJECT_SOURCE_DIR}/.source_version GIT_REVISION)
string(STRIP ${GIT_REVISION} GIT_REVISION)
elseif(USE_VERSION_FROM_GIT_TAG)
git_get_exact_tag(GIT_REVISION --tags --always)
if (${GIT_REVISION} STREQUAL "n/a")
git_rev_parse (GIT_REVISION --short)
endif()
endif()
if (NOT GIT_REVISION)
set(GIT_REVISION ${FREERDP_VERSION})
endif()
message(STATUS "Git Revision ${GIT_REVISION}")
set(FREERDP_INCLUDE_DIR "include/freerdp${FREERDP_VERSION_MAJOR}/")
# Compatibility options
@ -165,11 +143,25 @@ if(CCACHE AND WITH_CCACHE)
endif()
endif(CCACHE AND WITH_CCACHE)
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_version" )
file(READ ${CMAKE_SOURCE_DIR}/.source_version GIT_REVISION)
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}")
# Turn on solution folders (2.8.4+)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@ -225,7 +217,7 @@ endif()
if(MSVC)
include(MSVCRuntime)
if(NOT DEFINED MSVC_RUNTIME)
set(MSVC_RUNTIME "dynamic" CACHE STRING "MSVC runtime type [dynamic|static]")
set(MSVC_RUNTIME "dynamic")
endif()
if(MSVC_RUNTIME STREQUAL "static")
if(BUILD_SHARED_LIBS)
@ -355,7 +347,7 @@ if(NOT IOS)
find_package(Threads REQUIRED)
endif()
if(NOT WIN32 AND NOT IOS)
if(NOT WIN32)
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
@ -532,6 +524,7 @@ add_definitions(-DWINPR_EXPORTS -DFREERDP_EXPORTS)
if(NOT IOS)
check_include_files(fcntl.h HAVE_FCNTL_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(execinfo.h HAVE_EXECINFO_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
check_include_files(sys/filio.h HAVE_SYS_FILIO_H)
@ -539,18 +532,6 @@ if(NOT IOS)
check_include_files(sys/strtio.h HAVE_SYS_STRTIO_H)
check_include_files(sys/select.h HAVE_SYS_SELECT_H)
check_include_files(syslog.h HAVE_SYSLOG_H)
check_include_files(execinfo.h HAVE_EXECINFO_HEADER)
if (HAVE_EXECINFO_HEADER)
check_symbol_exists(backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
check_symbol_exists(backtrace_symbols execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS)
check_symbol_exists(backtrace_symbols_fd execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD)
# Some implementations (e.g. Android NDK API < 33) provide execinfo.h but do not define
# the backtrace functions. Disable detection for these cases
if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS AND HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD)
set(HAVE_EXECINFO_H ON)
endif()
endif()
else()
set(HAVE_FCNTL_H 1)
set(HAVE_UNISTD_H 1)
@ -609,11 +590,6 @@ if(ANDROID)
set (WITH_NEON OFF)
endif()
if(ANDROID_ABI STREQUAL arm64-v8a)
# https://github.com/android/ndk/issues/910
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=softfp")
endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DNDK_DEBUG=1)
@ -672,7 +648,6 @@ if(UNIX OR CYGWIN)
include(CheckFunctionExists)
check_function_exists(getlogin_r HAVE_GETLOGIN_R)
check_function_exists(getpwuid_r HAVE_GETPWUID_R)
else()
set(X11_FEATURE_TYPE "DISABLED")
set(WAYLAND_FEATURE_TYPE "DISABLED")
@ -730,7 +705,7 @@ set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback
set(VAAPI_FEATURE_TYPE "OPTIONAL")
set(VAAPI_FEATURE_PURPOSE "multimedia")
set(VAAPI_FEATURE_DESCRIPTION "[experimental] VA-API hardware acceleration for video playback")
set(VAAPI_FEATURE_DESCRIPTION "VA-API hardware acceleration for video playback")
set(IPP_FEATURE_TYPE "OPTIONAL")
set(IPP_FEATURE_PURPOSE "performance")
@ -740,13 +715,17 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
set(JPEG_FEATURE_PURPOSE "codec")
set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
set(X264_FEATURE_TYPE "OPTIONAL")
set(X264_FEATURE_PURPOSE "codec")
set(X264_FEATURE_DESCRIPTION "use x264 library")
set(OPENH264_FEATURE_TYPE "OPTIONAL")
set(OPENH264_FEATURE_PURPOSE "codec")
set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library")
set(OPENCL_FEATURE_TYPE "OPTIONAL")
set(OPENCL_FEATURE_PURPOSE "codec")
set(OPENCL_FEATURE_DESCRIPTION "[experimental] use OpenCL library")
set(OPENCL_FEATURE_DESCRIPTION "use OpenCL library")
set(GSM_FEATURE_TYPE "OPTIONAL")
set(GSM_FEATURE_PURPOSE "codec")
@ -762,7 +741,7 @@ set(FAAD2_FEATURE_DESCRIPTION "FAAD2 AAC audio codec library")
set(FAAC_FEATURE_TYPE "OPTIONAL")
set(FAAC_FEATURE_PURPOSE "codec")
set(FAAC_FEATURE_DESCRIPTION "[experimental] FAAC AAC audio codec library")
set(FAAC_FEATURE_DESCRIPTION "FAAC AAC audio codec library")
set(SOXR_FEATURE_TYPE "OPTIONAL")
set(SOXR_FEATURE_PURPOSE "codec")
@ -770,7 +749,7 @@ set(SOXR_FEATURE_DESCRIPTION "SOX audio resample library")
set(GSSAPI_FEATURE_TYPE "OPTIONAL")
set(GSSAPI_FEATURE_PURPOSE "auth")
set(GSSAPI_FEATURE_DESCRIPTION "[experimental] add kerberos support")
set(GSSAPI_FEATURE_DESCRIPTION "add kerberos support")
if(WIN32)
set(X11_FEATURE_TYPE "DISABLED")
@ -825,6 +804,7 @@ if(ANDROID)
set(PULSE_FEATURE_TYPE "DISABLED")
set(CUPS_FEATURE_TYPE "DISABLED")
set(PCSC_FEATURE_TYPE "DISABLED")
set(FFMPEG_FEATURE_TYPE "DISABLED")
set(VAAPI_FEATURE_TYPE "DISABLED")
set(OPENSLES_FEATURE_TYPE "REQUIRED")
endif()
@ -847,6 +827,7 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
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(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION})
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
@ -872,23 +853,18 @@ if (WITH_DSP_FFMPEG)
# Deactivate FFmpeg backend for sound, if the version is too old.
# See libfreerdp/codec/dsp_ffmpeg.h
file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version.h" AV_VERSION_FILE REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+")
if (EXISTS "${AVCODEC_INCLUDE_DIR}/libavcodec/version_major.h")
file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version_major.h" AV_VERSION_FILE2 REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+")
list(APPEND AV_VERSION_FILE ${AV_VERSION_FILE2})
endif()
FOREACH(item ${AV_VERSION_FILE})
STRING(REGEX MATCH "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+" litem ${item})
IF(litem)
string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem})
list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN)
if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
message(ERROR "invalid entry in libavcodec version header ${item}")
endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
list(GET VSPLIT_LINE 0 VNAME)
list(GET VSPLIT_LINE 1 VVALUE)
set(${VNAME} ${VVALUE})
ENDIF(litem)
IF(litem)
string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem})
list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN)
if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
message(ERROR "invalid entry in libavcodec version header ${item}")
endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
list(GET VSPLIT_LINE 0 VNAME)
list(GET VSPLIT_LINE 1 VVALUE)
set(${VNAME} ${VVALUE})
ENDIF(litem)
ENDFOREACH(item ${AV_VERSION_FILE})
set(AVCODEC_VERSION "${LIBAVCODEC_VERSION_MAJOR}.${LIBAVCODEC_VERSION_MINOR}.${LIBAVCODEC_VERSION_MICRO}")
@ -937,7 +913,7 @@ if(MBEDTLS_FOUND)
add_definitions("-DWITH_MBEDTLS")
endif()
if (WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG OR WITH_MEDIACODEC)
if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG)
set(WITH_GFX_H264 ON)
else()
set(WITH_GFX_H264 OFF)
@ -990,16 +966,7 @@ if (APPLE)
else (APPLE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
if (NOT FREEBSD)
if (NOT BUILTIN_CHANNELS)
if (NOT DEFINED WITH_PLUGIN_RPATH_ONLY)
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..:\$ORIGIN/../${FREERDP_PLUGIN_PATH}")
else()
# we need to supply this run path, even if not using RPATH in general
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${FREERDP_PLUGIN_PATH}")
endif()
else()
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..")
endif()
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..")
endif()
endif(APPLE)
@ -1062,6 +1029,15 @@ add_subdirectory(include)
add_subdirectory(libfreerdp)
if (IOS)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.0")
if (IOS_PLATFORM MATCHES "SIMULATOR")
set(CMAKE_OSX_SYSROOT "iphonesimulator")
else()
set(CMAKE_OSX_SYSROOT "iphoneos")
endif()
endif()
# RdTk
include_directories("${CMAKE_SOURCE_DIR}/rdtk/include")
include_directories("${CMAKE_BINARY_DIR}/rdtk/include")

344
ChangeLog
View File

@ -1,346 +1,3 @@
# 2024-04-22 Version 2.11.7
Noteworthy changes:
* Backported oss-fuzz fixes
For a complete and detailed change log since the last release run:
git log 2.11.7...2.11.6
# 2024-04-17 Version 2.11.6
CVE:
CVE-2024-32041 [Low[ OutOfBound Read in zgfx_decompress_segment
CVE-2024-32039 [Moderate] Integer overflow & OutOfBound Write in clear_decompress_residual_data
CVE-2024-32040 [Low] integer underflow in nsc_rle_decode
CVE-2024-32458 [Low] OutOfBound Read in planar_skip_plane_rle
CVE-2024-32459 [Low] OutOfBound Read in ncrush_decompress
CVE-2024-32460 [Low] OutOfBound Read in interleaved_decompress
Noteworthy changes:
* Backported #10077
For a complete and detailed change log since the last release run:
git log 2.11.6...2.11.5
# 2024-01-19 Version 2.11.5
Noteworthy changes:
* Fix integer overflow in progressive decoder
* Update OpenSSL API usage for compatiblility with newer versions (#9747)
* Prevent NULL dereference for single thread decoder (#9712)
For a complete and detailed change log since the last release run:
git log 2.11.5...2.11.4
# 2023-12-14 Version 2.11.4
Notworthy changes:
* fix a typo in unicode commit (#9652)
For a complete and detailed change log since the last release run:
git log 2.11.4...2.11.3
# 2023-12-14 Version 2.11.3
Notworthy changes:
* Disabled windows MEDIA FOUNDATION h264 decoder due to reported issues (#9469)
* Fix issues with drive redirection (#9530,9554, #9586, #9617)
* Use endian safe ICU string converter (#9631)
* Improve AAC support (#9577)
* Fix swiss german keyboard layout (#9560)
* Enable rfx-mode:image (#9428)
For a complete and detailed change log since the last release run:
git log 2.11.3...2.11.2
# 2023-09-20 Version 2.11.2
Notworthy changes:
* Backported #9378: backported wArrayList (optional) copy on insert
* Backported #9360: backported certificate algorithm detection
For a complete and detailed change log since the last release run:
git log 2.11.2...2.11.1
# 2023-09-04 Version 2.11.1
Notworthy changes:
* Backported #9356: Fix issues with order updates
For a complete and detailed change log since the last release run:
git log 2.11.1..2.11.0
# 2023-08-28 Version 2.11.0
Noteworthy changes:
* Various input validation fixes
* Added various CMake options #9317
* LibreSSL build fixes #8709
Fixed issues:
* Backported #9233: Big endian support
* Backported #9099: Mouse grabbing support
* Backported #6851: wayland scrolling fix
* Backported #8690: Update h264 to use new FFMPEG API
* Backported #7306: early bail from update_read_window_state_order breaks protocol
* Backported #8903: rdpecam/server: Remove wrong assertion
* Backported #8994: bounds checks for gdi/gfx rectangles
* Backported #9023: enforce rdpdr client side state checks
* Backported #6331: deactivate mouse grabbing by default
* Cherry-pick out of #9172: channels/cliprdr: Fix writing incorrect PDU type for unlock PDUs
# 2023-02-16 Version 2.10.0
Noteworthy changes:
* Fix android build scripts, use CMake from SDK
* Fix connection negotiation with mstsc/msrdc #8426
* [ntlm]: use rfc5929 binding hash algorithm #8430
* [channels,printer] Fixed reference counting #8433
* Fix uwac pixman #8439
* Fix Rdp security #8457
* [client,x11] Detect key autorepeat #8522
* [build] add channel path to RPATH #8551
* Fix build with BUILTIN_CHANNELS=OFF #8560
* revert changes so that the osmajortype/osminortype is not overwritten #8571
* [uwac] do not use iso C functions #8604
* [winpr,sam] fix inalid NULL arguments #8605
* Fix incompatible function pointer types #8625
Fixed issues:
* Backported #8581: Ignore data PDUs for DVCs that were not opened successfully
* Backported #8498: [channel,urbdrc] fix type of usb hotplug callback
* Backported #8537: Extended info enforce limits
* Backported #8611: [core] add missing redirection fields
# 2022-11-16 Version 2.9.0
Noteworthy changes:
* Backported #8252: Support sending server redirection PDU
* Backported #8406: Ensure X11 client cursor is never smaller 1x1
* Backported #8403: Fixed multiple client side input validation issues
(CVE-2022-39316, CVE-2022-39317, CVE-2022-39318, CVE-2022-39319,
CVE-2022-39320, CVE-2022-41877, CVE-2022-39347)
* Backported #7282: Proxy server now discards input events sent before
activation was received
* Backported #8324: Internal replacements for md4, md5 and hmac-md5
For the time being the RDP protocol requires these outdated hash
algorithms. So any distribution that wants to ship a working
FreeRDP should check the options WITH_INTERNAL_MD4 (and depending
on OpenSSL deprecation status WITH_INTERNAL_MD5)
Fixed issues:
* Backported #8341: Null checks in winpr_Digest_Free
* Backported #8335: Missing NULL return in winpr_Digest_New
* Backported #8192: Support for audin version 2 microphone channel
* Backported #7282: Discard input events before activation (Fixes #8374)
For a complete and detailed change log since the last release run:
git log 2.8.1..2.9.0
# 2022-10-12 Version 2.8.1
Noteworthy changes:
* Fixed CVE-2022-39282
* Fixed CVE-2022-39283
* Added missing commit for backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable)
* Added hash checks for android build script dependencies
Fixed issues:
* Backported #8190: Fix build break with newer FFMPEG versions
* Backported #8234: Updated flatpak with build script
* Backported #8210: Better execinfo support check for android
* Backported #7708: Header now defines DumpThreadHandles
* Backported #8176: Check fullscreen state and not setting
* Backported #8236: Send resize on window state change
* Backported #7611: Audin macOS monterey fix
* Backported #8291: Android build script update
# 2022-07-28 Version 2.8.0
Noteworthy changes:
* Backported API to get peer accepted channel option flags
* Backported API to get peer accepted channel names
* Backported Stream_CheckAndLogRequiredLength
* Backported #7954: Add server side handling for [MS-RDPET]
* Backported #8010: Add server side handling for [MS-RDPECAM]
* Backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable)
* Backported #8051: Relieve CLIPRDR filename restriction when connecting to non-MS Windows servers
* Backported #8048: TLS version control
* Backported #7987: Add a new command line arg to enforce tls1.2
Fixed issues:
* Fixed #7837: Prevent out of bound reads for FFMPEG
* Backported #7859 and #7861: Unwind support for backtrace generation
* Backported #7440: wlfreerdp appid
* Backported #7832: RAIL window restore
* Backported #7833: Refactored WinPR thread locking
* Backported #7893: Mac rdpsnd memory leak fixes
* Backported #7895: Mac audin memory leak fixes
* Backported #7898: Automatic android versioning
* Backported #7916: GFX 10.7 capability support
* Backported #7949: Server RDPSND API improvements
* Backported #7957: Server DVC API improvements
* Backported #7760: Fixed osMinorType values
* Backported #8013: Add missing osMajorType values
* Backported #8076: Fix wrong usage of subband diffing flag (tile artifact fix)
For a complete and detailed change log since the last release run:
git log 2.7.0..2.8.0
# 2022-04-25 Version 2.7.0
Noteworthy changes:
* Backported OpenSSL3 gateway support (#7822)
* Backported various NTLM fixes
* Backported WINPR_ASSERT to ease future backports
Fixed issues:
* Backported #6786: Use /network:auto by default
* Backported #7714: Workaround for broken surface frame marker
* Backported #7733: Support 10bit X11 color (BGRX32 only)
* Backported #7745: GFX progressive double free
* Backported #7808: Disable websockets with /gt:rpc
* Backported #7815: RAIL expect LOGON_MSG_SESSION_CONTINUE
Important notes:
For a complete and detailed change log since the last release run:
git log 2.6.1..2.7.0
# 2022-03-07 Version 2.6.1
Noteworthy changes:
Fixed issues:
* Backported freerdp_abort_connect during freerdp_connect fix (#7700)
* Backported improved version dection see docs/version_detection.md for details
* Backported various rdpsnd fixes (#7695)
Important notes:
For a complete and detailed change log since the last release run:
git log 2.0.0..2.6.1
# 2022-02-22 Version 2.6.0
Noteworthy changes:
* Backported android FFMPEG build scripts
* Updated android build dependencies
Fixed issues:
* Backported #7303: Fix PDU length for RDPINPUT_PROTOCOL_V300
* Backported #7658: Sanitize optional physical monitor size values
* Backported #7426: Wayland memory corruption
* Backported #7293: Remove unused codec x264
* Backported #7541: Allow resolutions larger 2048x2048
* Backported #7574: FFMPEG 5.0 support
* Backported #7578: FFMPEG 5.0 support
* Backported #7580: Fixed device hotplugging
* Backported #7583: GetUserNameExA: Prefer getpwuid_r over getlogin_r over getlogin
* Backported #7585: Android Mediacodec support
Important notes:
For a complete and detailed change log since the last release run:
git log 2.5.0..2.6.0
# 2022-01-12 Version 2.5.0
Noteworthy changes:
* Fixed smartcard login in case a redirection occurs the pin was lost
* Backported windows client drawing fixes
* Backported improved macOS keyboard layout detection
* Backported TcpConnectTimeout
* Backported LibreSSL compatibility patches
* Backported signal handler backtrace
* Backported OpenSSL 3.0 support
Fixed issues:
* Backport #7539: Wayland client clipboard issues
* Backport #7509: Various fixes regarding registry emulation, addin loader
and updated locale detection
* Backport #7466: Android android_register_pointer missing initialization
Important notes:
For a complete and detailed change log since the last release run:
git log 2.4.1..2.5.0
# 2021-10-20 Version 2.4.1
Noteworthy changes:
* Refactored RPC gateway parsing code
* OpenSSL 3.0 compatibility fixes
* USB redirection: fixed transfer lengths
Fixed issues:
* #7363: Length checks in ConvertUTF8toUTF16
* #7349: Added checks for bitmap width and heigth values
Important notes:
* CVE-2021-41159: Improper client input validation for gateway connections allows to overwrite memory
* CVE-2021-41160: Improper region checks in all clients allow out of bound write to memory
For a complete and detailed change log since the last release run:
git log 2.4.0..2.4.1
# 2021-07-27 Version 2.4.0
Noteworthy changes:
* Backported multithreadded progressive decoder (#7036)
* Backported clipboard fixes (#6924)
* Fixed remote file read (#7185)
Fixed issues:
* #6938: RAILS clipboard remote -> local
* #6985: Support newer FFMPEG builds
* #6989: Use OpenSSL default certificate store settings
* #7073: Planar alignment fixes
# 2021-03-15 Version 2.3.2
For a complete and detailed change log since the last release run:
git log 2.3.2..2.4.0
Noteworthy changes:
* Fixed autoreconnect printer backend loading
* Fixed compilation on older mac os versions < 10.14
* Fixed mouse pointer move with smart-sizing
* Added command line option to disable websocket gateway support
* Fixed drive hotplugging issues with windows
* Fixed smartcard issues on mac
Fixed issues:
* #6900: Transparency issues with aFreeRDP
* #6848: Invalid format string in smartcard trace
* #6846: Fixed static builds
* #6888: Crash due to missing bounds checks
* #6882: Use default sound devoce on mac
For a complete and detailed change log since the last release run:
git log 2.3.1..2.3.2
# 2021-03-01 Version 2.3.1
Noteworthy changes:
* This is a compatibility bugfix release readding some (deprecated)
symbols/defines
* Also add some more EXPERIMENTAL warnings to CMake flags as some were not
clear enough.
* Fixed a memory leak in xfreerdp (mouse pointer updates)
* No longer activating some compile time debug options with -DWITH_DEBUG_ALL=ON
which might leak sensitive information.
* Added -DDEFINE_NO_DEPRECATED for developers to detect use of deprecated
symbols
For a complete and detailed change log since the last release run:
git log 2.3.0..2.3.1
# 2021-02-24 Version 2.3.0
Important notes:
@ -776,3 +433,4 @@ Virtual Channels:
* rdpsnd (Sound Redirection)
* alsa support
* pulse support

View File

@ -1,13 +0,0 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT ON)
define_channel_options(NAME "ainput" TYPE "dynamic"
DESCRIPTION "Advanced Input Virtual Channel Extension"
SPECIFICATIONS "[XXXXX]"
DEFAULT ${OPTION_DEFAULT})
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})

View File

@ -1,34 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Armin Novak <anovak@thincast.com>
# Copyright 2022 Thincast Technologies GmbH
#
# 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("ainput")
set(${MODULE_PREFIX}_SRCS
ainput_main.c
ainput_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 ${PROJECT_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")

View File

@ -1,315 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Advanced Input Virtual Channel Extension
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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 <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include "ainput_main.h"
#include <freerdp/channels/log.h>
#include <freerdp/client/ainput.h>
#include <freerdp/channels/ainput.h>
#include "../common/ainput_common.h"
#define TAG CHANNELS_TAG("ainput.client")
typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK;
struct AINPUT_CHANNEL_CALLBACK_
{
IWTSVirtualChannelCallback iface;
IWTSPlugin* plugin;
IWTSVirtualChannelManager* channel_mgr;
IWTSVirtualChannel* channel;
};
typedef struct AINPUT_LISTENER_CALLBACK_ AINPUT_LISTENER_CALLBACK;
struct AINPUT_LISTENER_CALLBACK_
{
IWTSListenerCallback iface;
IWTSPlugin* plugin;
IWTSVirtualChannelManager* channel_mgr;
AINPUT_CHANNEL_CALLBACK* channel_callback;
};
typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
struct AINPUT_PLUGIN_
{
IWTSPlugin iface;
AINPUT_LISTENER_CALLBACK* listener_callback;
IWTSListener* listener;
UINT32 MajorVersion;
UINT32 MinorVersion;
BOOL initialized;
};
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
{
UINT16 type;
AINPUT_PLUGIN* ainput;
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
WINPR_ASSERT(callback);
WINPR_ASSERT(data);
ainput = (AINPUT_PLUGIN*)callback->plugin;
WINPR_ASSERT(ainput);
if (Stream_GetRemainingLength(data) < 2)
return ERROR_NO_DATA;
Stream_Read_UINT16(data, type);
switch (type)
{
case MSG_AINPUT_VERSION:
if (Stream_GetRemainingLength(data) < 8)
return ERROR_NO_DATA;
Stream_Read_UINT32(data, ainput->MajorVersion);
Stream_Read_UINT32(data, ainput->MinorVersion);
break;
default:
WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type);
break;
}
return CHANNEL_RC_OK;
}
static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y)
{
AINPUT_PLUGIN* ainput;
AINPUT_CHANNEL_CALLBACK* callback;
BYTE buffer[32] = { 0 };
UINT64 time;
wStream sbuffer = { 0 };
wStream* s = &sbuffer;
Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
WINPR_ASSERT(s);
WINPR_ASSERT(context);
time = GetTickCount64();
ainput = (AINPUT_PLUGIN*)context->handle;
WINPR_ASSERT(ainput);
WINPR_ASSERT(ainput->listener_callback);
if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
{
WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.",
ainput->MajorVersion, ainput->MinorVersion);
return CHANNEL_RC_UNSUPPORTED_VERSION;
}
callback = ainput->listener_callback->channel_callback;
WINPR_ASSERT(callback);
{
char buffer[128] = { 0 };
WLog_VRB(TAG, "[%s] sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32,
__FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y);
}
/* Message type */
Stream_Write_UINT16(s, MSG_AINPUT_MOUSE);
/* Event data */
Stream_Write_UINT64(s, time);
Stream_Write_UINT64(s, flags);
Stream_Write_INT32(s, x);
Stream_Write_INT32(s, y);
Stream_SealLength(s);
/* ainput back what we have received. AINPUT does not have any message IDs. */
WINPR_ASSERT(callback->channel);
WINPR_ASSERT(callback->channel->Write);
return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s),
NULL);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
free(callback);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
AINPUT_CHANNEL_CALLBACK* callback;
AINPUT_LISTENER_CALLBACK* listener_callback = (AINPUT_LISTENER_CALLBACK*)pListenerCallback;
WINPR_ASSERT(listener_callback);
WINPR_UNUSED(Data);
WINPR_UNUSED(pbAccept);
callback = (AINPUT_CHANNEL_CALLBACK*)calloc(1, sizeof(AINPUT_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = ainput_on_data_received;
callback->iface.OnClose = ainput_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = &callback->iface;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
WINPR_ASSERT(ainput);
if (ainput->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
ainput->listener_callback =
(AINPUT_LISTENER_CALLBACK*)calloc(1, sizeof(AINPUT_LISTENER_CALLBACK));
if (!ainput->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection;
ainput->listener_callback->plugin = pPlugin;
ainput->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0,
&ainput->listener_callback->iface, &ainput->listener);
ainput->listener->pInterface = ainput->iface.pInterface;
ainput->initialized = status == CHANNEL_RC_OK;
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
{
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
if (ainput && ainput->listener_callback)
{
IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, ainput->listener);
}
if (ainput)
{
free(ainput->listener_callback);
free(ainput->iface.pInterface);
}
free(ainput);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define DVCPluginEntry ainput_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 status = CHANNEL_RC_OK;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput");
if (!ainput)
{
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN));
if (!ainput || !context)
{
free(context);
free(ainput);
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
ainput->iface.Initialize = ainput_plugin_initialize;
ainput->iface.Terminated = ainput_plugin_terminated;
context->handle = (void*)ainput;
context->AInputSendInputEvent = ainput_send_input_event;
ainput->iface.pInterface = (void*)context;
status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface);
}
return status;
}

View File

@ -1,43 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Advanced Input Virtual Channel Extension
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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_AINPUT_CLIENT_MAIN_H
#define FREERDP_CHANNEL_AINPUT_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/log.h>
#define DVC_TAG CHANNELS_TAG("ainput.client")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__)
#else
#define DEBUG_DVC(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H */

View File

@ -1,59 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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_INT_AINPUT_COMMON_H
#define FREERDP_INT_AINPUT_COMMON_H
#include <winpr/string.h>
#include <freerdp/channels/ainput.h>
static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size)
{
char number[32] = { 0 };
if (flags & AINPUT_FLAGS_HAVE_REL)
winpr_str_append("AINPUT_FLAGS_HAVE_REL", buffer, size, "|");
if (flags & AINPUT_FLAGS_WHEEL)
winpr_str_append("AINPUT_FLAGS_WHEEL", buffer, size, "|");
if (flags & AINPUT_FLAGS_MOVE)
winpr_str_append("AINPUT_FLAGS_MOVE", buffer, size, "|");
if (flags & AINPUT_FLAGS_DOWN)
winpr_str_append("AINPUT_FLAGS_DOWN", buffer, size, "|");
if (flags & AINPUT_FLAGS_REL)
winpr_str_append("AINPUT_FLAGS_REL", buffer, size, "|");
if (flags & AINPUT_FLAGS_BUTTON1)
winpr_str_append("AINPUT_FLAGS_BUTTON1", buffer, size, "|");
if (flags & AINPUT_FLAGS_BUTTON2)
winpr_str_append("AINPUT_FLAGS_BUTTON2", buffer, size, "|");
if (flags & AINPUT_FLAGS_BUTTON3)
winpr_str_append("AINPUT_FLAGS_BUTTON3", buffer, size, "|");
if (flags & AINPUT_XFLAGS_BUTTON1)
winpr_str_append("AINPUT_XFLAGS_BUTTON1", buffer, size, "|");
if (flags & AINPUT_XFLAGS_BUTTON2)
winpr_str_append("AINPUT_XFLAGS_BUTTON2", buffer, size, "|");
_snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags);
winpr_str_append(number, buffer, size, " ");
return buffer;
}
#endif /* FREERDP_INT_AINPUT_COMMON_H */

View File

@ -1,27 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Armin Novak <anovak@thincast.com>
# Copyright 2022 Thincast Technologies GmbH
#
# 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("ainput")
set(${MODULE_PREFIX}_SRCS
ainput_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")

View File

@ -1,587 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Advanced Input Virtual Channel Extension
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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/assert.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include <winpr/stream.h>
#include <freerdp/server/ainput.h>
#include <freerdp/channels/ainput.h>
#include <freerdp/channels/log.h>
#include "../common/ainput_common.h"
#define TAG CHANNELS_TAG("ainput.server")
typedef enum
{
AINPUT_INITIAL,
AINPUT_OPENED,
AINPUT_VERSION_SENT,
} eAInputChannelState;
typedef struct
{
ainput_server_context context;
BOOL opened;
HANDLE stopEvent;
HANDLE thread;
void* ainput_channel;
DWORD SessionId;
BOOL isOpened;
BOOL externalThread;
/* Channel state */
eAInputChannelState state;
wStream* buffer;
} ainput_server;
static UINT ainput_server_context_poll(ainput_server_context* context);
static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle);
static UINT ainput_server_context_poll_int(ainput_server_context* context);
static BOOL ainput_server_is_open(ainput_server_context* context)
{
ainput_server* ainput = (ainput_server*)context;
WINPR_ASSERT(ainput);
return ainput->isOpened;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_server_open_channel(ainput_server* ainput)
{
DWORD Error;
HANDLE hEvent;
DWORD StartTick;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
WINPR_ASSERT(ainput);
if (WTSQuerySessionInformationA(ainput->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
ainput->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(ainput->context.vcm);
StartTick = GetTickCount();
while (ainput->ainput_channel == NULL)
{
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME,
WTS_CHANNEL_OPTION_DYNAMIC);
Error = GetLastError();
if (Error == ERROR_NOT_FOUND)
{
WLog_DBG(TAG, "Channel %s not found", AINPUT_DVC_CHANNEL_NAME);
break;
}
if (ainput->ainput_channel)
{
UINT32 channelId;
BOOL status = TRUE;
channelId = WTSChannelGetIdByHandle(ainput->ainput_channel);
IFCALLRET(ainput->context.ChannelIdAssigned, status, &ainput->context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
break;
}
if (GetTickCount() - StartTick > 5000)
{
WLog_WARN(TAG, "Timeout opening channel %s", AINPUT_DVC_CHANNEL_NAME);
break;
}
}
return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
}
static UINT ainput_server_send_version(ainput_server* ainput)
{
ULONG written;
wStream* s;
WINPR_ASSERT(ainput);
s = ainput->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
if (!Stream_EnsureCapacity(s, 10))
{
WLog_WARN(TAG, "[%s] out of memory", AINPUT_DVC_CHANNEL_NAME);
return ERROR_OUTOFMEMORY;
}
Stream_Write_UINT16(s, MSG_AINPUT_VERSION);
Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR); /* Version (4 bytes) */
Stream_Write_UINT32(s, AINPUT_VERSION_MINOR); /* Version (4 bytes) */
WINPR_ASSERT(Stream_GetPosition(s) <= ULONG_MAX);
if (!WTSVirtualChannelWrite(ainput->ainput_channel, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
return ERROR_INTERNAL_ERROR;
}
return CHANNEL_RC_OK;
}
static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s)
{
UINT error = CHANNEL_RC_OK;
UINT64 flags, time;
INT32 x, y;
char buffer[128] = { 0 };
WINPR_ASSERT(ainput);
WINPR_ASSERT(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
return ERROR_NO_DATA;
Stream_Read_UINT64(s, time);
Stream_Read_UINT64(s, flags);
Stream_Read_INT32(s, x);
Stream_Read_INT32(s, y);
WLog_VRB(TAG, "[%s] received: time=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32,
__FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y);
IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y);
return error;
}
static HANDLE ainput_server_get_channel_handle(ainput_server* ainput)
{
BYTE* buffer = NULL;
DWORD BytesReturned = 0;
HANDLE ChannelEvent = NULL;
WINPR_ASSERT(ainput);
if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
return ChannelEvent;
}
static DWORD WINAPI ainput_server_thread_func(LPVOID arg)
{
DWORD nCount;
HANDLE events[2] = { 0 };
ainput_server* ainput = (ainput_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
WINPR_ASSERT(ainput);
nCount = 0;
events[nCount++] = ainput->stopEvent;
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
{
switch (ainput->state)
{
case AINPUT_OPENED:
events[1] = ainput_server_get_channel_handle(ainput);
nCount = 2;
status = WaitForMultipleObjects(nCount, events, FALSE, 100);
switch (status)
{
case WAIT_TIMEOUT:
case WAIT_OBJECT_0 + 1:
case WAIT_OBJECT_0:
error = ainput_server_context_poll_int(&ainput->context);
break;
case WAIT_FAILED:
default:
WLog_WARN(TAG, "[%s] Wait for open failed", AINPUT_DVC_CHANNEL_NAME);
error = ERROR_INTERNAL_ERROR;
break;
}
break;
case AINPUT_VERSION_SENT:
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
switch (status)
{
case WAIT_TIMEOUT:
case WAIT_OBJECT_0 + 1:
case WAIT_OBJECT_0:
error = ainput_server_context_poll_int(&ainput->context);
break;
case WAIT_FAILED:
default:
WLog_WARN(TAG, "[%s] Wait for version failed", AINPUT_DVC_CHANNEL_NAME);
error = ERROR_INTERNAL_ERROR;
break;
}
break;
default:
error = ainput_server_context_poll_int(&ainput->context);
break;
}
}
WTSVirtualChannelClose(ainput->ainput_channel);
ainput->ainput_channel = NULL;
if (error && ainput->context.rdpcontext)
setChannelError(ainput->context.rdpcontext, error,
"ainput_server_thread_func reported an error");
ExitThread(error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_server_open(ainput_server_context* context)
{
ainput_server* ainput = (ainput_server*)context;
WINPR_ASSERT(ainput);
if (!ainput->externalThread && (ainput->thread == NULL))
{
ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ainput->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
return ERROR_INTERNAL_ERROR;
}
ainput->thread = CreateThread(NULL, 0, ainput_server_thread_func, ainput, 0, NULL);
if (!ainput->thread)
{
WLog_ERR(TAG, "CreateEvent failed!");
CloseHandle(ainput->stopEvent);
ainput->stopEvent = NULL;
return ERROR_INTERNAL_ERROR;
}
}
ainput->isOpened = TRUE;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_server_close(ainput_server_context* context)
{
UINT error = CHANNEL_RC_OK;
ainput_server* ainput = (ainput_server*)context;
WINPR_ASSERT(ainput);
if (!ainput->externalThread && ainput->thread)
{
SetEvent(ainput->stopEvent);
if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(ainput->thread);
CloseHandle(ainput->stopEvent);
ainput->thread = NULL;
ainput->stopEvent = NULL;
}
if (ainput->externalThread)
{
if (ainput->state != AINPUT_INITIAL)
{
WTSVirtualChannelClose(ainput->ainput_channel);
ainput->ainput_channel = NULL;
ainput->state = AINPUT_INITIAL;
}
}
ainput->isOpened = FALSE;
return error;
}
static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread)
{
UINT error = CHANNEL_RC_OK;
ainput_server* ainput = (ainput_server*)context;
WINPR_ASSERT(ainput);
if (ainput->isOpened)
{
WLog_WARN(TAG, "Application error: AINPUT channel already initialized, calling in this "
"state is not possible!");
return ERROR_INVALID_STATE;
}
ainput->externalThread = externalThread;
return error;
}
ainput_server_context* ainput_server_context_new(HANDLE vcm)
{
ainput_server* ainput = (ainput_server*)calloc(1, sizeof(ainput_server));
if (!ainput)
return NULL;
ainput->context.vcm = vcm;
ainput->context.Open = ainput_server_open;
ainput->context.IsOpen = ainput_server_is_open;
ainput->context.Close = ainput_server_close;
ainput->context.Initialize = ainput_server_initialize;
ainput->context.Poll = ainput_server_context_poll;
ainput->context.ChannelHandle = ainput_server_context_handle;
ainput->buffer = Stream_New(NULL, 4096);
if (!ainput->buffer)
goto fail;
return &ainput->context;
fail:
ainput_server_context_free(ainput);
return NULL;
}
void ainput_server_context_free(ainput_server_context* context)
{
ainput_server* ainput = (ainput_server*)context;
if (ainput)
{
ainput_server_close(context);
Stream_Free(ainput->buffer, TRUE);
}
free(ainput);
}
static UINT ainput_process_message(ainput_server* ainput)
{
BOOL rc;
UINT error = ERROR_INTERNAL_ERROR;
ULONG BytesReturned, ActualBytesReturned;
UINT16 MessageId;
wStream* s;
WINPR_ASSERT(ainput);
WINPR_ASSERT(ainput->ainput_channel);
s = ainput->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned);
if (!rc)
goto out;
if (BytesReturned < 2)
{
error = CHANNEL_RC_OK;
goto out;
}
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
error = CHANNEL_RC_NO_MEMORY;
goto out;
}
if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &ActualBytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
goto out;
}
if (BytesReturned != ActualBytesReturned)
{
WLog_ERR(TAG, "WTSVirtualChannelRead size mismatch %" PRId32 ", expected %" PRId32,
ActualBytesReturned, BytesReturned);
goto out;
}
Stream_SetLength(s, ActualBytesReturned);
Stream_Read_UINT16(s, MessageId);
switch (MessageId)
{
case MSG_AINPUT_MOUSE:
error = ainput_server_recv_mouse_event(ainput, s);
break;
default:
WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId);
break;
}
out:
if (error)
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
return error;
}
BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle)
{
ainput_server* ainput = (ainput_server*)context;
WINPR_ASSERT(ainput);
WINPR_ASSERT(handle);
if (!ainput->externalThread)
{
WLog_WARN(TAG, "[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME);
return FALSE;
}
if (ainput->state == AINPUT_INITIAL)
{
WLog_WARN(TAG, "[%s] state fail!", AINPUT_DVC_CHANNEL_NAME);
return FALSE;
}
*handle = ainput_server_get_channel_handle(ainput);
return TRUE;
}
UINT ainput_server_context_poll_int(ainput_server_context* context)
{
ainput_server* ainput = (ainput_server*)context;
UINT error = ERROR_INTERNAL_ERROR;
WINPR_ASSERT(ainput);
switch (ainput->state)
{
case AINPUT_INITIAL:
error = ainput_server_open_channel(ainput);
if (error)
WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error);
else
ainput->state = AINPUT_OPENED;
break;
case AINPUT_OPENED:
{
BYTE* buffer = NULL;
DWORD BytesReturned = 0;
if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer,
&BytesReturned) != TRUE)
{
WLog_ERR(TAG, "WTSVirtualChannelReady failed,");
}
else
{
if (*buffer != 0)
{
error = ainput_server_send_version(ainput);
if (error)
WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!",
error);
else
ainput->state = AINPUT_VERSION_SENT;
}
else
error = CHANNEL_RC_OK;
}
WTSFreeMemory(buffer);
}
break;
case AINPUT_VERSION_SENT:
error = ainput_process_message(ainput);
break;
default:
WLog_ERR(TAG, "AINPUT chanel is in invalid state %d", ainput->state);
break;
}
return error;
}
UINT ainput_server_context_poll(ainput_server_context* context)
{
ainput_server* ainput = (ainput_server*)context;
WINPR_ASSERT(ainput);
if (!ainput->externalThread)
{
WLog_WARN(TAG, "[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME);
return ERROR_INTERNAL_ERROR;
}
return ainput_server_context_poll_int(context);
}

View File

@ -242,6 +242,10 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, const AUDIO_FORMAT
break;
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
return TRUE;
default:
return FALSE;
}

View File

@ -43,18 +43,13 @@
#include "audin_main.h"
#define SNDIN_VERSION 0x02
enum
{
MSG_SNDIN_VERSION = 0x01,
MSG_SNDIN_FORMATS = 0x02,
MSG_SNDIN_OPEN = 0x03,
MSG_SNDIN_OPEN_REPLY = 0x04,
MSG_SNDIN_DATA_INCOMING = 0x05,
MSG_SNDIN_DATA = 0x06,
MSG_SNDIN_FORMATCHANGE = 0x07
} MSG_SNDIN_CMD;
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
#define MSG_SNDIN_OPEN_REPLY 0x04
#define MSG_SNDIN_DATA_INCOMING 0x05
#define MSG_SNDIN_DATA 0x06
#define MSG_SNDIN_FORMATCHANGE 0x07
typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK;
struct _AUDIN_LISTENER_CALLBACK
@ -110,7 +105,6 @@ struct _AUDIN_PLUGIN
IWTSListener* listener;
BOOL initialized;
UINT32 version;
};
static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args);
@ -144,7 +138,7 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre
static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
{
wStream* out;
const UINT32 ClientVersion = SNDIN_VERSION;
const UINT32 ClientVersion = 0x01;
UINT32 ServerVersion;
if (Stream_GetRemainingLength(s) < 4)
@ -155,7 +149,7 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c
ServerVersion, ClientVersion);
/* Do not answer server packet, we do not support the channel version. */
if (ServerVersion > ClientVersion)
if (ServerVersion != ClientVersion)
{
WLog_Print(audin->log, WLOG_WARN,
"Incompatible channel version server=%" PRIu32
@ -163,7 +157,6 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c
ServerVersion, ClientVersion);
return CHANNEL_RC_OK;
}
audin->version = ServerVersion;
out = Stream_New(NULL, 5);
@ -451,8 +444,11 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb
return FALSE;
}
if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
return FALSE;
if (!supported)
{
if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
return FALSE;
}
IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback);

View File

@ -154,16 +154,12 @@ static UINT audin_mac_set_format(IAudinDevice *device, const AUDIO_FORMAT *forma
if (format->wBitsPerSample == 0)
mac->audioFormat.mBitsPerChannel = 16;
mac->audioFormat.mBytesPerFrame = 0;
mac->audioFormat.mBytesPerPacket = 0;
mac->audioFormat.mChannelsPerFrame = mac->format.nChannels;
mac->audioFormat.mFramesPerPacket = 1;
mac->audioFormat.mBytesPerFrame =
mac->audioFormat.mChannelsPerFrame * (mac->audioFormat.mBitsPerChannel / 8);
mac->audioFormat.mBytesPerPacket =
mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket;
mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format);
mac->audioFormat.mFormatID = audin_mac_get_format(format);
mac->audioFormat.mFramesPerPacket = 1;
mac->audioFormat.mReserved = 0;
mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec;
return CHANNEL_RC_OK;
@ -424,40 +420,33 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
goto error_out;
}
#if defined(MAC_OS_X_VERSION_10_14)
if (@available(macOS 10.14, *))
AVAuthorizationStatus status =
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status)
{
@autoreleasepool {
AVAuthorizationStatus status =
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status)
{
case AVAuthorizationStatusAuthorized:
mac->isAuthorized = TRUE;
break;
case AVAuthorizationStatusNotDetermined:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(BOOL granted) {
if (granted == YES)
{
mac->isAuthorized = TRUE;
}
else
WLog_WARN(TAG, "Microphone access denied by user");
}];
break;
case AVAuthorizationStatusRestricted:
WLog_WARN(TAG, "Microphone access restricted by policy");
break;
case AVAuthorizationStatusDenied:
WLog_WARN(TAG, "Microphone access denied by policy");
break;
default:
break;
}
}
case AVAuthorizationStatusAuthorized:
mac->isAuthorized = TRUE;
break;
case AVAuthorizationStatusNotDetermined:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(BOOL granted) {
if (granted == YES)
{
mac->isAuthorized = TRUE;
}
else
WLog_WARN(TAG, "Microphone access denied by user");
}];
break;
case AVAuthorizationStatusRestricted:
WLog_WARN(TAG, "Microphone access restricted by policy");
break;
case AVAuthorizationStatusDenied:
WLog_WARN(TAG, "Microphone access denied by policy");
break;
default:
break;
}
#endif
return CHANNEL_RC_OK;
error_out:

View File

@ -215,7 +215,7 @@ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, void
opensles->user_data = user_data;
return CHANNEL_RC_OK;
error_out:
audin_opensles_close(device);
audin_opensles_close(opensles);
return ERROR_INTERNAL_ERROR;
}
@ -248,7 +248,7 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, ADDIN_A
{
UINT status;
DWORD flags;
const COMMAND_LINE_ARGUMENT_A* arg;
COMMAND_LINE_ARGUMENT_A* arg;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = {
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL,

View File

@ -113,6 +113,10 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, const AUDIO_FORMAT*
break;
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
return TRUE;
default:
return FALSE;
}

View File

@ -236,6 +236,17 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMA
break;
case WAVE_FORMAT_ALAW: /* A-LAW */
case WAVE_FORMAT_MULAW: /* U-LAW */
if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) &&
(format->wBitsPerSample == 8) &&
(format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
{
return TRUE;
}
break;
default:
return FALSE;
}

View File

@ -110,74 +110,27 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance
setChannelError(winmm->rdpcontext, error, "waveInProc reported an error");
}
static BOOL log_mmresult(AudinWinmmDevice* winmm, const char* what, MMRESULT result)
{
if (result != MMSYSERR_NOERROR)
{
CHAR buffer[8192] = { 0 };
CHAR msg[8192] = { 0 };
CHAR cmsg[8192] = { 0 };
waveInGetErrorTextA(result, buffer, sizeof(buffer));
_snprintf(msg, sizeof(msg) - 1, "%s failed. %" PRIu32 " [%s]", what, result, buffer);
_snprintf(cmsg, sizeof(cmsg) - 1, "audin_winmm_thread_func reported an error '%s'", msg);
WLog_Print(winmm->log, WLOG_DEBUG, "%s", msg);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, cmsg);
return FALSE;
}
return TRUE;
}
static BOOL test_format_supported(const PWAVEFORMATEX pwfx)
{
MMRESULT rc;
WAVEINCAPSA caps = { 0 };
rc = waveInGetDevCapsA(WAVE_MAPPER, &caps, sizeof(caps));
if (rc != MMSYSERR_NOERROR)
return FALSE;
switch (pwfx->nChannels)
{
case 1:
if ((caps.dwFormats &
(WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08 |
WAVE_FORMAT_1M16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_96M16)) == 0)
return FALSE;
break;
case 2:
if ((caps.dwFormats &
(WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08 |
WAVE_FORMAT_1S16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_96S16)) == 0)
return FALSE;
break;
default:
return FALSE;
}
rc = waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0,
WAVE_FORMAT_QUERY | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE);
return (rc == MMSYSERR_NOERROR);
}
static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
{
AudinWinmmDevice* winmm = (AudinWinmmDevice*)arg;
char* buffer;
int size, i;
WAVEHDR waveHdr[4] = { 0 };
WAVEHDR waveHdr[4];
DWORD status;
MMRESULT rc;
if (!winmm->hWaveIn)
{
MMRESULT rc;
rc = waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, (DWORD_PTR)waveInProc,
(DWORD_PTR)winmm,
CALLBACK_FUNCTION | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE);
if (!log_mmresult(winmm, "waveInOpen", rc))
if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur,
(DWORD_PTR)waveInProc, (DWORD_PTR)winmm,
CALLBACK_FUNCTION))
{
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
return ERROR_INTERNAL_ERROR;
}
}
size =
@ -197,22 +150,36 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
waveHdr[i].lpData = buffer;
rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
if (!log_mmresult(winmm, "waveInPrepareHeader", rc))
if (MMSYSERR_NOERROR != rc)
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInPrepareHeader failed. %" PRIu32 "", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
rc = waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
if (!log_mmresult(winmm, "waveInAddBuffer", rc))
if (MMSYSERR_NOERROR != rc)
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInAddBuffer failed. %" PRIu32 "", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
}
rc = waveInStart(winmm->hWaveIn);
if (!log_mmresult(winmm, "waveInStart", rc))
if (MMSYSERR_NOERROR != rc)
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInStart failed. %" PRIu32 "", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
status = WaitForSingleObject(winmm->stopEvent, INFINITE);
@ -228,17 +195,26 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
rc = waveInReset(winmm->hWaveIn);
if (!log_mmresult(winmm, "waveInReset", rc))
if (MMSYSERR_NOERROR != rc)
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInReset failed. %" PRIu32 "", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
for (i = 0; i < 4; i++)
{
rc = waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
if (!log_mmresult(winmm, "waveInUnprepareHeader", rc))
if (MMSYSERR_NOERROR != rc)
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInUnprepareHeader failed. %" PRIu32 "", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
free(waveHdr[i].lpData);
@ -246,8 +222,13 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
rc = waveInClose(winmm->hWaveIn);
if (!log_mmresult(winmm, "waveInClose", rc))
if (MMSYSERR_NOERROR != rc)
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInClose failed. %" PRIu32 "", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
winmm->hWaveIn = NULL;
@ -330,32 +311,16 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for
for (i = 0; i < winmm->cFormats; i++)
{
const PWAVEFORMATEX ppwfx = winmm->ppwfx[i];
if ((ppwfx->wFormatTag == format->wFormatTag) && (ppwfx->nChannels == format->nChannels) &&
(ppwfx->wBitsPerSample == format->wBitsPerSample) &&
(ppwfx->nSamplesPerSec == format->nSamplesPerSec))
if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag &&
winmm->ppwfx[i]->nChannels == format->nChannels &&
winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample)
{
/* BUG: Many devices report to support stereo recording but fail here.
* Ensure we always use mono. */
if (ppwfx->nChannels > 1)
{
ppwfx->nChannels = 1;
}
if (ppwfx->nBlockAlign != 2)
{
ppwfx->nBlockAlign = 2;
ppwfx->nAvgBytesPerSec = ppwfx->nSamplesPerSec * ppwfx->nBlockAlign;
}
if (!test_format_supported(ppwfx))
return ERROR_INVALID_PARAMETER;
winmm->pwfx_cur = ppwfx;
return CHANNEL_RC_OK;
winmm->pwfx_cur = winmm->ppwfx[i];
break;
}
}
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK;
}
static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
@ -367,9 +332,6 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMA
if (!winmm || !format)
return FALSE;
if (format->wFormatTag != WAVE_FORMAT_PCM)
return FALSE;
pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize);
if (!pwfx)
@ -384,27 +346,29 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMA
data = (BYTE*)pwfx + sizeof(WAVEFORMATEX);
memcpy(data, format->data, format->cbSize);
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
if (!test_format_supported(pwfx))
goto fail;
if (winmm->cFormats >= winmm->ppwfx_size)
if (pwfx->wFormatTag == WAVE_FORMAT_PCM)
{
PWAVEFORMATEX* tmp_ppwfx;
tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2);
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
if (!tmp_ppwfx)
goto fail;
if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY))
{
if (winmm->cFormats >= winmm->ppwfx_size)
{
PWAVEFORMATEX* tmp_ppwfx;
tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2);
winmm->ppwfx_size *= 2;
winmm->ppwfx = tmp_ppwfx;
if (!tmp_ppwfx)
return FALSE;
winmm->ppwfx_size *= 2;
winmm->ppwfx = tmp_ppwfx;
}
winmm->ppwfx[winmm->cFormats++] = pwfx;
return TRUE;
}
}
winmm->ppwfx[winmm->cFormats++] = pwfx;
return TRUE;
fail:
free(pwfx);
return FALSE;
}
@ -543,7 +507,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
}
winmm->ppwfx_size = 10;
winmm->ppwfx = calloc(winmm->ppwfx_size, sizeof(PWAVEFORMATEX));
winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size);
if (!winmm->ppwfx)
{
@ -552,7 +516,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
goto error_out;
}
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, &winmm->iface)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)winmm)))
{
WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!",
error);

View File

@ -162,6 +162,9 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s)
for (i = 0; i < audin->context.num_server_formats; i++)
{
AUDIO_FORMAT format = audin->context.server_formats[i];
// TODO: Eliminate this
format.nAvgBytesPerSec =
format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8;
if (!audio_format_write(s, &format))
{
@ -557,8 +560,6 @@ static BOOL audin_server_open(audin_server_context* context)
PULONG pSessionId = NULL;
DWORD BytesReturned = 0;
audin->SessionId = WTS_CURRENT_SESSION;
UINT32 channelId;
BOOL status = TRUE;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned))
@ -576,15 +577,6 @@ static BOOL audin_server_open(audin_server_context* context)
return FALSE;
}
channelId = WTSChannelGetIdByHandle(audin->audin_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
{
WLog_ERR(TAG, "CreateEvent failed!");

View File

@ -231,8 +231,10 @@ static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCS
do
{
BOOL used = FALSE;
FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
char* p[5];
FREERDP_ADDIN* pAddin;
nDashes = 0;
pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
if (!pAddin)
{
@ -240,116 +242,57 @@ static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCS
goto error_out;
}
nDashes = 0;
for (index = 0; FindData.cFileName[index]; index++)
nDashes += (FindData.cFileName[index] == '-') ? 1 : 0;
if (nDashes == 1)
{
size_t len;
char* p[2] = { 0 };
/* <name>-client.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
len = p[1] - p[0];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
ppAddins[nAddins++] = pAddin;
used = TRUE;
}
else if (nDashes == 2)
{
size_t len;
char* p[4] = { 0 };
/* <name>-client-<subsystem>.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
p[2] = strchr(p[1], '-') + 1;
p[3] = strchr(p[2], '.') + 1;
len = p[1] - p[0];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
len = p[3] - p[2];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
ppAddins[nAddins++] = pAddin;
used = TRUE;
}
else if (nDashes == 3)
{
size_t len;
char* p[5] = { 0 };
/* <name>-client-<subsystem>-<type>.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
p[2] = strchr(p[1], '-') + 1;
p[3] = strchr(p[2], '-') + 1;
p[4] = strchr(p[3], '.') + 1;
len = p[1] - p[0];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
len = p[3] - p[2];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
len = p[4] - p[3];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cType, p[3], MIN(ARRAYSIZE(pAddin->cType), len - 1));
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
strncpy(pAddin->cType, p[3], (p[4] - p[3]) - 1);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
pAddin->dwFlags |= FREERDP_ADDIN_TYPE;
ppAddins[nAddins++] = pAddin;
used = TRUE;
}
skip:
if (!used)
else
{
free(pAddin);
}
} while (FindNextFileA(hFind, &FindData));
FindClose(hFind);

View File

@ -173,3 +173,198 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
return error;
}
static UINT64 filetime_to_uint64(FILETIME value)
{
UINT64 converted = 0;
converted |= (UINT32)value.dwHighDateTime;
converted <<= 32;
converted |= (UINT32)value.dwLowDateTime;
return converted;
}
static FILETIME uint64_to_filetime(UINT64 value)
{
FILETIME converted;
converted.dwLowDateTime = (UINT32)(value >> 0);
converted.dwHighDateTime = (UINT32)(value >> 32);
return converted;
}
#define CLIPRDR_FILEDESCRIPTOR_SIZE (4 + 32 + 4 + 16 + 8 + 8 + 520)
/**
* Parse a packed file list.
*
* The resulting array must be freed with the `free()` function.
*
* @param [in] format_data packed `CLIPRDR_FILELIST` to parse.
* @param [in] format_data_length length of `format_data` in bytes.
* @param [out] file_descriptor_array parsed array of `FILEDESCRIPTOR` structs.
* @param [out] file_descriptor_count number of elements in `file_descriptor_array`.
*
* @returns 0 on success, otherwise a Win32 error code.
*/
UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length,
FILEDESCRIPTORW** file_descriptor_array, UINT32* file_descriptor_count)
{
UINT result = NO_ERROR;
UINT32 i;
UINT32 count = 0;
wStream* s = NULL;
if (!format_data || !file_descriptor_array || !file_descriptor_count)
return ERROR_BAD_ARGUMENTS;
s = Stream_New((BYTE*)format_data, format_data_length);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "invalid packed file list");
result = ERROR_INCORRECT_SIZE;
goto out;
}
Stream_Read_UINT32(s, count); /* cItems (4 bytes) */
if (Stream_GetRemainingLength(s) / CLIPRDR_FILEDESCRIPTOR_SIZE < count)
{
WLog_ERR(TAG, "packed file list is too short: expected %" PRIuz ", have %" PRIuz,
((size_t)count) * CLIPRDR_FILEDESCRIPTOR_SIZE, Stream_GetRemainingLength(s));
result = ERROR_INCORRECT_SIZE;
goto out;
}
*file_descriptor_count = count;
*file_descriptor_array = calloc(count, sizeof(FILEDESCRIPTORW));
if (!*file_descriptor_array)
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto out;
}
for (i = 0; i < count; i++)
{
int c;
UINT64 lastWriteTime;
FILEDESCRIPTORW* file = &((*file_descriptor_array)[i]);
Stream_Read_UINT32(s, file->dwFlags); /* flags (4 bytes) */
Stream_Seek(s, 32); /* reserved1 (32 bytes) */
Stream_Read_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */
Stream_Seek(s, 16); /* reserved2 (16 bytes) */
Stream_Read_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */
file->ftLastWriteTime = uint64_to_filetime(lastWriteTime);
Stream_Read_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */
Stream_Read_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */
for (c = 0; c < 260; c++) /* cFileName (520 bytes) */
Stream_Read_UINT16(s, file->cFileName[c]);
}
if (Stream_GetRemainingLength(s) > 0)
WLog_WARN(TAG, "packed file list has %" PRIuz " excess bytes",
Stream_GetRemainingLength(s));
out:
Stream_Free(s, FALSE);
return result;
}
#define CLIPRDR_MAX_FILE_SIZE (2U * 1024 * 1024 * 1024)
/**
* Serialize a packed file list.
*
* The resulting format data must be freed with the `free()` function.
*
* @param [in] file_descriptor_array array of `FILEDESCRIPTOR` structs to serialize.
* @param [in] file_descriptor_count number of elements in `file_descriptor_array`.
* @param [out] format_data serialized CLIPRDR_FILELIST.
* @param [out] format_data_length length of `format_data` in bytes.
*
* @returns 0 on success, otherwise a Win32 error code.
*/
UINT cliprdr_serialize_file_list(const FILEDESCRIPTORW* file_descriptor_array,
UINT32 file_descriptor_count, BYTE** format_data,
UINT32* format_data_length)
{
return cliprdr_serialize_file_list_ex(CB_STREAM_FILECLIP_ENABLED, file_descriptor_array,
file_descriptor_count, format_data, format_data_length);
}
UINT cliprdr_serialize_file_list_ex(UINT32 flags, const FILEDESCRIPTORW* file_descriptor_array,
UINT32 file_descriptor_count, BYTE** format_data,
UINT32* format_data_length)
{
UINT result = NO_ERROR;
UINT32 i;
wStream* s = NULL;
if (!file_descriptor_array || !format_data || !format_data_length)
return ERROR_BAD_ARGUMENTS;
if ((flags & CB_STREAM_FILECLIP_ENABLED) == 0)
{
WLog_WARN(TAG, "No file clipboard support annouonced!");
return ERROR_BAD_ARGUMENTS;
}
s = Stream_New(NULL, 4 + file_descriptor_count * CLIPRDR_FILEDESCRIPTOR_SIZE);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT32(s, file_descriptor_count); /* cItems (4 bytes) */
for (i = 0; i < file_descriptor_count; i++)
{
int c;
UINT64 lastWriteTime;
const FILEDESCRIPTORW* file = &file_descriptor_array[i];
/*
* There is a known issue with Windows server getting stuck in
* an infinite loop when downloading files that are larger than
* 2 gigabytes. Do not allow clients to send such file lists.
*
* https://support.microsoft.com/en-us/help/2258090
*/
if ((flags & CB_HUGE_FILE_SUPPORT_ENABLED) == 0)
{
if ((file->nFileSizeHigh > 0) || (file->nFileSizeLow >= CLIPRDR_MAX_FILE_SIZE))
{
WLog_ERR(TAG, "cliprdr does not support files over 2 GB");
result = ERROR_FILE_TOO_LARGE;
goto error;
}
}
Stream_Write_UINT32(s, file->dwFlags); /* flags (4 bytes) */
Stream_Zero(s, 32); /* reserved1 (32 bytes) */
Stream_Write_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */
Stream_Zero(s, 16); /* reserved2 (16 bytes) */
lastWriteTime = filetime_to_uint64(file->ftLastWriteTime);
Stream_Write_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */
Stream_Write_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */
Stream_Write_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */
for (c = 0; c < 260; c++) /* cFileName (520 bytes) */
Stream_Write_UINT16(s, file->cFileName[c]);
}
Stream_SealLength(s);
Stream_GetBuffer(s, *format_data);
Stream_GetLength(s, *format_data_length);
Stream_Free(s, FALSE);
return result;
error:
Stream_Free(s, TRUE);
return result;
}

View File

@ -138,7 +138,7 @@ cliprdr_packet_unlock_clipdata_new(const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockCl
if (!unlockClipboardData)
return NULL;
s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4);
s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4);
if (!s)
return NULL;

View File

@ -58,7 +58,7 @@ static wStream* disp_server_single_packet_new(UINT32 type, UINT32 length)
}
header.type = type;
header.length = DISPLAY_CONTROL_HEADER_LENGTH + length;
header.length = length;
if ((error = disp_write_header(s, &header)))
{
@ -72,24 +72,6 @@ error:
return NULL;
}
static void disp_server_sanitize_monitor_layout(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor)
{
if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH ||
monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH ||
monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT ||
monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT)
{
if (monitor->PhysicalWidth != 0 || monitor->PhysicalHeight != 0)
WLog_DBG(
TAG,
"Sanitizing invalid physical monitor size. Old physical monitor size: [%" PRIu32
", %" PRIu32 "]",
monitor->PhysicalWidth, monitor->PhysicalHeight);
monitor->PhysicalWidth = monitor->PhysicalHeight = 0;
}
}
static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor)
{
if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH ||
@ -106,6 +88,22 @@ static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT*
return FALSE;
}
if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH ||
monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH)
{
WLog_WARN(TAG, "Received invalid value for monitor->PhysicalWidth: %" PRIu32 "",
monitor->PhysicalWidth);
return FALSE;
}
if (monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT ||
monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT)
{
WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "",
monitor->PhysicalHeight);
return FALSE;
}
switch (monitor->Orientation)
{
case ORIENTATION_LANDSCAPE:
@ -185,8 +183,6 @@ static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerC
Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */
Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
disp_server_sanitize_monitor_layout(monitor);
WLog_DBG(TAG,
"\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32
"x%" PRIu32 ")",
@ -378,8 +374,6 @@ static UINT disp_server_open(DispServerContext* context)
void* buffer;
buffer = NULL;
priv->SessionId = WTS_CURRENT_SESSION;
UINT32 channelId;
BOOL status = TRUE;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
@ -401,16 +395,6 @@ static UINT disp_server_open(DispServerContext* context)
goto out_close;
}
channelId = WTSChannelGetIdByHandle(priv->disp_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
rc = ERROR_INTERNAL_ERROR;
goto out_close;
}
/* Query for channel event handle */
if (!WTSVirtualChannelQuery(priv->disp_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) ||

View File

@ -61,14 +61,10 @@
} while (0)
#endif
static BOOL drive_file_fix_path(WCHAR* path, size_t length)
static void drive_file_fix_path(WCHAR* path)
{
size_t i;
if ((length == 0) || (length > UINT32_MAX))
return FALSE;
WINPR_ASSERT(path);
size_t length = _wcslen(path);
for (i = 0; i < length; i++)
{
@ -79,82 +75,58 @@ static BOOL drive_file_fix_path(WCHAR* path, size_t length)
#ifdef WIN32
if ((length == 3) && (path[1] == L':') && (path[2] == L'/'))
return FALSE;
return;
#else
if ((length == 1) && (path[0] == L'/'))
return FALSE;
return;
#endif
if ((length > 0) && (path[length - 1] == L'/'))
path[length - 1] = L'\0';
return TRUE;
}
static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
size_t PathWCharLength)
size_t PathLength)
{
BOOL ok = FALSE;
WCHAR* fullpath = NULL;
size_t length;
WCHAR* fullpath;
size_t base_path_length;
if (!base_path || (!path && (PathWCharLength > 0)))
goto fail;
if (!base_path || (!path && (PathLength > 0)))
return NULL;
const size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
length = base_path_length + PathWCharLength + 1;
fullpath = (WCHAR*)calloc(length, sizeof(WCHAR));
base_path_length = _wcslen(base_path) * 2;
fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR));
if (!fullpath)
goto fail;
{
WLog_ERR(TAG, "malloc failed!");
return NULL;
}
CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR));
CopyMemory(fullpath, base_path, base_path_length);
if (path)
CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR));
if (!drive_file_fix_path(fullpath, length))
goto fail;
/* Ensure the path does not contain sequences like '..' */
const WCHAR dotdot[] = { '.', '.', '\0' };
if (_wcsstr(&fullpath[base_path_length], dotdot))
{
char abuffer[MAX_PATH] = { 0 };
ConvertFromUnicode(CP_UTF8, 0, &fullpath[base_path_length], -1, (char**)&abuffer,
ARRAYSIZE(abuffer) - 1, NULL, NULL);
WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!",
&abuffer[base_path_length]);
goto fail;
}
ok = TRUE;
fail:
if (!ok)
{
free(fullpath);
fullpath = NULL;
}
CopyMemory((char*)fullpath + base_path_length, path, PathLength);
drive_file_fix_path(fullpath);
return fullpath;
}
static BOOL drive_file_remove_dir(const WCHAR* path)
{
WIN32_FIND_DATAW findFileData = { 0 };
WIN32_FIND_DATAW findFileData;
BOOL ret = TRUE;
HANDLE dir = INVALID_HANDLE_VALUE;
WCHAR* fullpath = NULL;
WCHAR* path_slash = NULL;
size_t base_path_length = 0;
HANDLE dir;
WCHAR* fullpath;
WCHAR* path_slash;
size_t base_path_length;
if (!path)
return FALSE;
base_path_length = _wcslen(path);
path_slash = (WCHAR*)calloc(base_path_length + 3, sizeof(WCHAR));
base_path_length = _wcslen(path) * 2;
path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3);
if (!path_slash)
{
@ -162,11 +134,12 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
return FALSE;
}
CopyMemory(path_slash, path, base_path_length * sizeof(WCHAR));
path_slash[base_path_length] = L'/';
path_slash[base_path_length + 1] = L'*';
CopyMemory(path_slash, path, base_path_length);
path_slash[base_path_length / 2] = L'/';
path_slash[base_path_length / 2 + 1] = L'*';
DEBUG_WSTR("Search in %s", path_slash);
dir = FindFirstFileW(path_slash, &findFileData);
path_slash[base_path_length / 2 + 1] = 0;
if (dir == INVALID_HANDLE_VALUE)
{
@ -176,7 +149,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
do
{
const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
size_t len = _wcslen(findFileData.cFileName);
if ((len == 1 && findFileData.cFileName[0] == L'.') ||
(len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.'))
@ -184,7 +157,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
continue;
}
fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len);
fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2);
DEBUG_WSTR("Delete %s", fullpath);
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@ -360,13 +333,13 @@ static BOOL drive_file_init(DRIVE_FILE* file)
return file->file_handle != INVALID_HANDLE_VALUE;
}
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength,
UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition,
UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id,
UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions,
UINT32 FileAttributes, UINT32 SharedAccess)
{
DRIVE_FILE* file;
if (!base_path || (!path && (PathWCharLength > 0)))
if (!base_path || (!path && (PathLength > 0)))
return NULL;
file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE));
@ -386,7 +359,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat
file->CreateDisposition = CreateDisposition;
file->CreateOptions = CreateOptions;
file->SharedAccess = SharedAccess;
drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength));
drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength));
if (!drive_file_init(file))
{
@ -741,10 +714,13 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
return FALSE;
fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input),
FileNameLength / sizeof(WCHAR));
FileNameLength);
if (!fullpath)
{
WLog_ERR(TAG, "drive_file_combine_fullpath failed!");
return FALSE;
}
#ifdef _WIN32
@ -783,7 +759,7 @@ 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 PathWCharLength, wStream* output)
const WCHAR* path, UINT32 PathLength, wStream* output)
{
size_t length;
WCHAR* ent_path;
@ -797,7 +773,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
if (file->find_handle != INVALID_HANDLE_VALUE)
FindClose(file->find_handle);
ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength);
/* open new search handle and retrieve the first entry */
file->find_handle = FindFirstFileW(ent_path, &file->find_data);
free(ent_path);

View File

@ -51,9 +51,9 @@ struct _DRIVE_FILE
UINT32 CreateOptions;
};
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength,
UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition,
UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess);
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id,
UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions,
UINT32 FileAttributes, UINT32 SharedAccess);
BOOL drive_file_free(DRIVE_FILE* file);
BOOL drive_file_open(DRIVE_FILE* file);
@ -64,6 +64,6 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
wStream* input);
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
const WCHAR* path, UINT32 PathWCharLength, wStream* output);
const WCHAR* path, UINT32 PathLength, wStream* output);
#endif /* FREERDP_CHANNEL_DRIVE_FILE_H */

View File

@ -184,8 +184,8 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
path = (const WCHAR*)Stream_Pointer(irp->input);
FileId = irp->devman->id_sequence++;
file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess,
CreateDisposition, CreateOptions, FileAttributes, SharedAccess);
file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition,
CreateOptions, FileAttributes, SharedAccess);
if (!file)
{
@ -629,9 +629,6 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
Stream_Read_UINT32(irp->input, PathLength);
Stream_Seek(irp->input, 23); /* Padding */
path = (WCHAR*)Stream_Pointer(irp->input);
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
return ERROR_INVALID_DATA;
file = drive_get_file_by_id(drive, irp->FileId);
if (file == NULL)
@ -639,8 +636,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
irp->IoStatus = STATUS_UNSUCCESSFUL;
Stream_Write_UINT32(irp->output, 0); /* Length */
}
else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path,
PathLength / sizeof(WCHAR), irp->output))
else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength,
irp->output))
{
irp->IoStatus = drive_map_windows_err(GetLastError());
}

View File

@ -91,21 +91,7 @@ static UINT echo_server_open_channel(echo_server* echo)
WTSVirtualChannelOpenEx(echo->SessionId, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC);
if (echo->echo_channel)
{
UINT32 channelId;
BOOL status = TRUE;
channelId = WTSChannelGetIdByHandle(echo->echo_channel);
IFCALLRET(echo->context.ChannelIdAssigned, status, &echo->context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
break;
}
Error = GetLastError();

View File

@ -25,10 +25,9 @@ include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
if (NOT BUILTIN_CHANNELS OR NOT BUILD_SHARED_LIBS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client)
endif()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -159,7 +159,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
buffer = (BYTE*)calloc(Length, sizeof(BYTE));
buffer = (BYTE*)malloc(Length);
if (!buffer)
{
@ -178,7 +178,6 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
}
else
{
Length = status;
}
Stream_Write_UINT32(irp->output, Length);

View File

@ -33,7 +33,6 @@
#include <cups/cups.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/string.h>
#include <freerdp/channels/rdpdr.h>
@ -93,7 +92,7 @@ static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data,
{
FILE* fp;
fp = winpr_fopen((const char*)cups_printjob->printjob_object, "a+b");
fp = fopen((const char*)cups_printjob->printjob_object, "a+b");
if (!fp)
return ERROR_INTERNAL_ERROR;
@ -403,8 +402,8 @@ FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void)
uniq_cups_driver->driver.ReleaseRef = printer_cups_release_ref_driver;
uniq_cups_driver->id_sequence = 1;
uniq_cups_driver->driver.AddRef(&uniq_cups_driver->driver);
}
uniq_cups_driver->driver.AddRef(&uniq_cups_driver->driver);
return &uniq_cups_driver->driver;
}

View File

@ -82,9 +82,9 @@ static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* n
char* bname = crypto_base64_encode((const BYTE*)name, (int)length);
char* config = GetCombinedPath(dir, bname);
if (config && !winpr_PathFileExists(config))
if (config && !PathFileExistsA(config))
{
if (!winpr_PathMakePath(config, NULL))
if (!PathMakePathA(config, NULL))
{
free(config);
config = NULL;
@ -145,7 +145,7 @@ static BOOL printer_config_valid(const char* path)
if (!path)
return FALSE;
if (!winpr_PathFileExists(path))
if (!PathFileExistsA(path))
return FALSE;
return TRUE;
@ -261,7 +261,7 @@ static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name
if (!printer_config_valid(path))
goto fail;
rc = winpr_RemoveDirectory(path);
rc = RemoveDirectoryA(path);
fail:
free(path);
return rc;
@ -275,7 +275,7 @@ static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldNam
char* newPath = get_printer_config_path(settings, newName, newLength);
if (printer_config_valid(oldPath))
rc = winpr_MoveFile(oldPath, newPath);
rc = MoveFileA(oldPath, newPath);
free(oldPath);
free(newPath);
@ -979,7 +979,7 @@ printer_DeviceServiceEntry
device = (RDPDR_PRINTER*)pEntryPoints->device;
name = device->Name;
driver_name = _strdup(device->DriverName);
driver_name = device->DriverName;
/* Secondary argument is one of the following:
*
@ -1016,8 +1016,7 @@ printer_DeviceServiceEntry
if (!driver)
{
WLog_ERR(TAG, "Could not get a printer driver!");
error = CHANNEL_RC_INITIALIZATION_ERROR;
goto fail;
return CHANNEL_RC_INITIALIZATION_ERROR;
}
if (name && name[0])
@ -1065,9 +1064,7 @@ printer_DeviceServiceEntry
}
fail:
free(driver_name);
if (driver)
driver->ReleaseRef(driver);
driver->ReleaseRef(driver);
return error;
}

View File

@ -452,8 +452,8 @@ FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void)
win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
win_driver->id_sequence = 1;
win_driver->driver.AddRef(&win_driver->driver);
}
win_driver->driver.AddRef(&win_driver->driver);
return &win_driver->driver;
}

View File

@ -32,8 +32,6 @@
#include "rail_orders.h"
static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask);
/**
* Function description
*
@ -41,7 +39,6 @@ static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureM
*/
UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
{
char buffer[128] = { 0 };
UINT16 orderLength;
if (!rail || !s)
@ -52,7 +49,7 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
rail_write_pdu_header(s, orderType, orderLength);
Stream_SetPosition(s, orderLength);
WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
rail_get_order_type_string(orderType), orderLength);
return rail_send_channel_data(rail, s);
}
@ -391,46 +388,7 @@ static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
return error;
}
static UINT rail_read_compartment_info_order(wStream* s,
RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_COMPARTMENT_INFO_ORDER_LENGTH))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */
Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */
Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */
Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */
return CHANNEL_RC_OK;
}
static UINT rail_recv_compartmentinfo_order(railPlugin* rail, wStream* s)
{
RailClientContext* context = rail_get_client_interface(rail);
RAIL_COMPARTMENT_INFO_ORDER pdu = { 0 };
UINT error;
if (!context || !s)
return ERROR_INVALID_PARAMETER;
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
return ERROR_BAD_CONFIGURATION;
if ((error = rail_read_compartment_info_order(s, &pdu)))
return error;
if (context->custom)
{
IFCALLRET(context->ClientCompartmentInfo, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error);
}
return error;
}
BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
{
UINT32 supported, masked;
@ -442,15 +400,7 @@ BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
masked = (supported & featureMask);
if (masked != featureMask)
{
char mask[256] = { 0 };
char actual[256] = { 0 };
WLog_WARN(TAG, "[%s] have %s, require %s", __func__,
freerdp_rail_support_flags_to_string(supported, actual, sizeof(actual)),
freerdp_rail_support_flags_to_string(featureMask, mask, sizeof(mask)));
return FALSE;
}
return TRUE;
}
@ -954,73 +904,6 @@ static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rai
return error;
}
static UINT rail_read_textscaleinfo_order(wStream* s, UINT32* pTextScaleFactor)
{
WINPR_ASSERT(pTextScaleFactor);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, *pTextScaleFactor);
return CHANNEL_RC_OK;
}
static UINT rail_recv_textscaleinfo_order(railPlugin* rail, wStream* s)
{
RailClientContext* context = rail_get_client_interface(rail);
UINT32 TextScaleFactor = 0;
UINT error;
if (!context)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_textscaleinfo_order(s, &TextScaleFactor)))
return error;
if (context->custom)
{
IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor);
if (error)
WLog_ERR(TAG, "context.ClientTextScale failed with error %" PRIu32 "", error);
}
return error;
}
static UINT rail_read_caretblinkinfo_order(wStream* s, UINT32* pCaretBlinkRate)
{
WINPR_ASSERT(pCaretBlinkRate);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, *pCaretBlinkRate);
return CHANNEL_RC_OK;
}
static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s)
{
RailClientContext* context = rail_get_client_interface(rail);
UINT32 CaretBlinkRate = 0;
UINT error;
if (!context)
return ERROR_INVALID_PARAMETER;
if ((error = rail_read_caretblinkinfo_order(s, &CaretBlinkRate)))
return error;
if (context->custom)
{
IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate);
if (error)
WLog_ERR(TAG, "context.ClientCaretBlinkRate failed with error %" PRIu32 "", error);
}
return error;
}
/**
* Function description
*
@ -1028,10 +911,9 @@ static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s)
*/
UINT rail_order_recv(railPlugin* rail, wStream* s)
{
char buffer[128] = { 0 };
UINT16 orderType;
UINT16 orderLength;
UINT error = CHANNEL_RC_OK;
UINT error;
if (!rail || !s)
return ERROR_INVALID_PARAMETER;
@ -1043,88 +925,55 @@ UINT rail_order_recv(railPlugin* rail, wStream* s)
}
WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
rail_get_order_type_string(orderType), orderLength);
switch (orderType)
{
case TS_RAIL_ORDER_HANDSHAKE:
error = rail_recv_handshake_order(rail, s);
break;
case TS_RAIL_ORDER_COMPARTMENTINFO:
error = rail_recv_compartmentinfo_order(rail, s);
break;
return rail_recv_handshake_order(rail, s);
case TS_RAIL_ORDER_HANDSHAKE_EX:
error = rail_recv_handshake_ex_order(rail, s);
break;
return rail_recv_handshake_ex_order(rail, s);
case TS_RAIL_ORDER_EXEC_RESULT:
error = rail_recv_exec_result_order(rail, s);
break;
return rail_recv_exec_result_order(rail, s);
case TS_RAIL_ORDER_SYSPARAM:
error = rail_recv_server_sysparam_order(rail, s);
break;
return rail_recv_server_sysparam_order(rail, s);
case TS_RAIL_ORDER_MINMAXINFO:
error = rail_recv_server_minmaxinfo_order(rail, s);
break;
return rail_recv_server_minmaxinfo_order(rail, s);
case TS_RAIL_ORDER_LOCALMOVESIZE:
error = rail_recv_server_localmovesize_order(rail, s);
break;
return rail_recv_server_localmovesize_order(rail, s);
case TS_RAIL_ORDER_GET_APPID_RESP:
error = rail_recv_server_get_appid_resp_order(rail, s);
break;
return rail_recv_server_get_appid_resp_order(rail, s);
case TS_RAIL_ORDER_LANGBARINFO:
error = rail_recv_langbar_info_order(rail, s);
break;
return rail_recv_langbar_info_order(rail, s);
case TS_RAIL_ORDER_TASKBARINFO:
error = rail_recv_taskbar_info_order(rail, s);
break;
return rail_recv_taskbar_info_order(rail, s);
case TS_RAIL_ORDER_ZORDER_SYNC:
error = rail_recv_zorder_sync_order(rail, s);
break;
return rail_recv_zorder_sync_order(rail, s);
case TS_RAIL_ORDER_CLOAK:
error = rail_recv_cloak_order(rail, s);
break;
return rail_recv_cloak_order(rail, s);
case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
error = rail_recv_power_display_request_order(rail, s);
break;
return rail_recv_power_display_request_order(rail, s);
case TS_RAIL_ORDER_GET_APPID_RESP_EX:
error = rail_recv_get_application_id_extended_response_order(rail, s);
break;
case TS_RAIL_ORDER_TEXTSCALEINFO:
error = rail_recv_textscaleinfo_order(rail, s);
break;
case TS_RAIL_ORDER_CARETBLINKINFO:
error = rail_recv_caretblinkinfo_order(rail, s);
break;
return rail_recv_get_application_id_extended_response_order(rail, s);
default:
WLog_ERR(TAG, "Unknown RAIL PDU %s received.",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)));
WLog_ERR(TAG, "Unknown RAIL PDU order reveived.");
return ERROR_INVALID_DATA;
}
if (error != CHANNEL_RC_OK)
{
char buffer[128] = { 0 };
WLog_Print(rail->log, WLOG_ERROR, "Failed to process rail %s PDU, length:%" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
}
return error;
return CHANNEL_RC_OK;
}
/**
@ -1509,9 +1358,6 @@ UINT rail_send_client_compartment_info_order(railPlugin* rail,
if (!rail || !compartmentInfo)
return ERROR_INVALID_PARAMETER;
if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
return ERROR_BAD_CONFIGURATION;
s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH);
if (!s)

View File

@ -27,72 +27,37 @@
#define TAG CHANNELS_TAG("rail.common")
static const char* const RAIL_ORDER_TYPE_STRINGS[] = { "",
"Execute",
"Activate",
"System Parameters Update",
"System Command",
"Handshake",
"Notify Event",
"",
"Window Move",
"Local Move/Size",
"Min Max Info",
"Client Status",
"System Menu",
"Language Bar Info",
"Get Application ID Request",
"Get Application ID Response",
"Execute Result",
"",
"",
"",
"",
"",
"" };
const char* rail_get_order_type_string(UINT16 orderType)
{
switch (orderType)
{
case TS_RAIL_ORDER_EXEC:
return "TS_RAIL_ORDER_EXEC";
case TS_RAIL_ORDER_ACTIVATE:
return "TS_RAIL_ORDER_ACTIVATE";
case TS_RAIL_ORDER_SYSPARAM:
return "TS_RAIL_ORDER_SYSPARAM";
case TS_RAIL_ORDER_SYSCOMMAND:
return "TS_RAIL_ORDER_SYSCOMMAND";
case TS_RAIL_ORDER_HANDSHAKE:
return "TS_RAIL_ORDER_HANDSHAKE";
case TS_RAIL_ORDER_NOTIFY_EVENT:
return "TS_RAIL_ORDER_NOTIFY_EVENT";
case TS_RAIL_ORDER_WINDOWMOVE:
return "TS_RAIL_ORDER_WINDOWMOVE";
case TS_RAIL_ORDER_LOCALMOVESIZE:
return "TS_RAIL_ORDER_LOCALMOVESIZE";
case TS_RAIL_ORDER_MINMAXINFO:
return "TS_RAIL_ORDER_MINMAXINFO";
case TS_RAIL_ORDER_CLIENTSTATUS:
return "TS_RAIL_ORDER_CLIENTSTATUS";
case TS_RAIL_ORDER_SYSMENU:
return "TS_RAIL_ORDER_SYSMENU";
case TS_RAIL_ORDER_LANGBARINFO:
return "TS_RAIL_ORDER_LANGBARINFO";
case TS_RAIL_ORDER_GET_APPID_REQ:
return "TS_RAIL_ORDER_GET_APPID_REQ";
case TS_RAIL_ORDER_GET_APPID_RESP:
return "TS_RAIL_ORDER_GET_APPID_RESP";
case TS_RAIL_ORDER_TASKBARINFO:
return "TS_RAIL_ORDER_TASKBARINFO";
case TS_RAIL_ORDER_LANGUAGEIMEINFO:
return "TS_RAIL_ORDER_LANGUAGEIMEINFO";
case TS_RAIL_ORDER_COMPARTMENTINFO:
return "TS_RAIL_ORDER_COMPARTMENTINFO";
case TS_RAIL_ORDER_HANDSHAKE_EX:
return "TS_RAIL_ORDER_HANDSHAKE_EX";
case TS_RAIL_ORDER_ZORDER_SYNC:
return "TS_RAIL_ORDER_ZORDER_SYNC";
case TS_RAIL_ORDER_CLOAK:
return "TS_RAIL_ORDER_CLOAK";
case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST";
case TS_RAIL_ORDER_SNAP_ARRANGE:
return "TS_RAIL_ORDER_SNAP_ARRANGE";
case TS_RAIL_ORDER_GET_APPID_RESP_EX:
return "TS_RAIL_ORDER_GET_APPID_RESP_EX";
case TS_RAIL_ORDER_EXEC_RESULT:
return "TS_RAIL_ORDER_EXEC_RESULT";
case TS_RAIL_ORDER_TEXTSCALEINFO:
return "TS_RAIL_ORDER_TEXTSCALEINFO";
case TS_RAIL_ORDER_CARETBLINKINFO:
return "TS_RAIL_ORDER_CARETBLINKINFO";
default:
return "TS_RAIL_ORDER_UNKNOWN";
}
}
UINT32 index = ((orderType & 0xF0) >> 3) + (orderType & 0x0F);
if (index >= ARRAYSIZE(RAIL_ORDER_TYPE_STRINGS))
return "UNKNOWN";
const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length)
{
_snprintf(buffer, length, "%s[0x%04" PRIx16 "]", rail_get_order_type_string(orderType),
orderType);
return buffer;
return RAIL_ORDER_TYPE_STRINGS[index];
}
/**

View File

@ -71,6 +71,5 @@ UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
BOOL extendedSpiSupported);
BOOL rail_is_extended_spi_supported(UINT32 channelsFlags);
const char* rail_get_order_type_string(UINT16 orderType);
const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length);
#endif /* FREERDP_CHANNEL_RAIL_COMMON_H */

View File

@ -62,7 +62,6 @@ static UINT rail_send(RailServerContext* context, wStream* s, ULONG length)
*/
static UINT rail_server_send_pdu(RailServerContext* context, wStream* s, UINT16 orderType)
{
char buffer[128] = { 0 };
UINT16 orderLength;
if (!context || !s)
@ -72,8 +71,8 @@ static UINT rail_server_send_pdu(RailServerContext* context, wStream* s, UINT16
Stream_SetPosition(s, 0);
rail_write_pdu_header(s, orderType, orderLength);
Stream_SetPosition(s, orderLength);
WLog_DBG(TAG, "Sending %s PDU, length: %" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
WLog_DBG(TAG, "Sending %s PDU, length: %" PRIu16 "", rail_get_order_type_string(orderType),
orderLength);
return rail_send(context, s, orderLength);
}
@ -1536,7 +1535,6 @@ void rail_server_set_handshake_ex_flags(RailServerContext* context, DWORD flags)
UINT rail_server_handle_messages(RailServerContext* context)
{
char buffer[128] = { 0 };
UINT status = CHANNEL_RC_OK;
DWORD bytesReturned;
UINT16 orderType;
@ -1586,8 +1584,8 @@ UINT rail_server_handle_messages(RailServerContext* context)
return ERROR_INTERNAL_ERROR;
}
WLog_DBG(TAG, "Received %s PDU, length:%" PRIu16 "",
rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
WLog_DBG(TAG, "Received %s PDU, length:%" PRIu16 "", rail_get_order_type_string(orderType),
orderLength);
switch (orderType)
{

View File

@ -22,6 +22,6 @@ set(${MODULE_PREFIX}_SRCS
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "VirtualChannelEntryEx")
target_link_libraries(${MODULE_NAME} winpr freerdp)
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")

View File

@ -41,8 +41,6 @@
#include "devman.h"
#define TAG CHANNELS_TAG("rdpdr.client")
static void devman_device_free(void* obj)
{
DEVICE* device = (DEVICE*)obj;
@ -64,7 +62,7 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
if (!devman)
{
WLog_Print(rdpdr->log, WLOG_INFO, "calloc failed!");
WLog_INFO(TAG, "calloc failed!");
return NULL;
}
@ -74,7 +72,7 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
if (!devman->devices)
{
WLog_Print(rdpdr->log, WLOG_INFO, "ListDictionary_New failed!");
WLog_INFO(TAG, "ListDictionary_New failed!");
free(devman);
return NULL;
}

View File

@ -76,13 +76,13 @@ static UINT irp_complete(IRP* irp)
return irp_free(irp);
}
IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error)
IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error)
{
IRP* irp;
DEVICE* device;
UINT32 DeviceId;
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
if (Stream_GetRemainingLength(s) < 20)
{
if (error)
*error = ERROR_INVALID_DATA;
@ -94,7 +94,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error)
if (!device)
{
WLog_Print(log, WLOG_WARN, "devman_get_device_by_id failed!");
WLog_WARN(TAG, "devman_get_device_by_id failed!");
if (error)
*error = CHANNEL_RC_OK;
@ -105,7 +105,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error)
if (!irp)
{
WLog_Print(log, WLOG_ERROR, "_aligned_malloc failed!");
WLog_ERR(TAG, "_aligned_malloc failed!");
if (error)
*error = CHANNEL_RC_NO_MEMORY;
return NULL;
@ -125,7 +125,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error)
irp->output = Stream_New(NULL, 256);
if (!irp->output)
{
WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
WLog_ERR(TAG, "Stream_New failed!");
_aligned_free(irp);
if (error)
*error = CHANNEL_RC_NO_MEMORY;

View File

@ -21,9 +21,8 @@
#ifndef FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H
#define FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H
#include <winpr/wlog.h>
#include "rdpdr_main.h"
IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error);
IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error);
#endif /* FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H */

View File

@ -35,8 +35,6 @@
#include "rdpdr_main.h"
#include "rdpdr_capabilities.h"
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
/* Output device redirection capability set header */
static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 capabilityLength,
UINT32 version)
@ -50,59 +48,39 @@ static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16
static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s)
{
WINPR_UNUSED(rdpdr);
const UINT32 ioCode1 = rdpdr->clientIOCode1 & rdpdr->serverIOCode1;
const UINT32 ioCode2 = rdpdr->clientIOCode2 & rdpdr->serverIOCode2;
rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
GENERAL_CAPABILITY_VERSION_02);
Stream_Write_UINT32(s, rdpdr->clientOsType); /* osType, ignored on receipt */
Stream_Write_UINT32(s, rdpdr->clientOsVersion); /* osVersion, unused and must be set to zero */
Stream_Write_UINT16(s, rdpdr->clientVersionMajor); /* protocolMajorVersion, must be set to 1 */
Stream_Write_UINT16(s, rdpdr->clientVersionMinor); /* protocolMinorVersion */
Stream_Write_UINT32(s, ioCode1); /* ioCode1 */
Stream_Write_UINT32(s, ioCode2); /* ioCode2, must be set to zero, reserved for future use */
Stream_Write_UINT32(s, rdpdr->clientExtendedPDU); /* extendedPDU */
Stream_Write_UINT32(s, rdpdr->clientExtraFlags1); /* extraFlags1 */
rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02);
Stream_Write_UINT32(s, 0); /* osType, ignored on receipt */
Stream_Write_UINT32(s, 0); /* osVersion, unused and must be set to zero */
Stream_Write_UINT16(s, 1); /* protocolMajorVersion, must be set to 1 */
Stream_Write_UINT16(s, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */
Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */
Stream_Write_UINT32(s, 0); /* ioCode2, must be set to zero, reserved for future use */
Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU |
RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */
Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */
Stream_Write_UINT32(s, 0); /* extraFlags2, must be set to zero, reserved for future use */
Stream_Write_UINT32(
s,
rdpdr->clientExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
Stream_Write_UINT32(
s, rdpdr->clientSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
be redirected before logon */
s, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */
}
/* Process device direction general capability set */
static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (capabilityLength != 36)
{
WLog_Print(rdpdr->log, WLOG_ERROR,
"CAP_GENERAL_TYPE::CapabilityLength expected 36, got %" PRIu32,
capabilityLength);
return ERROR_INVALID_DATA;
}
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
if (Stream_GetRemainingLength(s) < 2)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, rdpdr->serverOsType); /* osType, ignored on receipt */
Stream_Read_UINT32(s, rdpdr->serverOsVersion); /* osVersion, unused and must be set to zero */
Stream_Read_UINT16(s, rdpdr->serverVersionMajor); /* protocolMajorVersion, must be set to 1 */
Stream_Read_UINT16(s, rdpdr->serverVersionMinor); /* protocolMinorVersion */
Stream_Read_UINT32(s, rdpdr->serverIOCode1); /* ioCode1 */
Stream_Read_UINT32(
s, rdpdr->serverIOCode2); /* ioCode2, must be set to zero, reserved for future use */
Stream_Read_UINT32(s, rdpdr->serverExtendedPDU); /* extendedPDU */
Stream_Read_UINT32(s, rdpdr->serverExtraFlags1); /* extraFlags1 */
Stream_Read_UINT32(
s,
rdpdr->serverExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
Stream_Read_UINT32(
s, rdpdr->serverSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
be redirected before logon */
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < capabilityLength - 4U)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
return CHANNEL_RC_OK;
}
@ -114,14 +92,23 @@ static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process printer direction capability set */
static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
if (Stream_GetRemainingLength(s) < 2)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength);
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < capabilityLength - 4U)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
return CHANNEL_RC_OK;
}
@ -133,14 +120,23 @@ static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process port redirection capability set */
static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
if (Stream_GetRemainingLength(s) < 2)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength);
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4U)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < capabilityLength - 4U)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
return CHANNEL_RC_OK;
}
@ -152,14 +148,23 @@ static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process drive redirection capability set */
static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
if (Stream_GetRemainingLength(s) < 2)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength);
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < capabilityLength - 4U)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
return CHANNEL_RC_OK;
}
@ -171,14 +176,23 @@ static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
}
/* Process smartcard redirection capability set */
static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength)
static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
{
UINT16 capabilityLength;
WINPR_UNUSED(rdpdr);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
if (Stream_GetRemainingLength(s) < 2)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength);
Stream_Read_UINT16(s, capabilityLength);
if (capabilityLength < 4)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < capabilityLength - 4U)
return ERROR_INVALID_DATA;
Stream_Seek(s, capabilityLength - 4U);
return CHANNEL_RC_OK;
}
@ -187,14 +201,12 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
UINT status = CHANNEL_RC_OK;
UINT16 i;
UINT16 numCapabilities;
UINT16 capabilityType;
if (!rdpdr || !s)
return CHANNEL_RC_NULL_DATA;
WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_SERVER_CAPS);
rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS);
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, numCapabilities);
@ -202,44 +214,31 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
for (i = 0; i < numCapabilities; i++)
{
UINT16 capabilityType;
UINT16 capabilityLength;
UINT32 version = 0;
if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s,
2 * sizeof(UINT16) + sizeof(UINT32)))
if (Stream_GetRemainingLength(s) < sizeof(UINT16))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, capabilityType);
Stream_Read_UINT16(s, capabilityLength);
Stream_Read_UINT32(s, version);
if (capabilityLength < 8)
{
return ERROR_INVALID_DATA;
}
capabilityLength -= 8;
switch (capabilityType)
{
case CAP_GENERAL_TYPE:
status = rdpdr_process_general_capset(rdpdr, s, capabilityLength);
status = rdpdr_process_general_capset(rdpdr, s);
break;
case CAP_PRINTER_TYPE:
status = rdpdr_process_printer_capset(rdpdr, s, capabilityLength);
status = rdpdr_process_printer_capset(rdpdr, s);
break;
case CAP_PORT_TYPE:
status = rdpdr_process_port_capset(rdpdr, s, capabilityLength);
status = rdpdr_process_port_capset(rdpdr, s);
break;
case CAP_DRIVE_TYPE:
status = rdpdr_process_drive_capset(rdpdr, s, capabilityLength);
status = rdpdr_process_drive_capset(rdpdr, s);
break;
case CAP_SMARTCARD_TYPE:
status = rdpdr_process_smartcard_capset(rdpdr, s, capabilityLength);
status = rdpdr_process_smartcard_capset(rdpdr, s);
break;
default:
@ -265,7 +264,7 @@ UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr)
if (!s)
{
WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
WLog_ERR(TAG, "Stream_New failed!");
return CHANNEL_RC_NO_MEMORY;
}

File diff suppressed because it is too large Load Diff

View File

@ -42,33 +42,15 @@
#include <CoreServices/CoreServices.h>
#endif
#if !defined(Stream_CheckAndLogRequiredLengthWLog)
#define Stream_CheckAndLogRequiredLengthWLog(log, s, len) \
Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, len, "%s(%s:%d)", __FUNCTION__, \
__FILE__, __LINE__)
#endif
#define TAG CHANNELS_TAG("rdpdr.client")
typedef struct rdpdr_plugin rdpdrPlugin;
enum RDPDR_CHANNEL_STATE
{
RDPDR_CHANNEL_STATE_INITIAL = 0,
RDPDR_CHANNEL_STATE_ANNOUNCE,
RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY,
RDPDR_CHANNEL_STATE_NAME_REQUEST,
RDPDR_CHANNEL_STATE_SERVER_CAPS,
RDPDR_CHANNEL_STATE_CLIENT_CAPS,
RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM,
RDPDR_CHANNEL_STATE_READY,
RDPDR_CHANNEL_STATE_USER_LOGGEDON
};
struct rdpdr_plugin
{
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints;
enum RDPDR_CHANNEL_STATE state;
HANDLE thread;
wStream* data_in;
void* InitHandle;
@ -77,33 +59,12 @@ struct rdpdr_plugin
DEVMAN* devman;
UINT32 serverOsType;
UINT32 serverOsVersion;
UINT16 serverVersionMajor;
UINT16 serverVersionMinor;
UINT32 serverExtendedPDU;
UINT32 serverIOCode1;
UINT32 serverIOCode2;
UINT32 serverExtraFlags1;
UINT32 serverExtraFlags2;
UINT32 serverSpecialTypeDeviceCap;
UINT32 clientOsType;
UINT32 clientOsVersion;
UINT16 clientVersionMajor;
UINT16 clientVersionMinor;
UINT32 clientExtendedPDU;
UINT32 clientIOCode1;
UINT32 clientIOCode2;
UINT32 clientExtraFlags1;
UINT32 clientExtraFlags2;
UINT32 clientSpecialTypeDeviceCap;
UINT32 clientID;
UINT16 versionMajor;
UINT16 versionMinor;
UINT16 clientID;
char computerName[256];
UINT32 sequenceId;
BOOL userLoggedOn;
/* hotplug support */
HANDLE hotplugThread;
@ -117,10 +78,8 @@ struct rdpdr_plugin
HANDLE stopEvent;
#endif
rdpContext* rdpcontext;
wLog* log;
};
BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next);
UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s);
#endif /* FREERDP_CHANNEL_RDPDR_CLIENT_MAIN_H */

View File

@ -1952,7 +1952,7 @@ static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* con
irp->Callback = rdpdr_server_drive_query_directory_callback2;
irp->DeviceId = deviceId;
irp->FileId = fileId;
winpr_str_append("\\*.*", irp->PathName, ARRAYSIZE(irp->PathName), NULL);
strcat(irp->PathName, "\\*.*");
if (!rdpdr_server_enqueue_irp(context, irp))
{

View File

@ -57,6 +57,13 @@ struct _RDPDR_HEADER
};
typedef struct _RDPDR_HEADER RDPDR_HEADER;
#define RDPDR_VERSION_MAJOR 0x0001
#define RDPDR_VERSION_MINOR_RDP50 0x0002
#define RDPDR_VERSION_MINOR_RDP51 0x0005
#define RDPDR_VERSION_MINOR_RDP52 0x000A
#define RDPDR_VERSION_MINOR_RDP6X 0x000C
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
struct _RDPDR_CAPABILITY_HEADER

View File

@ -1,22 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
#
# 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("rdpecam")
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -1,12 +0,0 @@
set(OPTION_DEFAULT ON)
set(OPTION_CLIENT_DEFAULT OFF)
set(OPTION_SERVER_DEFAULT ON)
define_channel_options(NAME "rdpecam" TYPE "dynamic"
DESCRIPTION "Video Capture Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPECAM]"
DEFAULT ${OPTION_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})

View File

@ -1,27 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
#
# 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("rdpecam")
set(${MODULE_PREFIX}_SRCS
camera_device_enumerator_main.c
camera_device_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")

View File

@ -1,612 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* 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 <freerdp/channels/log.h>
#include <freerdp/server/rdpecam-enumerator.h>
#define TAG CHANNELS_TAG("rdpecam-enumerator.server")
typedef enum
{
ENUMERATOR_INITIAL,
ENUMERATOR_OPENED,
} eEnumeratorChannelState;
typedef struct
{
CamDevEnumServerContext context;
HANDLE stopEvent;
HANDLE thread;
void* enumerator_channel;
DWORD SessionId;
BOOL isOpened;
BOOL externalThread;
/* Channel state */
eEnumeratorChannelState state;
wStream* buffer;
} enumerator_server;
static UINT enumerator_server_initialize(CamDevEnumServerContext* context, BOOL externalThread)
{
UINT error = CHANNEL_RC_OK;
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (enumerator->isOpened)
{
WLog_WARN(TAG, "Application error: Camera Device Enumerator channel already initialized, "
"calling in this state is not possible!");
return ERROR_INVALID_STATE;
}
enumerator->externalThread = externalThread;
return error;
}
static UINT enumerator_server_open_channel(enumerator_server* enumerator)
{
CamDevEnumServerContext* context = &enumerator->context;
DWORD Error = ERROR_SUCCESS;
HANDLE hEvent;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
UINT32 channelId;
BOOL status = TRUE;
WINPR_ASSERT(enumerator);
if (WTSQuerySessionInformationA(enumerator->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
enumerator->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(enumerator->context.vcm);
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
enumerator->enumerator_channel = WTSVirtualChannelOpenEx(
enumerator->SessionId, RDPECAM_CONTROL_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
if (!enumerator->enumerator_channel)
{
Error = GetLastError();
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
return Error;
}
channelId = WTSChannelGetIdByHandle(enumerator->enumerator_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
return Error;
}
static UINT enumerator_server_handle_select_version_request(CamDevEnumServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SELECT_VERSION_REQUEST pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
IFCALLRET(context->SelectVersionRequest, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SelectVersionRequest failed with error %" PRIu32 "", error);
return error;
}
static UINT enumerator_server_recv_device_added_notification(CamDevEnumServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_DEVICE_ADDED_NOTIFICATION pdu;
UINT error = CHANNEL_RC_OK;
size_t remaining_length;
WCHAR* channel_name_start;
char* tmp;
size_t i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
/*
* RequiredLength 4:
*
* Nullterminator DeviceName (2),
* VirtualChannelName (>= 1),
* Nullterminator VirtualChannelName (1)
*/
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_NO_DATA;
pdu.DeviceName = (WCHAR*)Stream_Pointer(s);
remaining_length = Stream_GetRemainingLength(s);
channel_name_start = (WCHAR*)Stream_Pointer(s);
/* Search for null terminator of DeviceName */
for (i = 0; i < remaining_length; i += sizeof(WCHAR), ++channel_name_start)
{
if (*channel_name_start == L'\0')
break;
}
if (*channel_name_start != L'\0')
{
WLog_ERR(TAG, "enumerator_server_recv_device_added_notification: Invalid DeviceName!");
return ERROR_INVALID_DATA;
}
pdu.VirtualChannelName = (char*)++channel_name_start;
++i;
if (i >= remaining_length || *pdu.VirtualChannelName == '\0')
{
WLog_ERR(TAG,
"enumerator_server_recv_device_added_notification: Invalid VirtualChannelName!");
return ERROR_INVALID_DATA;
}
tmp = pdu.VirtualChannelName;
for (; i < remaining_length; ++i, ++tmp)
{
if (*tmp == '\0')
break;
}
if (*tmp != '\0')
{
WLog_ERR(TAG,
"enumerator_server_recv_device_added_notification: Invalid VirtualChannelName!");
return ERROR_INVALID_DATA;
}
IFCALLRET(context->DeviceAddedNotification, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->DeviceAddedNotification failed with error %" PRIu32 "", error);
return error;
}
static UINT enumerator_server_recv_device_removed_notification(CamDevEnumServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_DEVICE_REMOVED_NOTIFICATION pdu;
UINT error = CHANNEL_RC_OK;
size_t remaining_length;
char* tmp;
size_t i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
return ERROR_NO_DATA;
pdu.VirtualChannelName = (char*)Stream_Pointer(s);
remaining_length = Stream_GetRemainingLength(s);
tmp = (char*)(Stream_Pointer(s) + 1);
for (i = 1; i < remaining_length; ++i, ++tmp)
{
if (*tmp == '\0')
break;
}
if (*tmp != '\0')
{
WLog_ERR(TAG,
"enumerator_server_recv_device_removed_notification: Invalid VirtualChannelName!");
return ERROR_INVALID_DATA;
}
IFCALLRET(context->DeviceRemovedNotification, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->DeviceRemovedNotification failed with error %" PRIu32 "", error);
return error;
}
static UINT enumerator_process_message(enumerator_server* enumerator)
{
BOOL rc;
UINT error = ERROR_INTERNAL_ERROR;
ULONG BytesReturned;
CAM_SHARED_MSG_HEADER header = { 0 };
wStream* s;
WINPR_ASSERT(enumerator);
WINPR_ASSERT(enumerator->enumerator_channel);
s = enumerator->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
rc = WTSVirtualChannelRead(enumerator->enumerator_channel, 0, NULL, 0, &BytesReturned);
if (!rc)
goto out;
if (BytesReturned < 1)
{
error = CHANNEL_RC_OK;
goto out;
}
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
error = CHANNEL_RC_NO_MEMORY;
goto out;
}
if (WTSVirtualChannelRead(enumerator->enumerator_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
goto out;
}
Stream_SetLength(s, BytesReturned);
if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, header.Version);
Stream_Read_UINT8(s, header.MessageId);
switch (header.MessageId)
{
case CAM_MSG_ID_SelectVersionRequest:
error =
enumerator_server_handle_select_version_request(&enumerator->context, s, &header);
break;
case CAM_MSG_ID_DeviceAddedNotification:
error =
enumerator_server_recv_device_added_notification(&enumerator->context, s, &header);
break;
case CAM_MSG_ID_DeviceRemovedNotification:
error = enumerator_server_recv_device_removed_notification(&enumerator->context, s,
&header);
break;
default:
WLog_ERR(TAG, "enumerator_process_message: unknown or invalid MessageId %" PRIu8 "",
header.MessageId);
break;
}
out:
if (error)
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
return error;
}
static UINT enumerator_server_context_poll_int(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
UINT error = ERROR_INTERNAL_ERROR;
WINPR_ASSERT(enumerator);
switch (enumerator->state)
{
case ENUMERATOR_INITIAL:
error = enumerator_server_open_channel(enumerator);
if (error)
WLog_ERR(TAG, "enumerator_server_open_channel failed with error %" PRIu32 "!",
error);
else
enumerator->state = ENUMERATOR_OPENED;
break;
case ENUMERATOR_OPENED:
error = enumerator_process_message(enumerator);
break;
}
return error;
}
static HANDLE enumerator_server_get_channel_handle(enumerator_server* enumerator)
{
void* buffer = NULL;
DWORD BytesReturned = 0;
HANDLE ChannelEvent = NULL;
WINPR_ASSERT(enumerator);
if (WTSVirtualChannelQuery(enumerator->enumerator_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
return ChannelEvent;
}
static DWORD WINAPI enumerator_server_thread_func(LPVOID arg)
{
DWORD nCount;
HANDLE events[2] = { 0 };
enumerator_server* enumerator = (enumerator_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
WINPR_ASSERT(enumerator);
nCount = 0;
events[nCount++] = enumerator->stopEvent;
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
{
switch (enumerator->state)
{
case ENUMERATOR_INITIAL:
error = enumerator_server_context_poll_int(&enumerator->context);
if (error == CHANNEL_RC_OK)
{
events[1] = enumerator_server_get_channel_handle(enumerator);
nCount = 2;
}
break;
case ENUMERATOR_OPENED:
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
switch (status)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
case WAIT_TIMEOUT:
error = enumerator_server_context_poll_int(&enumerator->context);
break;
case WAIT_FAILED:
default:
error = ERROR_INTERNAL_ERROR;
break;
}
break;
}
}
WTSVirtualChannelClose(enumerator->enumerator_channel);
enumerator->enumerator_channel = NULL;
if (error && enumerator->context.rdpcontext)
setChannelError(enumerator->context.rdpcontext, error,
"enumerator_server_thread_func reported an error");
ExitThread(error);
return error;
}
static UINT enumerator_server_open(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (!enumerator->externalThread && (enumerator->thread == NULL))
{
enumerator->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!enumerator->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
return ERROR_INTERNAL_ERROR;
}
enumerator->thread =
CreateThread(NULL, 0, enumerator_server_thread_func, enumerator, 0, NULL);
if (!enumerator->thread)
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(enumerator->stopEvent);
enumerator->stopEvent = NULL;
return ERROR_INTERNAL_ERROR;
}
}
enumerator->isOpened = TRUE;
return CHANNEL_RC_OK;
}
static UINT enumerator_server_close(CamDevEnumServerContext* context)
{
UINT error = CHANNEL_RC_OK;
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (!enumerator->externalThread && enumerator->thread)
{
SetEvent(enumerator->stopEvent);
if (WaitForSingleObject(enumerator->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(enumerator->thread);
CloseHandle(enumerator->stopEvent);
enumerator->thread = NULL;
enumerator->stopEvent = NULL;
}
if (enumerator->externalThread)
{
if (enumerator->state != ENUMERATOR_INITIAL)
{
WTSVirtualChannelClose(enumerator->enumerator_channel);
enumerator->enumerator_channel = NULL;
enumerator->state = ENUMERATOR_INITIAL;
}
}
enumerator->isOpened = FALSE;
return error;
}
static UINT enumerator_server_context_poll(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (!enumerator->externalThread)
return ERROR_INTERNAL_ERROR;
return enumerator_server_context_poll_int(context);
}
static BOOL enumerator_server_context_handle(CamDevEnumServerContext* context, HANDLE* handle)
{
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
WINPR_ASSERT(handle);
if (!enumerator->externalThread)
return FALSE;
if (enumerator->state == ENUMERATOR_INITIAL)
return FALSE;
*handle = enumerator_server_get_channel_handle(enumerator);
return TRUE;
}
static UINT enumerator_server_packet_send(CamDevEnumServerContext* context, wStream* s)
{
enumerator_server* enumerator = (enumerator_server*)context;
UINT error = CHANNEL_RC_OK;
ULONG written;
if (!WTSVirtualChannelWrite(enumerator->enumerator_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
error = ERROR_INTERNAL_ERROR;
goto out;
}
if (written < Stream_GetPosition(s))
{
WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
Stream_GetPosition(s));
}
out:
Stream_Free(s, TRUE);
return error;
}
static UINT enumerator_send_select_version_response_pdu(
CamDevEnumServerContext* context, const CAM_SELECT_VERSION_RESPONSE* selectVersionResponse)
{
wStream* s;
s = Stream_New(NULL, CAM_HEADER_SIZE);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return ERROR_NOT_ENOUGH_MEMORY;
}
Stream_Write_UINT8(s, selectVersionResponse->Header.Version);
Stream_Write_UINT8(s, selectVersionResponse->Header.MessageId);
return enumerator_server_packet_send(context, s);
}
CamDevEnumServerContext* cam_dev_enum_server_context_new(HANDLE vcm)
{
enumerator_server* enumerator = (enumerator_server*)calloc(1, sizeof(enumerator_server));
if (!enumerator)
return NULL;
enumerator->context.vcm = vcm;
enumerator->context.Initialize = enumerator_server_initialize;
enumerator->context.Open = enumerator_server_open;
enumerator->context.Close = enumerator_server_close;
enumerator->context.Poll = enumerator_server_context_poll;
enumerator->context.ChannelHandle = enumerator_server_context_handle;
enumerator->context.SelectVersionResponse = enumerator_send_select_version_response_pdu;
enumerator->buffer = Stream_New(NULL, 4096);
if (!enumerator->buffer)
goto fail;
return &enumerator->context;
fail:
cam_dev_enum_server_context_free(&enumerator->context);
return NULL;
}
void cam_dev_enum_server_context_free(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
if (enumerator)
{
enumerator_server_close(context);
Stream_Free(enumerator->buffer, TRUE);
}
free(enumerator);
}

View File

@ -1,969 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* 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 <freerdp/channels/log.h>
#include <freerdp/server/rdpecam.h>
#define TAG CHANNELS_TAG("rdpecam.server")
typedef enum
{
CAMERA_DEVICE_INITIAL,
CAMERA_DEVICE_OPENED,
} eCameraDeviceChannelState;
typedef struct
{
CameraDeviceServerContext context;
HANDLE stopEvent;
HANDLE thread;
void* device_channel;
DWORD SessionId;
BOOL isOpened;
BOOL externalThread;
/* Channel state */
eCameraDeviceChannelState state;
wStream* buffer;
} device_server;
static UINT device_server_initialize(CameraDeviceServerContext* context, BOOL externalThread)
{
UINT error = CHANNEL_RC_OK;
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (device->isOpened)
{
WLog_WARN(TAG, "Application error: Camera channel already initialized, "
"calling in this state is not possible!");
return ERROR_INVALID_STATE;
}
device->externalThread = externalThread;
return error;
}
static UINT device_server_open_channel(device_server* device)
{
CameraDeviceServerContext* context = &device->context;
DWORD Error = ERROR_SUCCESS;
HANDLE hEvent;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
UINT32 channelId;
BOOL status = TRUE;
WINPR_ASSERT(device);
if (WTSQuerySessionInformationA(device->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
device->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(device->context.vcm);
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
device->device_channel = WTSVirtualChannelOpenEx(device->SessionId, context->virtualChannelName,
WTS_CHANNEL_OPTION_DYNAMIC);
if (!device->device_channel)
{
Error = GetLastError();
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
return Error;
}
channelId = WTSChannelGetIdByHandle(device->device_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
return Error;
}
static UINT device_server_handle_success_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SUCCESS_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
IFCALLRET(context->SuccessResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SuccessResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_error_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_ERROR_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_NO_DATA;
Stream_Read_UINT32(s, pdu.ErrorCode);
IFCALLRET(context->ErrorResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->ErrorResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_stream_list_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_STREAM_LIST_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
BYTE i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
return ERROR_NO_DATA;
pdu.N_Descriptions = MIN(Stream_GetRemainingLength(s) / 5, 255);
for (i = 0; i < pdu.N_Descriptions; ++i)
{
CAM_STREAM_DESCRIPTION* StreamDescription = &pdu.StreamDescriptions[i];
Stream_Read_UINT16(s, StreamDescription->FrameSourceTypes);
Stream_Read_UINT8(s, StreamDescription->StreamCategory);
Stream_Read_UINT8(s, StreamDescription->Selected);
Stream_Read_UINT8(s, StreamDescription->CanBeShared);
}
IFCALLRET(context->StreamListResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->StreamListResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_media_type_list_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_MEDIA_TYPE_LIST_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
BYTE i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
return ERROR_NO_DATA;
pdu.N_Descriptions = Stream_GetRemainingLength(s) / 26;
pdu.MediaTypeDescriptions = calloc(pdu.N_Descriptions, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
if (!pdu.MediaTypeDescriptions)
{
WLog_ERR(TAG, "Failed to allocate %zu CAM_MEDIA_TYPE_DESCRIPTION structs",
pdu.N_Descriptions);
return ERROR_NOT_ENOUGH_MEMORY;
}
for (i = 0; i < pdu.N_Descriptions; ++i)
{
CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions = &pdu.MediaTypeDescriptions[i];
Stream_Read_UINT8(s, MediaTypeDescriptions->Format);
Stream_Read_UINT32(s, MediaTypeDescriptions->Width);
Stream_Read_UINT32(s, MediaTypeDescriptions->Height);
Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateNumerator);
Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateDenominator);
Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioNumerator);
Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioDenominator);
Stream_Read_UINT8(s, MediaTypeDescriptions->Flags);
}
IFCALLRET(context->MediaTypeListResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->MediaTypeListResponse failed with error %" PRIu32 "", error);
free(pdu.MediaTypeDescriptions);
return error;
}
static UINT device_server_recv_current_media_type_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_CURRENT_MEDIA_TYPE_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.MediaTypeDescription.Format);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.Width);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.Height);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateNumerator);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateDenominator);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioNumerator);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioDenominator);
Stream_Read_UINT8(s, pdu.MediaTypeDescription.Flags);
IFCALLRET(context->CurrentMediaTypeResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->CurrentMediaTypeResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_sample_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SAMPLE_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.StreamIndex);
pdu.SampleSize = Stream_GetRemainingLength(s);
pdu.Sample = Stream_Pointer(s);
IFCALLRET(context->SampleResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SampleResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_sample_error_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SAMPLE_ERROR_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.StreamIndex);
Stream_Read_UINT32(s, pdu.ErrorCode);
IFCALLRET(context->SampleErrorResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SampleErrorResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_property_list_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_PROPERTY_LIST_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
pdu.N_Properties = Stream_GetRemainingLength(s) / 19;
if (pdu.N_Properties > 0)
{
size_t i;
pdu.Properties = calloc(pdu.N_Properties, sizeof(CAM_PROPERTY_DESCRIPTION));
if (!pdu.Properties)
{
WLog_ERR(TAG, "Failed to allocate %zu CAM_PROPERTY_DESCRIPTION structs",
pdu.N_Properties);
return ERROR_NOT_ENOUGH_MEMORY;
}
for (i = 0; i < pdu.N_Properties; ++i)
{
Stream_Read_UINT8(s, pdu.Properties[i].PropertySet);
Stream_Read_UINT8(s, pdu.Properties[i].PropertyId);
Stream_Read_UINT8(s, pdu.Properties[i].Capabilities);
Stream_Read_INT32(s, pdu.Properties[i].MinValue);
Stream_Read_INT32(s, pdu.Properties[i].MaxValue);
Stream_Read_INT32(s, pdu.Properties[i].Step);
Stream_Read_INT32(s, pdu.Properties[i].DefaultValue);
}
}
IFCALLRET(context->PropertyListResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->PropertyListResponse failed with error %" PRIu32 "", error);
free(pdu.Properties);
return error;
}
static UINT device_server_recv_property_value_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_PROPERTY_VALUE_RESPONSE pdu = { 0 };
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.PropertyValue.Mode);
Stream_Read_INT32(s, pdu.PropertyValue.Value);
IFCALLRET(context->PropertyValueResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->PropertyValueResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_process_message(device_server* device)
{
BOOL rc;
UINT error = ERROR_INTERNAL_ERROR;
ULONG BytesReturned;
CAM_SHARED_MSG_HEADER header = { 0 };
wStream* s;
WINPR_ASSERT(device);
WINPR_ASSERT(device->device_channel);
s = device->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
rc = WTSVirtualChannelRead(device->device_channel, 0, NULL, 0, &BytesReturned);
if (!rc)
goto out;
if (BytesReturned < 1)
{
error = CHANNEL_RC_OK;
goto out;
}
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
error = CHANNEL_RC_NO_MEMORY;
goto out;
}
if (WTSVirtualChannelRead(device->device_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
goto out;
}
Stream_SetLength(s, BytesReturned);
if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, header.Version);
Stream_Read_UINT8(s, header.MessageId);
switch (header.MessageId)
{
case CAM_MSG_ID_SuccessResponse:
error = device_server_handle_success_response(&device->context, s, &header);
break;
case CAM_MSG_ID_ErrorResponse:
error = device_server_recv_error_response(&device->context, s, &header);
break;
case CAM_MSG_ID_StreamListResponse:
error = device_server_recv_stream_list_response(&device->context, s, &header);
break;
case CAM_MSG_ID_MediaTypeListResponse:
error = device_server_recv_media_type_list_response(&device->context, s, &header);
break;
case CAM_MSG_ID_CurrentMediaTypeResponse:
error = device_server_recv_current_media_type_response(&device->context, s, &header);
break;
case CAM_MSG_ID_SampleResponse:
error = device_server_recv_sample_response(&device->context, s, &header);
break;
case CAM_MSG_ID_SampleErrorResponse:
error = device_server_recv_sample_error_response(&device->context, s, &header);
break;
case CAM_MSG_ID_PropertyListResponse:
error = device_server_recv_property_list_response(&device->context, s, &header);
break;
case CAM_MSG_ID_PropertyValueResponse:
error = device_server_recv_property_value_response(&device->context, s, &header);
break;
default:
WLog_ERR(TAG, "device_process_message: unknown or invalid MessageId %" PRIu8 "",
header.MessageId);
break;
}
out:
if (error)
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
return error;
}
static UINT device_server_context_poll_int(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
UINT error = ERROR_INTERNAL_ERROR;
WINPR_ASSERT(device);
switch (device->state)
{
case CAMERA_DEVICE_INITIAL:
error = device_server_open_channel(device);
if (error)
WLog_ERR(TAG, "device_server_open_channel failed with error %" PRIu32 "!", error);
else
device->state = CAMERA_DEVICE_OPENED;
break;
case CAMERA_DEVICE_OPENED:
error = device_process_message(device);
break;
}
return error;
}
static HANDLE device_server_get_channel_handle(device_server* device)
{
void* buffer = NULL;
DWORD BytesReturned = 0;
HANDLE ChannelEvent = NULL;
WINPR_ASSERT(device);
if (WTSVirtualChannelQuery(device->device_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
return ChannelEvent;
}
static DWORD WINAPI device_server_thread_func(LPVOID arg)
{
DWORD nCount;
HANDLE events[2] = { 0 };
device_server* device = (device_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
WINPR_ASSERT(device);
nCount = 0;
events[nCount++] = device->stopEvent;
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
{
switch (device->state)
{
case CAMERA_DEVICE_INITIAL:
error = device_server_context_poll_int(&device->context);
if (error == CHANNEL_RC_OK)
{
events[1] = device_server_get_channel_handle(device);
nCount = 2;
}
break;
case CAMERA_DEVICE_OPENED:
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
switch (status)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
case WAIT_TIMEOUT:
error = device_server_context_poll_int(&device->context);
break;
case WAIT_FAILED:
default:
error = ERROR_INTERNAL_ERROR;
break;
}
break;
}
}
WTSVirtualChannelClose(device->device_channel);
device->device_channel = NULL;
if (error && device->context.rdpcontext)
setChannelError(device->context.rdpcontext, error,
"device_server_thread_func reported an error");
ExitThread(error);
return error;
}
static UINT device_server_open(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (!device->externalThread && (device->thread == NULL))
{
device->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!device->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
return ERROR_INTERNAL_ERROR;
}
device->thread = CreateThread(NULL, 0, device_server_thread_func, device, 0, NULL);
if (!device->thread)
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(device->stopEvent);
device->stopEvent = NULL;
return ERROR_INTERNAL_ERROR;
}
}
device->isOpened = TRUE;
return CHANNEL_RC_OK;
}
static UINT device_server_close(CameraDeviceServerContext* context)
{
UINT error = CHANNEL_RC_OK;
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (!device->externalThread && device->thread)
{
SetEvent(device->stopEvent);
if (WaitForSingleObject(device->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(device->thread);
CloseHandle(device->stopEvent);
device->thread = NULL;
device->stopEvent = NULL;
}
if (device->externalThread)
{
if (device->state != CAMERA_DEVICE_INITIAL)
{
WTSVirtualChannelClose(device->device_channel);
device->device_channel = NULL;
device->state = CAMERA_DEVICE_INITIAL;
}
}
device->isOpened = FALSE;
return error;
}
static UINT device_server_context_poll(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (!device->externalThread)
return ERROR_INTERNAL_ERROR;
return device_server_context_poll_int(context);
}
static BOOL device_server_context_handle(CameraDeviceServerContext* context, HANDLE* handle)
{
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
WINPR_ASSERT(handle);
if (!device->externalThread)
return FALSE;
if (device->state == CAMERA_DEVICE_INITIAL)
return FALSE;
*handle = device_server_get_channel_handle(device);
return TRUE;
}
static wStream* device_server_packet_new(size_t size, BYTE version, BYTE messageId)
{
wStream* s;
/* Allocate what we need plus header bytes */
s = Stream_New(NULL, size + CAM_HEADER_SIZE);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return NULL;
}
Stream_Write_UINT8(s, version);
Stream_Write_UINT8(s, messageId);
return s;
}
static UINT device_server_packet_send(CameraDeviceServerContext* context, wStream* s)
{
device_server* device = (device_server*)context;
UINT error = CHANNEL_RC_OK;
ULONG written;
WINPR_ASSERT(context);
WINPR_ASSERT(s);
if (!WTSVirtualChannelWrite(device->device_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
error = ERROR_INTERNAL_ERROR;
goto out;
}
if (written < Stream_GetPosition(s))
{
WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
Stream_GetPosition(s));
}
out:
Stream_Free(s, TRUE);
return error;
}
static UINT device_server_write_and_send_header(CameraDeviceServerContext* context, BYTE messageId)
{
wStream* s;
WINPR_ASSERT(context);
s = device_server_packet_new(0, context->protocolVersion, messageId);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
return device_server_packet_send(context, s);
}
static UINT
device_send_activate_device_request_pdu(CameraDeviceServerContext* context,
const CAM_ACTIVATE_DEVICE_REQUEST* activateDeviceRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_ActivateDeviceRequest);
}
static UINT device_send_deactivate_device_request_pdu(
CameraDeviceServerContext* context,
const CAM_DEACTIVATE_DEVICE_REQUEST* deactivateDeviceRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_DeactivateDeviceRequest);
}
static UINT device_send_stream_list_request_pdu(CameraDeviceServerContext* context,
const CAM_STREAM_LIST_REQUEST* streamListRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_StreamListRequest);
}
static UINT
device_send_media_type_list_request_pdu(CameraDeviceServerContext* context,
const CAM_MEDIA_TYPE_LIST_REQUEST* mediaTypeListRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(mediaTypeListRequest);
s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_MediaTypeListRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, mediaTypeListRequest->StreamIndex);
return device_server_packet_send(context, s);
}
static UINT device_send_current_media_type_request_pdu(
CameraDeviceServerContext* context,
const CAM_CURRENT_MEDIA_TYPE_REQUEST* currentMediaTypeRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(currentMediaTypeRequest);
s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_CurrentMediaTypeRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, currentMediaTypeRequest->StreamIndex);
return device_server_packet_send(context, s);
}
static UINT
device_send_start_streams_request_pdu(CameraDeviceServerContext* context,
const CAM_START_STREAMS_REQUEST* startStreamsRequest)
{
wStream* s;
size_t i;
WINPR_ASSERT(context);
WINPR_ASSERT(startStreamsRequest);
s = device_server_packet_new(startStreamsRequest->N_Infos * 27ul, context->protocolVersion,
CAM_MSG_ID_StartStreamsRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
for (i = 0; i < startStreamsRequest->N_Infos; ++i)
{
const CAM_START_STREAM_INFO* info = &startStreamsRequest->StartStreamsInfo[i];
const CAM_MEDIA_TYPE_DESCRIPTION* description = &info->MediaTypeDescription;
Stream_Write_UINT8(s, info->StreamIndex);
Stream_Write_UINT8(s, description->Format);
Stream_Write_UINT32(s, description->Width);
Stream_Write_UINT32(s, description->Height);
Stream_Write_UINT32(s, description->FrameRateNumerator);
Stream_Write_UINT32(s, description->FrameRateDenominator);
Stream_Write_UINT32(s, description->PixelAspectRatioNumerator);
Stream_Write_UINT32(s, description->PixelAspectRatioDenominator);
Stream_Write_UINT8(s, description->Flags);
}
return device_server_packet_send(context, s);
}
static UINT device_send_stop_streams_request_pdu(CameraDeviceServerContext* context,
const CAM_STOP_STREAMS_REQUEST* stopStreamsRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_StopStreamsRequest);
}
static UINT device_send_sample_request_pdu(CameraDeviceServerContext* context,
const CAM_SAMPLE_REQUEST* sampleRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(sampleRequest);
s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_SampleRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, sampleRequest->StreamIndex);
return device_server_packet_send(context, s);
}
static UINT
device_send_property_list_request_pdu(CameraDeviceServerContext* context,
const CAM_PROPERTY_LIST_REQUEST* propertyListRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_PropertyListRequest);
}
static UINT
device_send_property_value_request_pdu(CameraDeviceServerContext* context,
const CAM_PROPERTY_VALUE_REQUEST* propertyValueRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(propertyValueRequest);
s = device_server_packet_new(2, context->protocolVersion, CAM_MSG_ID_PropertyValueRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, propertyValueRequest->PropertySet);
Stream_Write_UINT8(s, propertyValueRequest->PropertyId);
return device_server_packet_send(context, s);
}
static UINT device_send_set_property_value_request_pdu(
CameraDeviceServerContext* context,
const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(setPropertyValueRequest);
s = device_server_packet_new(2 + 5, context->protocolVersion,
CAM_MSG_ID_SetPropertyValueRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, setPropertyValueRequest->PropertySet);
Stream_Write_UINT8(s, setPropertyValueRequest->PropertyId);
Stream_Write_UINT8(s, setPropertyValueRequest->PropertyValue.Mode);
Stream_Write_INT32(s, setPropertyValueRequest->PropertyValue.Value);
return device_server_packet_send(context, s);
}
CameraDeviceServerContext* camera_device_server_context_new(HANDLE vcm)
{
device_server* device = (device_server*)calloc(1, sizeof(device_server));
if (!device)
return NULL;
device->context.vcm = vcm;
device->context.Initialize = device_server_initialize;
device->context.Open = device_server_open;
device->context.Close = device_server_close;
device->context.Poll = device_server_context_poll;
device->context.ChannelHandle = device_server_context_handle;
device->context.ActivateDeviceRequest = device_send_activate_device_request_pdu;
device->context.DeactivateDeviceRequest = device_send_deactivate_device_request_pdu;
device->context.StreamListRequest = device_send_stream_list_request_pdu;
device->context.MediaTypeListRequest = device_send_media_type_list_request_pdu;
device->context.CurrentMediaTypeRequest = device_send_current_media_type_request_pdu;
device->context.StartStreamsRequest = device_send_start_streams_request_pdu;
device->context.StopStreamsRequest = device_send_stop_streams_request_pdu;
device->context.SampleRequest = device_send_sample_request_pdu;
device->context.PropertyListRequest = device_send_property_list_request_pdu;
device->context.PropertyValueRequest = device_send_property_value_request_pdu;
device->context.SetPropertyValueRequest = device_send_set_property_value_request_pdu;
device->buffer = Stream_New(NULL, 4096);
if (!device->buffer)
goto fail;
return &device->context;
fail:
camera_device_server_context_free(&device->context);
return NULL;
}
void camera_device_server_context_free(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
if (device)
{
device_server_close(context);
Stream_Free(device->buffer, TRUE);
}
free(context->virtualChannelName);
free(device);
}

View File

@ -1386,6 +1386,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
return CHANNEL_RC_OK;
error_out:
free(context);
free(rdpei->contactPoints);
free(rdpei);
return error;
}

View File

@ -99,8 +99,6 @@ UINT rdpei_server_init(RdpeiServerContext* context)
void* buffer = NULL;
DWORD bytesReturned;
RdpeiServerPrivate* priv = context->priv;
UINT32 channelId;
BOOL status = TRUE;
priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME,
WTS_CHANNEL_OPTION_DYNAMIC);
@ -110,15 +108,6 @@ UINT rdpei_server_init(RdpeiServerContext* context)
return CHANNEL_RC_INITIALIZATION_ERROR;
}
channelId = WTSChannelGetIdByHandle(priv->channelHandle);
IFCALLRET(context->onChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->onChannelIdAssigned failed!");
goto out_close;
}
if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer,
&bytesReturned) ||
(bytesReturned != sizeof(HANDLE)))
@ -623,7 +612,6 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version,
{
ULONG written;
RdpeiServerPrivate* priv = context->priv;
UINT32 pduLen = 4;
if (priv->automataState != STATE_INITIAL)
{
@ -633,17 +621,14 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version,
Stream_SetPosition(priv->outputStream, 0);
if (version >= RDPINPUT_PROTOCOL_V300)
pduLen += 4;
if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen))
if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4))
{
WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen);
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4);
Stream_Write_UINT32(priv->outputStream, version);
if (version >= RDPINPUT_PROTOCOL_V300)
Stream_Write_UINT32(priv->outputStream, features);

View File

@ -163,12 +163,11 @@ fail:
static BOOL rdpgfx_is_capability_filtered(RDPGFX_PLUGIN* gfx, UINT32 caps)
{
const UINT32 filter = gfx->capsFilter;
const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81,
RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101,
RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105,
RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
RDPGFX_CAPVERSION_107 };
const UINT32 capList[] = {
RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10,
RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106
};
UINT32 x;
for (x = 0; x < ARRAYSIZE(capList); x++)
@ -191,7 +190,7 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback)
RdpgfxClientContext* context;
RDPGFX_CAPSET* capsSet;
RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 };
RDPGFX_CAPS_ADVERTISE_PDU pdu = { 0 };
RDPGFX_CAPS_ADVERTISE_PDU pdu;
if (!callback)
return ERROR_BAD_ARGUMENTS;
@ -324,25 +323,6 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback)
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_106_ERR;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
}
if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107))
{
capsSet = &capsSets[pdu.capsSetCount++];
capsSet->version = RDPGFX_CAPVERSION_107;
capsSet->length = 0x4;
capsSet->flags = caps10Flags;
#if !defined(CAIRO_FOUND) && !defined(SWSCALE_FOUND)
capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE;
#endif
}
}
return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu);
@ -915,8 +895,6 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream
case RDPGFX_CAPVERSION_104:
case RDPGFX_CAPVERSION_105:
case RDPGFX_CAPVERSION_106:
case RDPGFX_CAPVERSION_106_ERR:
case RDPGFX_CAPVERSION_107:
if (gfx->SendQoeAck)
{
RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe;
@ -1021,19 +999,6 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
cmd.data = pdu.bitmapData;
cmd.extra = NULL;
if (cmd.right < cmd.left)
{
WLog_Print(gfx->log, WLOG_ERROR, "RecvWireToSurface1Pdu right=%" PRIu32 " < left=%" PRIu32,
cmd.right, cmd.left);
return ERROR_INVALID_DATA;
}
if (cmd.bottom < cmd.top)
{
WLog_Print(gfx->log, WLOG_ERROR, "RecvWireToSurface1Pdu bottom=%" PRIu32 " < top=%" PRIu32,
cmd.bottom, cmd.top);
return ERROR_INVALID_DATA;
}
if ((error = rdpgfx_decode(gfx, &cmd)))
WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_decode failed with error %" PRIu32 "!", error);

View File

@ -1,4 +1,4 @@
/**
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Graphics Pipeline Extension
*
@ -24,7 +24,6 @@
#endif
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <freerdp/channels/log.h>
@ -111,9 +110,6 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId)
*/
UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
{
WINPR_ASSERT(s);
WINPR_ASSERT(header);
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "calloc failed!");
@ -123,13 +119,6 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
if ((header->pduLength < 8) || (Stream_GetRemainingLength(s) < (header->pduLength - 8)))
{
WLog_ERR(TAG, "header->pduLength %u less than 8!", header->pduLength);
return ERROR_INVALID_DATA;
}
return CHANNEL_RC_OK;
}

View File

@ -1428,8 +1428,6 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
PULONG pSessionId = NULL;
DWORD BytesReturned = 0;
priv->SessionId = WTS_CURRENT_SESSION;
UINT32 channelId;
BOOL status = TRUE;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
@ -1449,15 +1447,6 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
return FALSE;
}
channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
goto out_close;
}
/* Query for channel event handle */
if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) ||

View File

@ -213,6 +213,10 @@ static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMA
break;
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
break;
default:
return FALSE;
}

View File

@ -139,99 +139,86 @@ static void rdpsnd_mac_release(rdpsndMacPlugin *mac)
static BOOL rdpsnd_mac_open(rdpsndDevicePlugin *device, const AUDIO_FORMAT *format, UINT32 latency)
{
@autoreleasepool
{
AudioDeviceID outputDeviceID;
UInt32 propertySize;
OSStatus err;
NSError *error;
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
AudioObjectPropertyAddress propertyAddress = {
kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal,
#if defined(MAC_OS_VERSION_12_0)
kAudioObjectPropertyElementMain
#else
kAudioObjectPropertyElementMaster
#endif
};
AudioDeviceID outputDeviceID;
UInt32 propertySize;
OSStatus err;
NSError *error;
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDefaultSystemOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
if (mac->isOpen)
return TRUE;
if (!rdpsnd_mac_set_format(device, format, latency))
return FALSE;
propertySize = sizeof(outputDeviceID);
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL,
&propertySize, &outputDeviceID);
if (err)
{
WLog_ERR(TAG, "AudioHardwareGetProperty: %s", FormatError(err));
return FALSE;
}
mac->engine = [[AVAudioEngine alloc] init];
if (!mac->engine)
return FALSE;
err = AudioUnitSetProperty(mac->engine.outputNode.audioUnit,
kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
0, &outputDeviceID, sizeof(outputDeviceID));
if (err)
{
rdpsnd_mac_release(mac);
WLog_ERR(TAG, "AudioUnitSetProperty: %s", FormatError(err));
return FALSE;
}
mac->player = [[AVAudioPlayerNode alloc] init];
if (!mac->player)
{
rdpsnd_mac_release(mac);
WLog_ERR(TAG, "AVAudioPlayerNode::init() failed");
return FALSE;
}
[mac->engine attachNode:mac->player];
[mac->engine connect:mac->player to:mac->engine.mainMixerNode format:nil];
[mac->engine prepare];
if (![mac->engine startAndReturnError:&error])
{
device->Close(device);
WLog_ERR(TAG, "Failed to start audio player %s",
[error.localizedDescription UTF8String]);
return FALSE;
}
mac->isOpen = TRUE;
if (mac->isOpen)
return TRUE;
if (!rdpsnd_mac_set_format(device, format, latency))
return FALSE;
propertySize = sizeof(outputDeviceID);
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL,
&propertySize, &outputDeviceID);
if (err)
{
WLog_ERR(TAG, "AudioHardwareGetProperty: %s", FormatError(err));
return FALSE;
}
mac->engine = [[AVAudioEngine alloc] init];
if (!mac->engine)
return FALSE;
err = AudioUnitSetProperty(mac->engine.outputNode.audioUnit,
kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0,
&outputDeviceID, sizeof(outputDeviceID));
if (err)
{
rdpsnd_mac_release(mac);
WLog_ERR(TAG, "AudioUnitSetProperty: %s", FormatError(err));
return FALSE;
}
mac->player = [[AVAudioPlayerNode alloc] init];
if (!mac->player)
{
rdpsnd_mac_release(mac);
WLog_ERR(TAG, "AVAudioPlayerNode::init() failed");
return FALSE;
}
[mac->engine attachNode:mac->player];
[mac->engine connect:mac->player to:mac->engine.mainMixerNode format:nil];
[mac->engine prepare];
if (![mac->engine startAndReturnError:&error])
{
device->Close(device);
WLog_ERR(TAG, "Failed to start audio player %s", [error.localizedDescription UTF8String]);
return FALSE;
}
mac->isOpen = TRUE;
return TRUE;
}
static void rdpsnd_mac_close(rdpsndDevicePlugin *device)
{
@autoreleasepool
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
if (mac->isPlaying)
{
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
if (mac->isPlaying)
{
[mac->player stop];
mac->isPlaying = FALSE;
}
if (mac->isOpen)
{
[mac->engine stop];
mac->isOpen = FALSE;
}
rdpsnd_mac_release(mac);
[mac->player stop];
mac->isPlaying = FALSE;
}
if (mac->isOpen)
{
[mac->engine stop];
mac->isOpen = FALSE;
}
rdpsnd_mac_release(mac);
}
static void rdpsnd_mac_free(rdpsndDevicePlugin *device)
@ -259,118 +246,108 @@ static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin *device, const AUDIO_
static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin *device, UINT32 value)
{
@autoreleasepool
{
Float32 fVolume;
UINT16 volumeLeft;
UINT16 volumeRight;
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
Float32 fVolume;
UINT16 volumeLeft;
UINT16 volumeRight;
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
if (!mac->player)
return FALSE;
if (!mac->player)
return FALSE;
volumeLeft = (value & 0xFFFF);
volumeRight = ((value >> 16) & 0xFFFF);
fVolume = ((float)volumeLeft) / 65535.0f;
volumeLeft = (value & 0xFFFF);
volumeRight = ((value >> 16) & 0xFFFF);
fVolume = ((float)volumeLeft) / 65535.0f;
mac->player.volume = fVolume;
mac->player.volume = fVolume;
return TRUE;
}
return TRUE;
}
static void rdpsnd_mac_start(rdpsndDevicePlugin *device)
{
@autoreleasepool
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
if (!mac->isPlaying)
{
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
if (!mac->isPlaying)
if (!mac->engine.isRunning)
{
if (!mac->engine.isRunning)
NSError *error;
if (![mac->engine startAndReturnError:&error])
{
NSError *error;
if (![mac->engine startAndReturnError:&error])
{
device->Close(device);
WLog_ERR(TAG, "Failed to start audio player %s",
[error.localizedDescription UTF8String]);
return;
}
device->Close(device);
WLog_ERR(TAG, "Failed to start audio player %s",
[error.localizedDescription UTF8String]);
return;
}
[mac->player play];
mac->isPlaying = TRUE;
mac->diff = 100; /* Initial latency, corrected after first sample is played. */
}
[mac->player play];
mac->isPlaying = TRUE;
mac->diff = 100; /* Initial latency, corrected after first sample is played. */
}
}
static UINT rdpsnd_mac_play(rdpsndDevicePlugin *device, const BYTE *data, size_t size)
{
@autoreleasepool
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
AVAudioPCMBuffer *buffer;
AVAudioFormat *format;
float *const *db;
size_t pos, step, x;
AVAudioFrameCount count;
UINT64 start = GetTickCount64();
if (!mac->isOpen)
return 0;
step = 2 * mac->format.nChannels;
count = size / step;
format = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
sampleRate:mac->format.nSamplesPerSec
channels:mac->format.nChannels
interleaved:NO];
if (!format)
{
rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device;
AVAudioPCMBuffer *buffer;
AVAudioFormat *format;
float *const *db;
size_t pos, step, x;
AVAudioFrameCount count;
UINT64 start = GetTickCount64();
if (!mac->isOpen)
return 0;
step = 2 * mac->format.nChannels;
count = size / step;
format = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
sampleRate:mac->format.nSamplesPerSec
channels:mac->format.nChannels
interleaved:NO];
if (!format)
{
WLog_WARN(TAG, "AVAudioFormat::init() failed");
return 0;
}
buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:count];
[format release];
if (!buffer)
{
WLog_WARN(TAG, "AVAudioPCMBuffer::init() failed");
return 0;
}
buffer.frameLength = buffer.frameCapacity;
db = buffer.floatChannelData;
for (pos = 0; pos < count; pos++)
{
const BYTE *d = &data[pos * step];
for (x = 0; x < mac->format.nChannels; x++)
{
const float val = (int16_t)((uint16_t)d[0] | ((uint16_t)d[1] << 8)) / 32768.0f;
db[x][pos] = val;
d += sizeof(int16_t);
}
}
rdpsnd_mac_start(device);
[mac->player scheduleBuffer:buffer
completionHandler:^{
UINT64 stop = GetTickCount64();
if (start > stop)
mac->diff = 0;
else
mac->diff = stop - start;
}];
[buffer release];
return mac->diff > UINT_MAX ? UINT_MAX : mac->diff;
WLog_WARN(TAG, "AVAudioFormat::init() failed");
return 0;
}
buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:count];
if (!buffer)
{
[format release];
WLog_WARN(TAG, "AVAudioPCMBuffer::init() failed");
return 0;
}
buffer.frameLength = buffer.frameCapacity;
db = buffer.floatChannelData;
for (pos = 0; pos < count; pos++)
{
const BYTE *d = &data[pos * step];
for (x = 0; x < mac->format.nChannels; x++)
{
const float val = (int16_t)((uint16_t)d[0] | ((uint16_t)d[1] << 8)) / 32768.0f;
db[x][pos] = val;
d += sizeof(int16_t);
}
}
rdpsnd_mac_start(device);
[mac->player scheduleBuffer:buffer
completionHandler:^{
UINT64 stop = GetTickCount64();
if (start > stop)
mac->diff = 0;
else
mac->diff = stop - start;
}];
return mac->diff > UINT_MAX ? UINT_MAX : mac->diff;
}
#ifdef BUILTIN_CHANNELS

View File

@ -117,6 +117,10 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, const AUDIO_
break;
case WAVE_FORMAT_MULAW:
case WAVE_FORMAT_ALAW:
break;
default:
return FALSE;
}

View File

@ -25,9 +25,6 @@ include_directories(..)
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
if (NOT BUILTIN_CHANNELS)
list(APPEND ${MODULE_PREFIX}_LIBS freerdp-client)
endif()
list(APPEND ${MODULE_PREFIX}_LIBS freerdp)
list(APPEND ${MODULE_PREFIX}_LIBS winpr)

View File

@ -23,15 +23,11 @@
#include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <winpr/cmdline.h>
@ -55,39 +51,8 @@ struct rdpsnd_pulse_plugin
pa_stream* stream;
UINT32 latency;
UINT32 volume;
time_t reconnect_delay_seconds;
time_t reconnect_time;
};
static BOOL rdpsnd_check_pulse(rdpsndPulsePlugin* pulse, BOOL haveStream)
{
BOOL rc = TRUE;
WINPR_ASSERT(pulse);
if (!pulse->context)
{
WLog_WARN(TAG, "pulse->context=%p", pulse->context);
rc = FALSE;
}
if (haveStream)
{
if (!pulse->stream)
{
WLog_WARN(TAG, "pulse->stream=%p", pulse->stream);
rc = FALSE;
}
}
if (!pulse->mainloop)
{
WLog_WARN(TAG, "pulse->mainloop=%p", pulse->mainloop);
rc = FALSE;
}
return rc;
}
static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format);
static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int eol,
@ -100,8 +65,7 @@ static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int
;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(c);
if (!rdpsnd_check_pulse(pulse, FALSE) || !i)
if (!pulse || !c || !i)
return;
for (x = 0; x < i->volume.channels; x++)
@ -133,10 +97,6 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
{
pa_context_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(context);
WINPR_ASSERT(pulse);
state = pa_context_get_state(context);
switch (state)
@ -146,14 +106,6 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
break;
case PA_CONTEXT_FAILED:
// Destroy context now, create new one for next connection attempt
pa_context_unref(pulse->context);
pulse->context = NULL;
if (pulse->reconnect_delay_seconds >= 0)
pulse->reconnect_time = time(NULL) + pulse->reconnect_delay_seconds;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
case PA_CONTEXT_TERMINATED:
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
@ -165,17 +117,21 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
{
BOOL rc;
pa_operation* o;
pa_context_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!rdpsnd_check_pulse(pulse, FALSE))
if (!pulse->context)
return FALSE;
if (pa_context_connect(pulse->context, NULL, 0, NULL))
{
return FALSE;
}
pa_threaded_mainloop_lock(pulse->mainloop);
if (pa_context_connect(pulse->context, NULL, 0, NULL) < 0)
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
@ -201,35 +157,27 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
if (o)
pa_operation_unref(o);
pa_threaded_mainloop_unlock(pulse->mainloop);
if (state == PA_CONTEXT_READY)
{
rc = TRUE;
return TRUE;
}
else
{
pa_context_disconnect(pulse->context);
rc = FALSE;
return FALSE;
}
pa_threaded_mainloop_unlock(pulse->mainloop);
return rc;
}
static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
}
static void rdpsnd_pulse_wait_for_operation(rdpsndPulsePlugin* pulse, pa_operation* operation)
{
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
if (!operation)
return;
@ -245,11 +193,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
{
pa_stream_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(stream);
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
state = pa_stream_get_state(stream);
switch (state)
@ -260,8 +203,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
// Stream object is about to be destroyed, clean up our pointer
pulse->stream = NULL;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
@ -273,11 +214,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
static void rdpsnd_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata;
WINPR_ASSERT(stream);
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
pa_threaded_mainloop_signal(pulse->mainloop, 0);
}
@ -285,20 +221,15 @@ static void rdpsnd_pulse_close(rdpsndDevicePlugin* device)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
WINPR_ASSERT(pulse);
if (!rdpsnd_check_pulse(pulse, FALSE))
if (!pulse->context || !pulse->stream)
return;
pa_threaded_mainloop_lock(pulse->mainloop);
if (pulse->stream)
{
rdpsnd_pulse_wait_for_operation(
pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse));
pa_stream_disconnect(pulse->stream);
pa_stream_unref(pulse->stream);
pulse->stream = NULL;
}
rdpsnd_pulse_wait_for_operation(
pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse));
pa_stream_disconnect(pulse->stream);
pa_stream_unref(pulse->stream);
pulse->stream = NULL;
pa_threaded_mainloop_unlock(pulse->mainloop);
}
@ -306,9 +237,7 @@ static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_F
{
pa_sample_spec sample_spec = { 0 };
WINPR_ASSERT(format);
if (!rdpsnd_check_pulse(pulse, FALSE))
if (!pulse->context)
return FALSE;
if (!rdpsnd_pulse_format_supported(&pulse->device, format))
@ -352,52 +281,30 @@ static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_F
return TRUE;
}
static BOOL rdpsnd_pulse_context_connect(rdpsndDevicePlugin* device)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
if (!pulse->context)
return FALSE;
pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse);
if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse))
return FALSE;
return TRUE;
}
static BOOL rdpsnd_pulse_open_stream(rdpsndDevicePlugin* device)
static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format,
UINT32 latency)
{
pa_stream_state_t state;
pa_stream_flags_t flags;
pa_buffer_attr buffer_attr = { 0 };
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0 };
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->context || pulse->stream)
return TRUE;
if (!rdpsnd_pulse_set_format_spec(pulse, format))
return FALSE;
pulse->latency = latency;
if (pa_sample_spec_valid(&pulse->sample_spec) == 0)
{
pa_sample_spec_snprint(ss, sizeof(ss), &pulse->sample_spec);
return FALSE;
return TRUE;
}
pa_threaded_mainloop_lock(pulse->mainloop);
if (!pulse->context)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
if (pulse->reconnect_delay_seconds >= 0 && time(NULL) - pulse->reconnect_time >= 0)
rdpsnd_pulse_context_connect(device);
pa_threaded_mainloop_lock(pulse->mainloop);
}
if (!rdpsnd_check_pulse(pulse, FALSE))
{
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
}
pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL);
if (!pulse->stream)
@ -413,22 +320,19 @@ static BOOL rdpsnd_pulse_open_stream(rdpsndDevicePlugin* device)
if (pulse->latency > 0)
{
buffer_attr.maxlength = UINT32_MAX;
buffer_attr.maxlength = pa_usec_to_bytes(pulse->latency * 2 * 1000, &pulse->sample_spec);
buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec);
buffer_attr.prebuf = UINT32_MAX;
buffer_attr.minreq = UINT32_MAX;
buffer_attr.fragsize = UINT32_MAX;
buffer_attr.prebuf = (UINT32)-1;
buffer_attr.minreq = (UINT32)-1;
buffer_attr.fragsize = (UINT32)-1;
flags |= PA_STREAM_ADJUST_LATENCY;
}
if (pa_stream_connect_playback(pulse->stream, pulse->device_name,
pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0)
{
WLog_ERR(TAG, "error connecting playback stream");
pa_stream_unref(pulse->stream);
pulse->stream = NULL;
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
return TRUE;
}
for (;;)
@ -455,24 +359,6 @@ static BOOL rdpsnd_pulse_open_stream(rdpsndDevicePlugin* device)
return FALSE;
}
static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format,
UINT32 latency)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
WINPR_ASSERT(format);
if (!rdpsnd_check_pulse(pulse, FALSE))
return TRUE;
if (!rdpsnd_pulse_set_format_spec(pulse, format))
return FALSE;
pulse->latency = latency;
return rdpsnd_pulse_open_stream(device);
}
static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
@ -483,7 +369,9 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
rdpsnd_pulse_close(device);
if (pulse->mainloop)
{
pa_threaded_mainloop_stop(pulse->mainloop);
}
if (pulse->context)
{
@ -506,7 +394,6 @@ static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_
AUDIO_FORMAT* defaultFormat)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse || !defaultFormat)
return FALSE;
@ -528,9 +415,6 @@ static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_
BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format)
{
WINPR_ASSERT(device);
WINPR_ASSERT(format);
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
@ -543,7 +427,15 @@ BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMA
break;
default:
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) &&
(format->wBitsPerSample == 8) &&
(format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
{
return TRUE;
}
break;
}
@ -555,51 +447,39 @@ static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device)
pa_operation* o;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!rdpsnd_check_pulse(pulse, FALSE))
if (!pulse)
return 0;
if (!pulse->context || !pulse->mainloop)
return 0;
pa_threaded_mainloop_lock(pulse->mainloop);
o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse);
if (o)
pa_operation_unref(o);
pa_operation_unref(o);
pa_threaded_mainloop_unlock(pulse->mainloop);
return pulse->volume;
}
static void rdpsnd_set_volume_success_cb(pa_context* c, int success, void* userdata)
{
rdpsndPulsePlugin* pulse = userdata;
if (!rdpsnd_check_pulse(pulse, TRUE))
return;
WINPR_ASSERT(c);
WLog_INFO(TAG, "%s: %d", __FUNCTION__, success);
}
static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{
pa_cvolume cv = { 0 };
pa_cvolume cv;
pa_volume_t left;
pa_volume_t right;
pa_operation* operation;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!rdpsnd_check_pulse(pulse, TRUE))
{
WLog_WARN(TAG, "%s called before pulse backend was initialized");
if (!pulse->context || !pulse->stream)
return FALSE;
}
left = (pa_volume_t)(value & 0xFFFF);
right = (pa_volume_t)((value >> 16) & 0xFFFF);
pa_cvolume_init(&cv);
cv.channels = 2;
cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / PA_VOLUME_NORM;
cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / PA_VOLUME_NORM;
cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF;
cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF;
pa_threaded_mainloop_lock(pulse->mainloop);
operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream),
&cv, rdpsnd_set_volume_success_cb, pulse);
&cv, NULL, NULL);
if (operation)
pa_operation_unref(operation);
@ -611,38 +491,28 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size)
{
size_t length;
void* pa_data;
int status;
pa_usec_t latency;
int negative;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!data)
if (!pulse->stream || !data)
return 0;
pa_threaded_mainloop_lock(pulse->mainloop);
if (!rdpsnd_check_pulse(pulse, TRUE))
{
pa_threaded_mainloop_unlock(pulse->mainloop);
// Discard this playback request and just attempt to reconnect the stream
WLog_DBG(TAG, "reconnecting playback stream");
rdpsnd_pulse_open_stream(device);
return 0;
}
while (size > 0)
{
length = size;
while ((length = pa_stream_writable_size(pulse->stream)) == 0)
pa_threaded_mainloop_wait(pulse->mainloop);
status = pa_stream_begin_write(pulse->stream, &pa_data, &length);
if (status < 0)
if (length == (size_t)-1)
break;
memcpy(pa_data, data, length);
if (length > size)
length = size;
status = pa_stream_write(pulse->stream, pa_data, length, NULL, 0LL, PA_SEEK_RELATIVE);
status = pa_stream_write(pulse->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
if (status < 0)
{
@ -660,24 +530,22 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size
return latency / 1000;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = {
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
{ "reconnect_delay_seconds", COMMAND_LINE_VALUE_REQUIRED, "<reconnect_delay_seconds>", NULL,
NULL, -1, NULL, "reconnect_delay_seconds" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED,
"<device>", NULL, NULL, -1, NULL, "device" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
WINPR_ASSERT(pulse);
WINPR_ASSERT(args);
status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_pulse_args, flags, pulse,
NULL, NULL);
@ -698,15 +566,6 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV
if (!pulse->device_name)
return ERROR_OUTOFMEMORY;
}
CommandLineSwitchCase(arg, "reconnect_delay_seconds")
{
unsigned long val = strtoul(arg->Value, NULL, 0);
if ((errno != 0) || (val > INT32_MAX))
return ERROR_INVALID_DATA;
pulse->reconnect_delay_seconds = val;
}
CommandLineSwitchEnd(arg)
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
@ -719,14 +578,16 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV
#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry
#endif
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
rdpsndPulsePlugin* pulse;
UINT ret;
WINPR_ASSERT(pEntryPoints);
pulse = (rdpsndPulsePlugin*)calloc(1, sizeof(rdpsndPulsePlugin));
if (!pulse)
@ -752,8 +613,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
goto error;
}
}
pulse->reconnect_delay_seconds = 5;
pulse->reconnect_time = time(NULL);
ret = CHANNEL_RC_NO_MEMORY;
pulse->mainloop = pa_threaded_mainloop_new();
@ -761,17 +620,15 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
if (!pulse->mainloop)
goto error;
pa_threaded_mainloop_lock(pulse->mainloop);
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
return FALSE;
}
if (!pulse->context)
goto error;
pa_threaded_mainloop_unlock(pulse->mainloop);
pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse);
ret = ERROR_INVALID_OPERATION;
if (!rdpsnd_pulse_context_connect((rdpsndDevicePlugin*)pulse))
if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse))
goto error;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)pulse);

View File

@ -126,10 +126,6 @@ struct rdpsnd_plugin
HANDLE thread;
wMessageQueue* queue;
BOOL initialized;
UINT16 wVersion;
UINT32 volume;
BOOL applyVolume;
};
static const char* rdpsnd_is_dyn_str(BOOL dynamic)
@ -186,7 +182,7 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
rdpsnd->ClientFormats = audio_formats_new(rdpsnd->NumberOfServerFormats);
if (!rdpsnd->ClientFormats || !rdpsnd->device)
if (!rdpsnd->ClientFormats)
return;
for (index = 0; index < rdpsnd->NumberOfServerFormats; index++)
@ -217,10 +213,6 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
UINT16 length;
UINT32 dwVolume;
UINT16 wNumberOfFormats;
if (!rdpsnd->device || (!rdpsnd->dynamic && (rdpsnd->OpenHandle == 0)))
return CHANNEL_RC_INITIALIZATION_ERROR;
dwVolume = IFCALLRESULT(0, rdpsnd->device->GetVolume, rdpsnd->device);
wNumberOfFormats = rdpsnd->NumberOfClientFormats;
length = 4 + 20;
@ -272,9 +264,9 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
UINT16 index;
UINT16 wVersion;
UINT16 wNumberOfFormats;
UINT ret = ERROR_BAD_LENGTH;
audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
rdpsnd->NumberOfServerFormats = 0;
rdpsnd->ServerFormats = NULL;
@ -289,7 +281,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream*
Stream_Seek_UINT16(s); /* wDGramPort */
Stream_Read_UINT16(s, wNumberOfFormats);
Stream_Read_UINT8(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
Stream_Read_UINT16(s, rdpsnd->wVersion); /* wVersion */
Stream_Read_UINT16(s, wVersion); /* wVersion */
Stream_Seek_UINT8(s); /* bPad */
rdpsnd->NumberOfServerFormats = wNumberOfFormats;
@ -316,7 +308,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream*
if (ret == CHANNEL_RC_OK)
{
if (rdpsnd->wVersion >= CHANNEL_VERSION_WIN_7)
if (wVersion >= CHANNEL_VERSION_WIN_7)
ret = rdpsnd_send_quality_mode_pdu(rdpsnd);
}
@ -377,20 +369,6 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
}
static BOOL rdpsnd_apply_volume(rdpsndPlugin* rdpsnd)
{
WINPR_ASSERT(rdpsnd);
if (rdpsnd->isOpen && rdpsnd->applyVolume && rdpsnd->device)
{
BOOL rc = IFCALLRESULT(TRUE, rdpsnd->device->SetVolume, rdpsnd->device, rdpsnd->volume);
if (!rc)
return FALSE;
rdpsnd->applyVolume = FALSE;
}
return TRUE;
}
static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
const AUDIO_FORMAT* format)
{
@ -439,7 +417,7 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
rdpsnd->totalPlaySize = 0;
}
return rdpsnd_apply_volume(rdpsnd);
return TRUE;
}
/**
@ -600,7 +578,6 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
UINT64 end;
UINT64 diffMS, ts;
UINT latency = 0;
UINT error;
if (Stream_GetRemainingLength(s) < size)
return ERROR_BAD_LENGTH;
@ -608,15 +585,6 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
if (rdpsnd->wCurrentFormatNo >= rdpsnd->NumberOfClientFormats)
return ERROR_INTERNAL_ERROR;
/*
* Send the first WaveConfirm PDU. The server side uses this to determine the
* network latency.
* See also [MS-RDPEA] 2.2.3.8 Wave Confirm PDU
*/
error = rdpsnd_send_wave_confirm_pdu(rdpsnd, rdpsnd->wTimeStamp, rdpsnd->cBlockNo);
if (error)
return error;
data = Stream_Pointer(s);
format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo];
WLog_Print(rdpsnd->log, WLOG_DEBUG,
@ -649,11 +617,10 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
diffMS = end - rdpsnd->wArrivalTime + latency;
ts = (rdpsnd->wTimeStamp + diffMS) % UINT16_MAX;
/*
* Send the second WaveConfirm PDU. With the first WaveConfirm PDU,
* the server side uses this second WaveConfirm PDU to determine the actual
* render latency.
*/
/* Don't send wave confirm PDU if on dynamic channel */
if (rdpsnd->dynamic)
return CHANNEL_RC_OK;
return rdpsnd_send_wave_confirm_pdu(rdpsnd, (UINT16)ts, rdpsnd->cBlockNo);
}
@ -728,7 +695,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
*/
static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
BOOL rc = TRUE;
BOOL rc;
UINT32 dwVolume;
if (Stream_GetRemainingLength(s) < 4)
@ -737,10 +704,7 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
Stream_Read_UINT32(s, dwVolume);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "",
rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume);
rdpsnd->volume = dwVolume;
rdpsnd->applyVolume = TRUE;
rc = rdpsnd_apply_volume(rdpsnd);
rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
if (!rc)
{
@ -1218,51 +1182,38 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID
UINT32 dataLength)
{
UINT32 status;
DWORD opened = 0;
WINPR_UNUSED(pData);
WINPR_UNUSED(dataLength);
status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx(
rdpsnd->InitHandle, &opened, rdpsnd->channelDef.name, rdpsnd_virtual_channel_open_event_ex);
rdpsnd->InitHandle, &rdpsnd->OpenHandle, rdpsnd->channelDef.name,
rdpsnd_virtual_channel_open_event_ex);
if (status != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "%s pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]",
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(status), status);
goto fail;
return status;
}
if (rdpsnd_process_connect(rdpsnd) != CHANNEL_RC_OK)
rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
if (!rdpsnd->dsp_context)
goto fail;
rdpsnd->OpenHandle = opened;
return CHANNEL_RC_OK;
rdpsnd->pool = StreamPool_New(TRUE, 4096);
if (!rdpsnd->pool)
goto fail;
return rdpsnd_process_connect(rdpsnd);
fail:
if (opened != 0)
rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, opened);
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Free(rdpsnd->pool);
return CHANNEL_RC_NO_MEMORY;
}
static void cleanup_internals(rdpsndPlugin* rdpsnd)
{
if (!rdpsnd)
return;
if (rdpsnd->pool)
StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
rdpsnd->NumberOfClientFormats = 0;
rdpsnd->ClientFormats = NULL;
rdpsnd->NumberOfServerFormats = 0;
rdpsnd->ServerFormats = NULL;
rdpsnd->data_in = NULL;
}
/**
* Function description
*
@ -1272,25 +1223,33 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd)
{
UINT error;
if (rdpsnd->OpenHandle != 0)
if (rdpsnd->OpenHandle == 0)
return CHANNEL_RC_OK;
if (rdpsnd->device)
IFCALL(rdpsnd->device->Close, rdpsnd->device);
error =
rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle);
if (CHANNEL_RC_OK != error)
{
DWORD opened = rdpsnd->OpenHandle;
rdpsnd->OpenHandle = 0;
if (rdpsnd->device)
IFCALL(rdpsnd->device->Close, rdpsnd->device);
error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, opened);
if (CHANNEL_RC_OK != error)
{
WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error);
return error;
}
WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error);
return error;
}
cleanup_internals(rdpsnd);
rdpsnd->OpenHandle = 0;
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
StreamPool_Free(rdpsnd->pool);
audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
rdpsnd->NumberOfClientFormats = 0;
rdpsnd->ClientFormats = NULL;
audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
rdpsnd->NumberOfServerFormats = 0;
rdpsnd->ServerFormats = NULL;
if (rdpsnd->device)
{
@ -1307,36 +1266,6 @@ static void _queue_free(void* obj)
Stream_Release(s);
}
static void free_internals(rdpsndPlugin* rdpsnd)
{
if (!rdpsnd)
return;
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Free(rdpsnd->pool);
rdpsnd->pool = NULL;
rdpsnd->dsp_context = NULL;
}
static BOOL allocate_internals(rdpsndPlugin* rdpsnd)
{
if (!rdpsnd->pool)
{
rdpsnd->pool = StreamPool_New(TRUE, 4096);
if (!rdpsnd->pool)
return FALSE;
}
if (!rdpsnd->dsp_context)
{
rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
if (!rdpsnd->dsp_context)
return FALSE;
}
return TRUE;
}
static DWORD WINAPI play_thread(LPVOID arg)
{
UINT error = CHANNEL_RC_OK;
@ -1382,22 +1311,17 @@ static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd)
if (!rdpsnd->queue)
return CHANNEL_RC_NO_MEMORY;
if (!allocate_internals(rdpsnd))
return CHANNEL_RC_NO_MEMORY;
rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL);
if (!rdpsnd->thread)
return CHANNEL_RC_INITIALIZATION_ERROR;
return CHANNEL_RC_OK;
}
void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd)
static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd)
{
if (rdpsnd)
{
if (rdpsnd->queue)
MessageQueue_PostQuit(rdpsnd->queue, 0);
MessageQueue_PostQuit(rdpsnd->queue, 0);
if (rdpsnd->thread)
{
WaitForSingleObject(rdpsnd->thread, INFINITE);
@ -1405,7 +1329,6 @@ void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd)
}
MessageQueue_Free(rdpsnd->queue);
free_internals(rdpsnd);
audio_formats_free(rdpsnd->fixed_format, 1);
free(rdpsnd->subsystem);
free(rdpsnd->device_name);
@ -1447,7 +1370,6 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L
case CHANNEL_EVENT_TERMINATED:
rdpsnd_virtual_channel_event_terminated(plugin);
plugin = NULL;
break;
case CHANNEL_EVENT_ATTACHED:
@ -1479,27 +1401,6 @@ rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* plugin)
return plugin->rdpcontext;
}
static rdpsndPlugin* allocatePlugin(void)
{
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin));
if (!rdpsnd)
goto fail;
rdpsnd->fixed_format = audio_format_new();
if (!rdpsnd->fixed_format)
goto fail;
rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
if (!rdpsnd->log)
goto fail;
rdpsnd->attached = TRUE;
return rdpsnd;
fail:
if (rdpsnd)
audio_format_free(rdpsnd->fixed_format);
return NULL;
}
/* rdpsnd is always built-in */
BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
{
@ -1510,11 +1411,12 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
if (!pEntryPoints)
return FALSE;
rdpsnd = allocatePlugin();
rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin));
if (!rdpsnd)
return FALSE;
rdpsnd->attached = TRUE;
rdpsnd->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP;
sprintf_s(rdpsnd->channelDef.name, ARRAYSIZE(rdpsnd->channelDef.name), "rdpsnd");
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
@ -1525,6 +1427,15 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
rdpsnd->rdpcontext = pEntryPointsEx->context;
}
rdpsnd->fixed_format = audio_format_new();
if (!rdpsnd->fixed_format)
{
free(rdpsnd);
return FALSE;
}
rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints,
sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
rdpsnd->InitHandle = pInitHandle;
@ -1536,7 +1447,7 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
{
WLog_ERR(TAG, "%s pVirtualChannelInitEx failed with %s [%08" PRIX32 "]",
rdpsnd_is_dyn_str(FALSE), WTSErrorToString(rc), rc);
rdpsnd_virtual_channel_event_terminated(rdpsnd);
free(rdpsnd);
return FALSE;
}
@ -1548,10 +1459,19 @@ static UINT rdpsnd_on_open(IWTSVirtualChannelCallback* pChannelCallback)
RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)callback->plugin;
if (!allocate_internals(rdpsnd))
return ERROR_OUTOFMEMORY;
rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
if (!rdpsnd->dsp_context)
goto fail;
rdpsnd->pool = StreamPool_New(TRUE, 4096);
if (!rdpsnd->pool)
goto fail;
return rdpsnd_process_connect(rdpsnd);
fail:
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Free(rdpsnd->pool);
return CHANNEL_RC_NO_MEMORY;
}
static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
@ -1559,9 +1479,7 @@ static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback
RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback;
rdpsndPlugin* plugin;
wStream* copy;
size_t len;
len = Stream_GetRemainingLength(data);
size_t len = Stream_GetRemainingLength(data);
if (!callback || !callback->plugin)
return ERROR_INVALID_PARAMETER;
@ -1590,16 +1508,22 @@ static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback)
if (rdpsnd->device)
IFCALL(rdpsnd->device->Close, rdpsnd->device);
freerdp_dsp_context_free(rdpsnd->dsp_context);
StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
StreamPool_Free(rdpsnd->pool);
cleanup_internals(rdpsnd);
audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
rdpsnd->NumberOfClientFormats = 0;
rdpsnd->ClientFormats = NULL;
audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
rdpsnd->NumberOfServerFormats = 0;
rdpsnd->ServerFormats = NULL;
if (rdpsnd->device)
{
IFCALL(rdpsnd->device->Free, rdpsnd->device);
rdpsnd->device = NULL;
}
free_internals(rdpsnd);
free(pChannelCallback);
return CHANNEL_RC_OK;
}
@ -1698,7 +1622,7 @@ UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
if (!rdpsnd)
{
rdpsnd = allocatePlugin();
rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin));
if (!rdpsnd)
{
WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
@ -1709,10 +1633,14 @@ UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
rdpsnd->iface.Connected = NULL;
rdpsnd->iface.Disconnected = NULL;
rdpsnd->iface.Terminated = rdpsnd_plugin_terminated;
rdpsnd->attached = TRUE;
rdpsnd->dynamic = TRUE;
rdpsnd->fixed_format = audio_format_new();
if (!rdpsnd->fixed_format)
goto fail;
/* user data pointer is not const, cast to avoid warning. */
rdpsnd->channelEntryPoints.pExtendedData = (void*)pEntryPoints->GetPluginData(pEntryPoints);
rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
rdpsnd->channelEntryPoints.pExtendedData = pEntryPoints->GetPluginData(pEntryPoints);
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpsnd", &rdpsnd->iface);
}
@ -1722,5 +1650,8 @@ UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
return CHANNEL_RC_BAD_CHANNEL;
}
return error;
fail:
rdpsnd_plugin_terminated(&rdpsnd->iface);
return error;
}

View File

@ -28,7 +28,6 @@
#include <string.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/print.h>
#include <winpr/stream.h>
@ -37,33 +36,17 @@
#include "rdpsnd_common.h"
#include "rdpsnd_main.h"
static wStream* rdpsnd_server_get_buffer(RdpsndServerContext* context)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
s = context->priv->rdpsnd_pdu;
Stream_SetPosition(s, 0);
return s;
}
/**
* Send Server Audio Formats and Version PDU (2.2.2.1)
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_send_formats(RdpsndServerContext* context)
static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
{
wStream* s = rdpsnd_server_get_buffer(context);
size_t pos;
UINT16 i;
BOOL status = FALSE;
ULONG written;
if (!Stream_EnsureRemainingCapacity(s, 24))
return ERROR_OUTOFMEMORY;
Stream_Write_UINT8(s, SNDC_FORMATS);
Stream_Write_UINT8(s, 0);
Stream_Seek_UINT16(s);
@ -78,9 +61,12 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context)
for (i = 0; i < context->num_server_formats; i++)
{
const AUDIO_FORMAT* format = &context->server_formats[i];
AUDIO_FORMAT format = context->server_formats[i];
// TODO: Eliminate this!!!
format.nAvgBytesPerSec =
format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8;
if (!audio_format_write(s, format))
if (!audio_format_write(s, &format))
goto fail;
}
@ -88,8 +74,6 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context)
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, pos - 4);
Stream_SetPosition(s, pos);
WINPR_ASSERT(context->priv);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written);
Stream_SetPosition(s, 0);
@ -98,7 +82,7 @@ fail:
}
/**
* Read Wave Confirm PDU (2.2.3.8) and handle callback
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
@ -108,10 +92,11 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream
BYTE confirmBlockNum;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "not enough data in stream!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, timestamp);
Stream_Read_UINT8(s, confirmBlockNum);
@ -125,39 +110,13 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream
}
/**
* Read Training Confirm PDU (2.2.3.2) and handle callback
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context, wStream* s)
{
UINT16 timestamp;
UINT16 packsize;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, timestamp);
Stream_Read_UINT16(s, packsize);
IFCALLRET(context->TrainingConfirm, error, context, timestamp, packsize);
if (error)
WLog_ERR(TAG, "context->TrainingConfirm failed with error %" PRIu32 "", error);
return error;
}
/**
* Read Quality Mode PDU (2.2.2.3)
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s)
{
WINPR_ASSERT(context);
UINT16 quality;
if (Stream_GetRemainingLength(s) < 4)
{
@ -165,34 +124,34 @@ static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStrea
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, context->qualityMode); /* wQualityMode */
Stream_Seek_UINT16(s); /* Reserved */
WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", context->qualityMode);
Stream_Read_UINT16(s, quality);
Stream_Seek_UINT16(s); // reserved
WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", quality);
return CHANNEL_RC_OK;
}
/**
* Read Client Audio Formats and Version PDU (2.2.2.2)
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
{
UINT16 i, num_known_format = 0;
UINT32 flags, vol, pitch;
UINT16 udpPort;
BYTE lastblock;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
if (Stream_GetRemainingLength(s) < 20)
{
WLog_ERR(TAG, "not enough data in stream!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, context->capsFlags); /* dwFlags */
Stream_Read_UINT32(s, context->initialVolume); /* dwVolume */
Stream_Read_UINT32(s, context->initialPitch); /* dwPitch */
Stream_Read_UINT32(s, flags); /* dwFlags */
Stream_Read_UINT32(s, vol); /* dwVolume */
Stream_Read_UINT32(s, pitch); /* dwPitch */
Stream_Read_UINT16(s, udpPort); /* wDGramPort */
Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
@ -200,8 +159,11 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
Stream_Seek_UINT8(s); /* bPad */
/* this check is only a guess as cbSize can influence the size of a format record */
if (!Stream_CheckAndLogRequiredLength(TAG, s, 18ull * context->num_client_formats))
if (Stream_GetRemainingLength(s) < context->num_client_formats * 18)
{
WLog_ERR(TAG, "not enough data in stream!");
return ERROR_INVALID_DATA;
}
if (!context->num_client_formats)
{
@ -219,26 +181,24 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
for (i = 0; i < context->num_client_formats; i++)
{
AUDIO_FORMAT* format = &context->client_formats[i];
if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
if (Stream_GetRemainingLength(s) < 18)
{
WLog_ERR(TAG, "not enough data in stream!");
error = ERROR_INVALID_DATA;
goto out_free;
}
Stream_Read_UINT16(s, format->wFormatTag);
Stream_Read_UINT16(s, format->nChannels);
Stream_Read_UINT32(s, format->nSamplesPerSec);
Stream_Read_UINT32(s, format->nAvgBytesPerSec);
Stream_Read_UINT16(s, format->nBlockAlign);
Stream_Read_UINT16(s, format->wBitsPerSample);
Stream_Read_UINT16(s, format->cbSize);
Stream_Read_UINT16(s, context->client_formats[i].wFormatTag);
Stream_Read_UINT16(s, context->client_formats[i].nChannels);
Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec);
Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec);
Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign);
Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample);
Stream_Read_UINT16(s, context->client_formats[i].cbSize);
if (format->cbSize > 0)
if (context->client_formats[i].cbSize > 0)
{
if (!Stream_SafeSeek(s, format->cbSize))
if (!Stream_SafeSeek(s, context->client_formats[i].cbSize))
{
WLog_ERR(TAG, "Stream_SafeSeek failed!");
error = ERROR_INTERNAL_ERROR;
@ -246,7 +206,7 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
}
}
if (format->wFormatTag != 0)
if (context->client_formats[i].wFormatTag != 0)
{
// lets call this a known format
// TODO: actually look through our own list of known formats
@ -268,19 +228,15 @@ out_free:
static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
{
DWORD nCount = 0, status;
HANDLE events[2] = { 0 };
RdpsndServerContext* context = (RdpsndServerContext*)arg;
DWORD nCount, status;
HANDLE events[8];
RdpsndServerContext* context;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
context = (RdpsndServerContext*)arg;
nCount = 0;
events[nCount++] = context->priv->channelEvent;
events[nCount++] = context->priv->StopEvent;
WINPR_ASSERT(nCount <= ARRAYSIZE(events));
while (TRUE)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
@ -325,9 +281,6 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
*/
static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
context->priv->ownThread = ownThread;
return context->Start(context);
}
@ -344,9 +297,6 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 cli
AUDIO_FORMAT* format;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
if ((client_format_index >= context->num_client_formats) || (!context->src_format))
{
WLog_ERR(TAG, "index %d is not correct.", client_format_index);
@ -421,51 +371,6 @@ out:
return error;
}
/**
* Send Training PDU (2.2.3.1)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
BYTE* data)
{
size_t end = 0;
ULONG written;
BOOL status;
wStream* s = rdpsnd_server_get_buffer(context);
if (!Stream_EnsureRemainingCapacity(s, 8))
return ERROR_INTERNAL_ERROR;
Stream_Write_UINT8(s, SNDC_TRAINING);
Stream_Write_UINT8(s, 0);
Stream_Seek_UINT16(s);
Stream_Write_UINT16(s, timestamp);
Stream_Write_UINT16(s, packsize);
if (packsize > 0)
{
if (!Stream_EnsureRemainingCapacity(s, packsize))
{
Stream_SetPosition(s, 0);
return ERROR_INTERNAL_ERROR;
}
Stream_Write(s, data, packsize);
}
end = Stream_GetPosition(s);
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, end - 4);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end,
&written);
Stream_SetPosition(s, 0);
return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
}
static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment)
{
size_t size;
@ -499,21 +404,15 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi
const BYTE* src;
AUDIO_FORMAT* format;
ULONG written;
wStream* s = context->priv->rdpsnd_pdu;
UINT error = CHANNEL_RC_OK;
wStream* s = rdpsnd_server_get_buffer(context);
if (context->selected_client_format > context->num_client_formats)
if (context->selected_client_format >= context->num_client_formats)
return ERROR_INTERNAL_ERROR;
WINPR_ASSERT(context->client_formats);
format = &context->client_formats[context->selected_client_format];
/* WaveInfo PDU */
Stream_SetPosition(s, 0);
if (!Stream_EnsureRemainingCapacity(s, 16))
return ERROR_OUTOFMEMORY;
Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
Stream_Write_UINT8(s, 0); /* bPad */
Stream_Write_UINT16(s, 0); /* BodySize */
@ -523,7 +422,7 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi
Stream_Seek(s, 3); /* bPad */
start = Stream_GetPosition(s);
src = context->priv->out_buffer;
length = 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
return ERROR_INTERNAL_ERROR;
@ -537,6 +436,7 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, end - start + 8);
Stream_SetPosition(s, end);
context->block_no = (context->block_no + 1) % 256;
if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s),
start + 4, &written))
@ -564,8 +464,6 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi
error = ERROR_INTERNAL_ERROR;
}
context->block_no = (context->block_no + 1) % 256;
out:
Stream_SetPosition(s, 0);
context->priv->out_pending_frames = 0;
@ -578,79 +476,59 @@ out:
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
const BYTE* data, size_t size, BOOL encoded,
UINT16 timestamp, UINT32 audioTimeStamp)
static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
{
size_t length;
size_t end = 0;
const BYTE* src;
AUDIO_FORMAT* format;
ULONG written;
wStream* s = context->priv->rdpsnd_pdu;
UINT error = CHANNEL_RC_OK;
BOOL status;
wStream* s = rdpsnd_server_get_buffer(context);
if (!Stream_EnsureRemainingCapacity(s, 16))
{
if (context->selected_client_format >= context->num_client_formats)
return ERROR_INTERNAL_ERROR;
format = &context->client_formats[context->selected_client_format];
/* WaveInfo PDU */
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */
Stream_Write_UINT8(s, 0); /* bPad */
Stream_Write_UINT16(s, 0); /* BodySize */
Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */
Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
Stream_Seek(s, 3); /* bPad */
Stream_Write_UINT32(s, wTimestamp); /* dwAudioTimeStamp */
src = context->priv->out_buffer;
length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
error = ERROR_INTERNAL_ERROR;
goto out;
}
/* Wave2 PDU */
Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */
Stream_Write_UINT8(s, 0); /* bPad */
Stream_Write_UINT16(s, 0); /* BodySize */
Stream_Write_UINT16(s, timestamp); /* wTimeStamp */
Stream_Write_UINT16(s, formatNo); /* wFormatNo */
Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
Stream_Write_UINT8(s, 0); /* bPad */
Stream_Write_UINT8(s, 0); /* bPad */
Stream_Write_UINT8(s, 0); /* bPad */
Stream_Write_UINT32(s, audioTimeStamp); /* dwAudioTimeStamp */
if (encoded)
{
if (!Stream_EnsureRemainingCapacity(s, size))
{
error = ERROR_INTERNAL_ERROR;
goto out;
}
Stream_Write(s, data, size);
}
else
{
AUDIO_FORMAT* format;
BOOL rc;
if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
{
error = ERROR_INTERNAL_ERROR;
goto out;
}
format = &context->client_formats[formatNo];
/* Set stream size */
if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
return ERROR_INTERNAL_ERROR;
end = Stream_GetPosition(s);
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, end - 4);
context->block_no = (context->block_no + 1) % 256;
rc = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end,
&written);
if (!rc || (end != written))
{
WLog_ERR(TAG,
"WTSVirtualChannelWrite failed! [stream length=%" PRIdz " - written=%" PRIu32,
end, written);
error = ERROR_INTERNAL_ERROR;
goto out;
}
}
end = Stream_GetPosition(s);
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, end - 4);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end,
&written);
if (!status || (end != written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed! [stream length=%" PRIdz " - written=%" PRIu32,
end, written);
error = ERROR_INTERNAL_ERROR;
}
context->block_no = (context->block_no + 1) % 256;
out:
Stream_SetPosition(s, 0);
context->priv->out_pending_frames = 0;
return error;
@ -659,21 +537,8 @@ out:
/* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */
static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
{
const BYTE* src;
size_t length;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
if (context->selected_client_format >= context->num_client_formats)
return ERROR_INTERNAL_ERROR;
src = context->priv->out_buffer;
length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
FALSE, wTimestamp, wTimestamp);
return rdpsnd_server_send_wave2_pdu(context, wTimestamp);
else
return rdpsnd_server_send_wave_pdu(context, wTimestamp);
}
@ -686,11 +551,9 @@ static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wT
static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf, int nframes,
UINT16 wTimestamp)
{
int cframes;
int cframesize;
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
EnterCriticalSection(&context->priv->lock);
if (context->selected_client_format >= context->num_client_formats)
@ -703,13 +566,12 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void*
while (nframes > 0)
{
const size_t cframes =
MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
size_t cframesize = cframes * context->priv->src_bytes_per_frame;
cframes = MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
cframesize = cframes * context->priv->src_bytes_per_frame;
CopyMemory(context->priv->out_buffer +
(context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
buf, cframesize);
buf = (const BYTE*)buf + cframesize;
buf = (BYTE*)buf + cframesize;
nframes -= cframes;
context->priv->out_pending_frames += cframes;
@ -728,33 +590,6 @@ out:
return error;
}
/**
* Send encoded audio samples using a Wave2 PDU.
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
const void* buf, size_t size, UINT16 timestamp,
UINT32 audioTimeStamp)
{
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
if (context->clientVersion < CHANNEL_VERSION_WIN_8)
return ERROR_INTERNAL_ERROR;
EnterCriticalSection(&context->priv->lock);
error =
rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
LeaveCriticalSection(&context->priv->lock);
return error;
}
/**
* Function description
*
@ -762,23 +597,21 @@ static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 for
*/
static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int right)
{
size_t len;
size_t pos;
BOOL status;
ULONG written;
wStream* s = rdpsnd_server_get_buffer(context);
if (!Stream_EnsureRemainingCapacity(s, 8))
return ERROR_NOT_ENOUGH_MEMORY;
wStream* s = context->priv->rdpsnd_pdu;
Stream_Write_UINT8(s, SNDC_SETVOLUME);
Stream_Write_UINT8(s, 0);
Stream_Write_UINT16(s, 4); /* Payload length */
Stream_Seek_UINT16(s);
Stream_Write_UINT16(s, left);
Stream_Write_UINT16(s, right);
len = Stream_GetPosition(s);
pos = Stream_GetPosition(s);
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, pos - 4);
Stream_SetPosition(s, pos);
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s),
(ULONG)len, &written);
Stream_GetPosition(s), &written);
Stream_SetPosition(s, 0);
return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
}
@ -793,9 +626,8 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context)
size_t pos;
BOOL status;
ULONG written;
wStream* s = context->priv->rdpsnd_pdu;
UINT error = CHANNEL_RC_OK;
wStream* s = rdpsnd_server_get_buffer(context);
EnterCriticalSection(&context->priv->lock);
if (context->priv->out_pending_frames > 0)
@ -817,10 +649,6 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context)
return error;
context->selected_client_format = 0xFFFF;
if (!Stream_EnsureRemainingCapacity(s, 4))
return ERROR_OUTOFMEMORY;
Stream_Write_UINT8(s, SNDC_CLOSE);
Stream_Write_UINT8(s, 0);
Stream_Seek_UINT16(s);
@ -843,58 +671,14 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context)
{
void* buffer = NULL;
DWORD bytesReturned;
RdpsndServerPrivate* priv;
RdpsndServerPrivate* priv = context->priv;
UINT error = ERROR_INTERNAL_ERROR;
PULONG pSessionId = NULL;
priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd");
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
priv = context->priv;
priv->SessionId = WTS_CURRENT_SESSION;
if (context->use_dynamic_virtual_channel)
if (!priv->ChannelHandle)
{
UINT32 channelId;
BOOL status = TRUE;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &bytesReturned))
{
priv->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
priv->ChannelHandle = (HANDLE)WTSVirtualChannelOpenEx(
priv->SessionId, "AUDIO_PLAYBACK_DVC", WTS_CHANNEL_OPTION_DYNAMIC);
if (!priv->ChannelHandle)
{
WLog_ERR(TAG, "Open audio dynamic virtual channel (AUDIO_PLAYBACK_DVC) failed!");
return ERROR_INTERNAL_ERROR;
}
channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
goto out_close;
}
}
else
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
}
else
{
priv->ChannelHandle =
WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd");
if (!priv->ChannelHandle)
{
WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!");
return ERROR_INTERNAL_ERROR;
}
WLog_ERR(TAG, "WTSVirtualChannelOpen failed!");
return ERROR_INTERNAL_ERROR;
}
if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
@ -929,7 +713,7 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context)
goto out_pdu;
}
if ((error = rdpsnd_server_send_formats(context)))
if ((error = rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu)))
{
WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error);
goto out_lock;
@ -979,12 +763,6 @@ static UINT rdpsnd_server_stop(RdpsndServerContext* context)
{
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
if (!context->priv->StopEvent)
return error;
if (context->priv->ownThread)
{
if (context->priv->StopEvent)
@ -1000,46 +778,36 @@ static UINT rdpsnd_server_stop(RdpsndServerContext* context)
CloseHandle(context->priv->Thread);
CloseHandle(context->priv->StopEvent);
context->priv->Thread = NULL;
context->priv->StopEvent = NULL;
}
}
DeleteCriticalSection(&context->priv->lock);
if (context->priv->rdpsnd_pdu)
{
Stream_Free(context->priv->rdpsnd_pdu, TRUE);
context->priv->rdpsnd_pdu = NULL;
}
if (context->priv->ChannelHandle)
{
WTSVirtualChannelClose(context->priv->ChannelHandle);
context->priv->ChannelHandle = NULL;
}
return error;
}
RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
{
RdpsndServerContext* context;
RdpsndServerPrivate* priv;
RdpsndServerContext* context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext));
context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext));
if (!context)
goto fail;
{
WLog_ERR(TAG, "calloc failed!");
return NULL;
}
context->vcm = vcm;
context->Start = rdpsnd_server_start;
context->Stop = rdpsnd_server_stop;
context->selected_client_format = 0xFFFF;
context->Initialize = rdpsnd_server_initialize;
context->SendFormats = rdpsnd_server_send_formats;
context->SelectFormat = rdpsnd_server_select_format;
context->Training = rdpsnd_server_training;
context->SendSamples = rdpsnd_server_send_samples;
context->SendSamples2 = rdpsnd_server_send_samples2;
context->SetVolume = rdpsnd_server_set_volume;
context->Close = rdpsnd_server_close;
context->priv = priv = (RdpsndServerPrivate*)calloc(1, sizeof(RdpsndServerPrivate));
@ -1047,7 +815,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
if (!priv)
{
WLog_ERR(TAG, "calloc failed!");
goto fail;
goto out_free;
}
priv->dsp_context = freerdp_dsp_context_new(TRUE);
@ -1055,7 +823,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
if (!priv->dsp_context)
{
WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
goto fail;
goto out_free_priv;
}
priv->input_stream = Stream_New(NULL, 4);
@ -1063,23 +831,24 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
if (!priv->input_stream)
{
WLog_ERR(TAG, "Stream_New failed!");
goto fail;
goto out_free_dsp;
}
priv->expectedBytes = 4;
priv->waitingHeader = TRUE;
priv->ownThread = TRUE;
return context;
fail:
rdpsnd_server_context_free(context);
out_free_dsp:
freerdp_dsp_context_free(priv->dsp_context);
out_free_priv:
free(context->priv);
out_free:
free(context);
return NULL;
}
void rdpsnd_server_context_reset(RdpsndServerContext* context)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
context->priv->expectedBytes = 4;
context->priv->waitingHeader = TRUE;
Stream_SetPosition(context->priv->input_stream, 0);
@ -1087,21 +856,16 @@ void rdpsnd_server_context_reset(RdpsndServerContext* context)
void rdpsnd_server_context_free(RdpsndServerContext* context)
{
if (!context)
return;
if (context->priv->ChannelHandle)
WTSVirtualChannelClose(context->priv->ChannelHandle);
if (context->priv)
{
rdpsnd_server_stop(context);
free(context->priv->out_buffer);
free(context->priv->out_buffer);
if (context->priv->dsp_context)
freerdp_dsp_context_free(context->priv->dsp_context);
if (context->priv->dsp_context)
freerdp_dsp_context_free(context->priv->dsp_context);
if (context->priv->input_stream)
Stream_Free(context->priv->input_stream, TRUE);
}
if (context->priv->input_stream)
Stream_Free(context->priv->input_stream, TRUE);
free(context->server_formats);
free(context->client_formats);
@ -1111,9 +875,6 @@ void rdpsnd_server_context_free(RdpsndServerContext* context)
HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
return context->priv->channelEvent;
}
@ -1135,14 +896,8 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
{
DWORD bytesReturned;
UINT ret = CHANNEL_RC_OK;
RdpsndServerPrivate* priv;
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
priv = context->priv;
s = priv->input_stream;
RdpsndServerPrivate* priv = context->priv;
wStream* s = priv->input_stream;
if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s),
priv->expectedBytes, &bytesReturned))
@ -1197,10 +952,6 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
ret = rdpsnd_server_recv_waveconfirm(context, s);
break;
case SNDC_TRAINING:
ret = rdpsnd_server_recv_trainingconfirm(context, s);
break;
case SNDC_FORMATS:
ret = rdpsnd_server_recv_formats(context, s);
@ -1211,6 +962,8 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
case SNDC_QUALITYMODE:
ret = rdpsnd_server_recv_quality_mode(context, s);
Stream_SetPosition(s,
0); /* in case the Activated callback tries to treat some messages */
if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
IFCALL(context->Activated, context);

View File

@ -39,7 +39,6 @@ struct _rdpsnd_server_private
HANDLE StopEvent;
HANDLE channelEvent;
void* ChannelHandle;
DWORD SessionId;
BOOL waitingHeader;
DWORD expectedBytes;

View File

@ -50,21 +50,9 @@
#include <freerdp/server/remdesk.h>
#include <freerdp/server/encomsp.h>
#include <freerdp/server/rail.h>
#include <freerdp/server/telemetry.h>
#include <freerdp/server/rdpgfx.h>
#include <freerdp/server/disp.h>
#if defined(CHANNEL_RDPECAM_SERVER)
#include <freerdp/server/rdpecam-enumerator.h>
#include <freerdp/server/rdpecam.h>
#endif
#if defined(CHANNEL_AINPUT_SERVER)
#include <freerdp/server/ainput.h>
#endif
extern void freerdp_channels_dummy(void);
void freerdp_channels_dummy(void)
{
audin_server_context* audin;
@ -77,13 +65,8 @@ void freerdp_channels_dummy(void)
RemdeskServerContext* remdesk;
EncomspServerContext* encomsp;
RailServerContext* rail;
TelemetryServerContext* telemetry;
RdpgfxServerContext* rdpgfx;
DispServerContext* disp;
#if defined (CHANNEL_RDPECAM_SERVER)
CamDevEnumServerContext* camera_enumerator;
CameraDeviceServerContext* camera_device;
#endif
audin = audin_server_context_new(NULL);
audin_server_context_free(audin);
rdpsnd = rdpsnd_server_context_new(NULL);
@ -104,26 +87,10 @@ void freerdp_channels_dummy(void)
encomsp_server_context_free(encomsp);
rail = rail_server_context_new(NULL);
rail_server_context_free(rail);
telemetry = telemetry_server_context_new(NULL);
telemetry_server_context_free(telemetry);
rdpgfx = rdpgfx_server_context_new(NULL);
rdpgfx_server_context_free(rdpgfx);
disp = disp_server_context_new(NULL);
disp_server_context_free(disp);
#if defined (CHANNEL_RDPECAM_SERVER)
camera_enumerator = cam_dev_enum_server_context_new(NULL);
cam_dev_enum_server_context_free(camera_enumerator);
camera_device = camera_device_server_context_new(NULL);
camera_device_server_context_free(camera_device);
#endif
#if defined(CHANNEL_AINPUT_SERVER)
{
ainput_server_context* ainput = ainput_server_context_new(NULL);
ainput_server_context_free(ainput);
}
#endif
}
/**

View File

@ -180,7 +180,6 @@ void smartcard_context_free(void* pCtx)
/* cancel blocking calls like SCardGetStatusChange */
SCardCancel(pContext->hContext);
SCardReleaseContext(pContext->hContext);
if (MessageQueue_PostQuit(pContext->IrpQueue, 0) &&
(WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED))
@ -238,7 +237,7 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
/* Put thread to sleep so that PC/SC can process the cancel requests. This fixes a race
* condition that sometimes caused the pc/sc daemon to crash on MacOS (_xpc_api_misuse) */
SleepEx(100, FALSE);
Sleep(100);
/**
* Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList.
@ -252,7 +251,27 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
for (index = 0; index < keyCount; index++)
{
ListDictionary_SetItemValue(smartcard->rgSCardContextList, (void*)pKeys[index], NULL);
pContext = (SMARTCARD_CONTEXT*)ListDictionary_Remove(smartcard->rgSCardContextList,
(void*)pKeys[index]);
if (!pContext)
continue;
hContext = pContext->hContext;
if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS)
{
SCardReleaseContext(hContext);
if (MessageQueue_PostQuit(pContext->IrpQueue, 0) &&
(WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED))
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!",
GetLastError());
CloseHandle(pContext->thread);
MessageQueue_Free(pContext->IrpQueue);
free(pContext);
}
}
free(pKeys);

View File

@ -349,16 +349,10 @@ static char* smartcard_convert_string_list(const void* in, size_t bytes, BOOL un
if (bytes < 1)
return NULL;
if (in == NULL)
return NULL;
if (unicode)
{
length = (bytes / sizeof(WCHAR)) - 1;
mszA = (char*)calloc(length + 1, sizeof(WCHAR));
if (!mszA)
return NULL;
if (ConvertFromUnicode(CP_UTF8, 0, string.wz, (int)length, &mszA, length + 1, NULL, NULL) !=
length = (bytes / 2);
if (ConvertFromUnicode(CP_UTF8, 0, string.wz, (int)length, &mszA, 0, NULL, NULL) !=
(int)length)
{
free(mszA);
@ -368,11 +362,10 @@ static char* smartcard_convert_string_list(const void* in, size_t bytes, BOOL un
else
{
length = bytes;
mszA = (char*)calloc(length, sizeof(char));
mszA = (char*)malloc(length);
if (!mszA)
return NULL;
CopyMemory(mszA, string.sz, length - 1);
mszA[length - 1] = '\0';
CopyMemory(mszA, string.sz, length);
}
for (index = 0; index < length - 1; index++)
@ -1314,24 +1307,21 @@ static void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, const Sta
static void smartcard_trace_state_return(SMARTCARD_DEVICE* smartcard, const State_Return* ret)
{
char buffer[1024];
char* state;
WINPR_UNUSED(smartcard);
if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
return;
state = SCardGetReaderStateString(ret->dwState);
WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {");
WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")",
SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
WLog_LVL(TAG, g_LogLevel, " dwState: %s (0x%08" PRIX32 ")", state, ret->dwState);
WLog_LVL(TAG, g_LogLevel, " dwProtocol: %s (0x%08" PRIX32 ")",
SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol);
WLog_LVL(TAG, g_LogLevel, " cbAtrLen: (0x%08" PRIX32 ")", ret->cbAtrLen);
WLog_LVL(TAG, g_LogLevel, " dwState: %s (0x%08" PRIX32 ")", ret->dwState);
WLog_LVL(TAG, g_LogLevel, " dwProtocol: %s (0x%08" PRIX32 ")", ret->dwProtocol);
WLog_LVL(TAG, g_LogLevel, " cbAtrLen: %s (0x%08" PRIX32 ")", ret->cbAtrLen);
WLog_LVL(TAG, g_LogLevel, " rgAtr: %s",
smartcard_array_dump(ret->rgAtr, sizeof(ret->rgAtr), buffer, sizeof(buffer)));
WLog_LVL(TAG, g_LogLevel, "}");
free(state);
}
static void smartcard_trace_reconnect_return(SMARTCARD_DEVICE* smartcard,

View File

@ -1,22 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
#
# 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("telemetry")
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -1,12 +0,0 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT OFF)
set(OPTION_SERVER_DEFAULT ON)
define_channel_options(NAME "telemetry" TYPE "dynamic"
DESCRIPTION "Telemetry Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPET]"
DEFAULT ${OPTION_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})

View File

@ -1,26 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
#
# 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("telemetry")
set(${MODULE_PREFIX}_SRCS
telemetry_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")

View File

@ -1,443 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Telemetry Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* 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 <freerdp/channels/log.h>
#include <freerdp/server/telemetry.h>
#define TAG CHANNELS_TAG("telemetry.server")
typedef enum
{
TELEMETRY_INITIAL,
TELEMETRY_OPENED,
} eTelemetryChannelState;
typedef struct
{
TelemetryServerContext context;
HANDLE stopEvent;
HANDLE thread;
void* telemetry_channel;
DWORD SessionId;
BOOL isOpened;
BOOL externalThread;
/* Channel state */
eTelemetryChannelState state;
wStream* buffer;
} telemetry_server;
static UINT telemetry_server_initialize(TelemetryServerContext* context, BOOL externalThread)
{
UINT error = CHANNEL_RC_OK;
telemetry_server* telemetry = (telemetry_server*)context;
WINPR_ASSERT(telemetry);
if (telemetry->isOpened)
{
WLog_WARN(TAG, "Application error: TELEMETRY channel already initialized, "
"calling in this state is not possible!");
return ERROR_INVALID_STATE;
}
telemetry->externalThread = externalThread;
return error;
}
static UINT telemetry_server_open_channel(telemetry_server* telemetry)
{
TelemetryServerContext* context = &telemetry->context;
DWORD Error = ERROR_SUCCESS;
HANDLE hEvent;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
UINT32 channelId;
BOOL status = TRUE;
WINPR_ASSERT(telemetry);
if (WTSQuerySessionInformationA(telemetry->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
telemetry->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(telemetry->context.vcm);
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
telemetry->telemetry_channel = WTSVirtualChannelOpenEx(
telemetry->SessionId, TELEMETRY_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
if (!telemetry->telemetry_channel)
{
Error = GetLastError();
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
return Error;
}
channelId = WTSChannelGetIdByHandle(telemetry->telemetry_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
return Error;
}
static UINT telemetry_server_recv_rdp_telemetry_pdu(TelemetryServerContext* context, wStream* s)
{
TELEMETRY_RDP_TELEMETRY_PDU pdu;
UINT error = CHANNEL_RC_OK;
if (Stream_GetRemainingLength(s) < 16)
{
WLog_ERR(TAG, "telemetry_server_recv_rdp_telemetry_pdu: Not enough data!");
return ERROR_NO_DATA;
}
Stream_Read_UINT32(s, pdu.PromptForCredentialsMillis);
Stream_Read_UINT32(s, pdu.PromptForCredentialsDoneMillis);
Stream_Read_UINT32(s, pdu.GraphicsChannelOpenedMillis);
Stream_Read_UINT32(s, pdu.FirstGraphicsReceivedMillis);
IFCALLRET(context->RdpTelemetry, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->RdpTelemetry failed with error %" PRIu32 "", error);
return error;
}
static UINT telemetry_process_message(telemetry_server* telemetry)
{
BOOL rc;
UINT error = ERROR_INTERNAL_ERROR;
ULONG BytesReturned;
BYTE MessageId;
BYTE Length;
wStream* s;
WINPR_ASSERT(telemetry);
WINPR_ASSERT(telemetry->telemetry_channel);
s = telemetry->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
rc = WTSVirtualChannelRead(telemetry->telemetry_channel, 0, NULL, 0, &BytesReturned);
if (!rc)
goto out;
if (BytesReturned < 1)
{
error = CHANNEL_RC_OK;
goto out;
}
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
error = CHANNEL_RC_NO_MEMORY;
goto out;
}
if (WTSVirtualChannelRead(telemetry->telemetry_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
goto out;
}
Stream_SetLength(s, BytesReturned);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, MessageId);
Stream_Read_UINT8(s, Length);
switch (MessageId)
{
case 0x01:
error = telemetry_server_recv_rdp_telemetry_pdu(&telemetry->context, s);
break;
default:
WLog_ERR(TAG, "telemetry_process_message: unknown MessageId %" PRIu8 "", MessageId);
break;
}
out:
if (error)
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
return error;
}
static UINT telemetry_server_context_poll_int(TelemetryServerContext* context)
{
telemetry_server* telemetry = (telemetry_server*)context;
UINT error = ERROR_INTERNAL_ERROR;
WINPR_ASSERT(telemetry);
switch (telemetry->state)
{
case TELEMETRY_INITIAL:
error = telemetry_server_open_channel(telemetry);
if (error)
WLog_ERR(TAG, "telemetry_server_open_channel failed with error %" PRIu32 "!",
error);
else
telemetry->state = TELEMETRY_OPENED;
break;
case TELEMETRY_OPENED:
error = telemetry_process_message(telemetry);
break;
}
return error;
}
static HANDLE telemetry_server_get_channel_handle(telemetry_server* telemetry)
{
void* buffer = NULL;
DWORD BytesReturned = 0;
HANDLE ChannelEvent = NULL;
WINPR_ASSERT(telemetry);
if (WTSVirtualChannelQuery(telemetry->telemetry_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
return ChannelEvent;
}
static DWORD WINAPI telemetry_server_thread_func(LPVOID arg)
{
DWORD nCount;
HANDLE events[2] = { 0 };
telemetry_server* telemetry = (telemetry_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
WINPR_ASSERT(telemetry);
nCount = 0;
events[nCount++] = telemetry->stopEvent;
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
{
switch (telemetry->state)
{
case TELEMETRY_INITIAL:
error = telemetry_server_context_poll_int(&telemetry->context);
if (error == CHANNEL_RC_OK)
{
events[1] = telemetry_server_get_channel_handle(telemetry);
nCount = 2;
}
break;
case TELEMETRY_OPENED:
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
switch (status)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
case WAIT_TIMEOUT:
error = telemetry_server_context_poll_int(&telemetry->context);
break;
case WAIT_FAILED:
default:
error = ERROR_INTERNAL_ERROR;
break;
}
break;
}
}
WTSVirtualChannelClose(telemetry->telemetry_channel);
telemetry->telemetry_channel = NULL;
if (error && telemetry->context.rdpcontext)
setChannelError(telemetry->context.rdpcontext, error,
"telemetry_server_thread_func reported an error");
ExitThread(error);
return error;
}
static UINT telemetry_server_open(TelemetryServerContext* context)
{
telemetry_server* telemetry = (telemetry_server*)context;
WINPR_ASSERT(telemetry);
if (!telemetry->externalThread && (telemetry->thread == NULL))
{
telemetry->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!telemetry->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
return ERROR_INTERNAL_ERROR;
}
telemetry->thread = CreateThread(NULL, 0, telemetry_server_thread_func, telemetry, 0, NULL);
if (!telemetry->thread)
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(telemetry->stopEvent);
telemetry->stopEvent = NULL;
return ERROR_INTERNAL_ERROR;
}
}
telemetry->isOpened = TRUE;
return CHANNEL_RC_OK;
}
static UINT telemetry_server_close(TelemetryServerContext* context)
{
UINT error = CHANNEL_RC_OK;
telemetry_server* telemetry = (telemetry_server*)context;
WINPR_ASSERT(telemetry);
if (!telemetry->externalThread && telemetry->thread)
{
SetEvent(telemetry->stopEvent);
if (WaitForSingleObject(telemetry->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(telemetry->thread);
CloseHandle(telemetry->stopEvent);
telemetry->thread = NULL;
telemetry->stopEvent = NULL;
}
if (telemetry->externalThread)
{
if (telemetry->state != TELEMETRY_INITIAL)
{
WTSVirtualChannelClose(telemetry->telemetry_channel);
telemetry->telemetry_channel = NULL;
telemetry->state = TELEMETRY_INITIAL;
}
}
telemetry->isOpened = FALSE;
return error;
}
static UINT telemetry_server_context_poll(TelemetryServerContext* context)
{
telemetry_server* telemetry = (telemetry_server*)context;
WINPR_ASSERT(telemetry);
if (!telemetry->externalThread)
return ERROR_INTERNAL_ERROR;
return telemetry_server_context_poll_int(context);
}
static BOOL telemetry_server_context_handle(TelemetryServerContext* context, HANDLE* handle)
{
telemetry_server* telemetry = (telemetry_server*)context;
WINPR_ASSERT(telemetry);
WINPR_ASSERT(handle);
if (!telemetry->externalThread)
return FALSE;
if (telemetry->state == TELEMETRY_INITIAL)
return FALSE;
*handle = telemetry_server_get_channel_handle(telemetry);
return TRUE;
}
TelemetryServerContext* telemetry_server_context_new(HANDLE vcm)
{
telemetry_server* telemetry = (telemetry_server*)calloc(1, sizeof(telemetry_server));
if (!telemetry)
return NULL;
telemetry->context.vcm = vcm;
telemetry->context.Initialize = telemetry_server_initialize;
telemetry->context.Open = telemetry_server_open;
telemetry->context.Close = telemetry_server_close;
telemetry->context.Poll = telemetry_server_context_poll;
telemetry->context.ChannelHandle = telemetry_server_context_handle;
telemetry->buffer = Stream_New(NULL, 4096);
if (!telemetry->buffer)
goto fail;
return &telemetry->context;
fail:
telemetry_server_context_free(&telemetry->context);
return NULL;
}
void telemetry_server_context_free(TelemetryServerContext* context)
{
telemetry_server* telemetry = (telemetry_server*)context;
if (telemetry)
{
telemetry_server_close(context);
Stream_Free(telemetry->buffer, TRUE);
}
free(telemetry);
}

View File

@ -195,12 +195,9 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
if (media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
{
size_t required = 6;
/* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
See http://haali.su/mkv/codecs.pdf */
p = mdecoder->codec_context->extradata;
if (mdecoder->codec_context->extradata_size < required)
return FALSE;
*p++ = 1; /* Reserved? */
*p++ = media_type->ExtraData[8]; /* Profile */
*p++ = 0; /* Profile */
@ -209,36 +206,23 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
*p++ = 0xe0 | 0x01; /* Reserved | #sps */
s = media_type->ExtraData + 20;
size = ((UINT32)(*s)) * 256 + ((UINT32)(*(s + 1)));
required += size + 2;
if (mdecoder->codec_context->extradata_size < required)
return FALSE;
memcpy(p, s, size + 2);
s += size + 2;
p += size + 2;
required++;
if (mdecoder->codec_context->extradata_size < required)
return FALSE;
*p++ = 1; /* #pps */
size = ((UINT32)(*s)) * 256 + ((UINT32)(*(s + 1)));
required += size + 2;
if (mdecoder->codec_context->extradata_size < required)
return FALSE;
memcpy(p, s, size + 2);
}
else
{
memcpy(mdecoder->codec_context->extradata, media_type->ExtraData,
media_type->ExtraDataSize);
if (mdecoder->codec_context->extradata_size < media_type->ExtraDataSize + 8)
return FALSE;
memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8);
}
}
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100)
if (mdecoder->codec->capabilities & AV_CODEC_CAP_TRUNCATED)
mdecoder->codec_context->flags |= AV_CODEC_FLAG_TRUNCATED;
#endif
return TRUE;
}
@ -261,9 +245,6 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
{
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder;
WINPR_ASSERT(mdecoder);
WINPR_ASSERT(media_type);
switch (media_type->MajorType)
{
case TSMF_MAJOR_TYPE_VIDEO:
@ -316,9 +297,6 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
http://msdn.microsoft.com/en-us/library/dd757806.aspx */
if (media_type->ExtraData)
{
if (media_type->ExtraDataSize < 12)
return FALSE;
media_type->ExtraData += 12;
media_type->ExtraDataSize -= 12;
}
@ -637,9 +615,7 @@ static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* context)
{
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all();
#endif
return TRUE;
}

View File

@ -420,8 +420,6 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m
http://msdn.microsoft.com/en-us/library/dd757806.aspx */
if (media_type->ExtraData)
{
if (media_type->ExtraDataSize < 12)
return FALSE;
media_type->ExtraData += 12;
media_type->ExtraDataSize -= 12;
}

View File

@ -386,12 +386,7 @@ static BOOL tsmf_read_format_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s, UINT3
if (cbFormat > 176)
{
const size_t nsize = cbFormat - 176;
if (mediatype->ExtraDataSize < nsize)
return FALSE;
if (!Stream_CheckAndLogRequiredLength(TAG, s, nsize))
return FALSE;
mediatype->ExtraDataSize = nsize;
mediatype->ExtraDataSize = cbFormat - 176;
mediatype->ExtraData = Stream_Pointer(s);
}
break;

View File

@ -69,20 +69,16 @@ UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
*/
UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
{
UINT32 i = 0;
UINT32 v = 0;
UINT32 pos = 0;
UINT32 CapabilityType = 0;
UINT32 cbCapabilityLength = 0;
UINT32 numHostCapabilities = 0;
UINT32 i;
UINT32 v;
UINT32 pos;
UINT32 CapabilityType;
UINT32 cbCapabilityLength;
UINT32 numHostCapabilities;
WINPR_ASSERT(ifman);
if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
return ERROR_OUTOFMEMORY;
if (Stream_GetRemainingLength(ifman->input) < ifman->input_size)
return ERROR_INVALID_DATA;
pos = Stream_GetPosition(ifman->output);
Stream_Copy(ifman->input, ifman->output, ifman->input_size);
Stream_SetPosition(ifman->output, pos);

View File

@ -97,13 +97,7 @@ static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId,
UINT32 OutputBufferSize)
{
const UINT32 InterfaceId = (STREAM_ID_PROXY << 30) | (InterfaceField & 0x3FFFFFFF);
#if UINT32_MAX >= SIZE_MAX
if (OutputBufferSize > UINT32_MAX - 28ull)
return NULL;
#endif
wStream* out = Stream_New(NULL, OutputBufferSize + 28ull);
wStream* out = Stream_New(NULL, OutputBufferSize + 28);
if (!out)
return NULL;
@ -247,10 +241,6 @@ static UINT urbdrc_process_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* c
Stream_Read_UINT32(s, OutputBufferSize);
Stream_Read_UINT32(s, RequestId);
if (OutputBufferSize > UINT32_MAX - 4)
return ERROR_INVALID_DATA;
InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev));
out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, OutputBufferSize + 4);
@ -683,11 +673,7 @@ static UINT urb_control_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callba
buffer = Stream_Pointer(out);
if (transferDir == USBD_TRANSFER_DIRECTION_OUT)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize))
return ERROR_INVALID_DATA;
Stream_Copy(s, out, OutputBufferSize);
}
/** process TS_URB_CONTROL_TRANSFER */
if (!pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType,
@ -734,20 +720,10 @@ static UINT urb_bulk_or_interrupt_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBA
Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */
Stream_Read_UINT32(s, OutputBufferSize);
EndpointAddress = (PipeHandle & 0x000000ff);
if (transferDir == USBD_TRANSFER_DIRECTION_OUT)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize))
{
return ERROR_INVALID_DATA;
}
}
/** process TS_URB_BULK_OR_INTERRUPT_TRANSFER */
return pdev->bulk_or_interrupt_transfer(
pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, noAck,
OutputBufferSize, (transferDir == USBD_TRANSFER_DIRECTION_OUT) ? Stream_Pointer(s) : NULL,
urb_bulk_transfer_cb, 10000);
return pdev->bulk_or_interrupt_transfer(pdev, callback, MessageId, RequestId, EndpointAddress,
TransferFlags, noAck, OutputBufferSize,
urb_bulk_transfer_cb, 10000);
}
static void urb_isoch_transfer_cb(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out,
@ -827,13 +803,6 @@ static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback
packetDescriptorData = Stream_Pointer(s);
Stream_Seek(s, NumberOfPackets * 12);
Stream_Read_UINT32(s, OutputBufferSize);
if (transferDir == USBD_TRANSFER_DIRECTION_OUT)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize))
return ERROR_INVALID_DATA;
}
return pdev->isoch_transfer(
pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, StartFrame,
ErrorCount, noAck, packetDescriptorData, NumberOfPackets, OutputBufferSize,
@ -1779,13 +1748,6 @@ static UINT urbdrc_process_transfer_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLB
break;
}
if (error)
{
WLog_Print(urbdrc->log, WLOG_WARN,
"USB transfer request URB Function %08" PRIx32 " failed with %08" PRIx32,
URB_Function, error);
}
return error;
}

View File

@ -193,8 +193,8 @@ const char* usb_interface_class_to_string(uint8_t class)
static ASYNC_TRANSFER_USER_DATA* async_transfer_user_data_new(IUDEVICE* idev, UINT32 MessageId,
size_t offset, size_t BufferSize,
const BYTE* data, size_t packetSize,
BOOL NoAck, t_isoch_transfer_cb cb,
size_t packetSize, BOOL NoAck,
t_isoch_transfer_cb cb,
URBDRC_CHANNEL_CALLBACK* callback)
{
ASYNC_TRANSFER_USER_DATA* user_data = calloc(1, sizeof(ASYNC_TRANSFER_USER_DATA));
@ -210,19 +210,14 @@ static ASYNC_TRANSFER_USER_DATA* async_transfer_user_data_new(IUDEVICE* idev, UI
free(user_data);
return NULL;
}
Stream_Seek(user_data->data, offset); /* Skip header offset */
if (data)
memcpy(Stream_Pointer(user_data->data), data, BufferSize);
else
user_data->OutputBufferSize = BufferSize;
user_data->noack = NoAck;
user_data->cb = cb;
user_data->callback = callback;
user_data->idev = idev;
user_data->MessageId = MessageId;
user_data->OutputBufferSize = BufferSize;
user_data->queue = pdev->request_queue;
return user_data;
@ -237,7 +232,7 @@ static void async_transfer_user_data_free(ASYNC_TRANSFER_USER_DATA* user_data)
}
}
static void LIBUSB_CALL func_iso_callback(struct libusb_transfer* transfer)
static void func_iso_callback(struct libusb_transfer* transfer)
{
ASYNC_TRANSFER_USER_DATA* user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data;
const UINT32 streamID = stream_id_from_buffer(transfer);
@ -336,7 +331,7 @@ static const LIBUSB_ENDPOINT_DESCEIPTOR* func_get_ep_desc(LIBUSB_CONFIG_DESCRIPT
return NULL;
}
static void LIBUSB_CALL func_bulk_transfer_cb(struct libusb_transfer* transfer)
static void func_bulk_transfer_cb(struct libusb_transfer* transfer)
{
ASYNC_TRANSFER_USER_DATA* user_data;
uint32_t streamID;
@ -490,19 +485,17 @@ static LIBUSB_DEVICE* udev_get_libusb_dev(libusb_context* context, uint8_t bus_n
for (i = 0; i < total_device; i++)
{
LIBUSB_DEVICE* dev = libusb_list[i];
if ((bus_number == libusb_get_bus_number(dev)) &&
(dev_number == libusb_get_device_address(dev)))
uint8_t cbus = libusb_get_bus_number(libusb_list[i]);
uint8_t caddr = libusb_get_device_address(libusb_list[i]);
if ((bus_number == cbus) && (dev_number == caddr))
{
device = dev;
}
else
{
libusb_unref_device(dev);
device = libusb_list[i];
break;
}
}
libusb_free_device_list(libusb_list, 0);
libusb_free_device_list(libusb_list, 1);
return device;
}
@ -524,6 +517,7 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB
return descriptor;
}
static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting)
{
int error = 0, diff = 0;
@ -1013,9 +1007,6 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev)
if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc)
return FALSE;
#ifdef _WIN32
return TRUE;
#else
urbdrc = pdev->urbdrc;
if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0)
@ -1036,7 +1027,6 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev)
}
return TRUE;
#endif
}
static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev)
@ -1053,14 +1043,12 @@ static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev)
log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_release_interface", err);
#ifndef _WIN32
if (err != LIBUSB_ERROR_NO_DEVICE)
{
err = libusb_attach_kernel_driver(pdev->libusb_handle, i);
log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if=%d",
err, i);
}
#endif
}
return TRUE;
@ -1209,8 +1197,8 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* c
return -1;
urbdrc = pdev->urbdrc;
user_data = async_transfer_user_data_new(idev, MessageId, 48, BufferSize, Buffer,
outSize + 1024, NoAck, cb, callback);
user_data = async_transfer_user_data_new(idev, MessageId, 48, BufferSize, outSize + 1024, NoAck,
cb, callback);
if (!user_data)
return -1;
@ -1218,21 +1206,20 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* c
user_data->ErrorCount = ErrorCount;
user_data->StartFrame = StartFrame;
if (!Buffer)
if (Buffer) /* We read data, prepare a bufffer */
{
user_data->OutputBufferSize = 0;
memmove(Stream_Pointer(user_data->data), Buffer, BufferSize);
}
else
Stream_Seek(user_data->data, (NumberOfPackets * 12));
if (NumberOfPackets > 0)
{
iso_packet_size = BufferSize / NumberOfPackets;
iso_transfer = libusb_alloc_transfer((int)NumberOfPackets);
}
iso_packet_size = BufferSize / NumberOfPackets;
iso_transfer = libusb_alloc_transfer(NumberOfPackets);
if (iso_transfer == NULL)
{
WLog_Print(urbdrc->log, WLOG_ERROR,
"Error: libusb_alloc_transfer [NumberOfPackets=%" PRIu32 ", BufferSize=%" PRIu32
" ]",
NumberOfPackets, BufferSize);
WLog_Print(urbdrc->log, WLOG_ERROR, "Error: libusb_alloc_transfer.");
async_transfer_user_data_free(user_data);
return -1;
}
@ -1283,7 +1270,7 @@ static BOOL libusb_udev_control_transfer(IUDEVICE* idev, UINT32 RequestId, UINT3
static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback,
UINT32 MessageId, UINT32 RequestId,
UINT32 EndpointAddress, UINT32 TransferFlags,
BOOL NoAck, UINT32 BufferSize, const BYTE* data,
BOOL NoAck, UINT32 BufferSize,
t_isoch_transfer_cb cb, UINT32 Timeout)
{
UINT32 transfer_type;
@ -1299,7 +1286,7 @@ static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, URBDRC_CHANNEL
urbdrc = pdev->urbdrc;
user_data =
async_transfer_user_data_new(idev, MessageId, 36, BufferSize, data, 0, NoAck, cb, callback);
async_transfer_user_data_new(idev, MessageId, 36, BufferSize, 0, NoAck, cb, callback);
if (!user_data)
return -1;
@ -1487,7 +1474,6 @@ static void udev_free(IUDEVICE* idev)
ArrayList_Free(udev->request_queue);
/* free the config descriptor that send from windows */
msusb_msconfig_free(udev->MsConfig);
libusb_unref_device(udev->libusb_dev);
libusb_close(udev->libusb_handle);
libusb_close(udev->hub_handle);
free(udev->devDescriptor);
@ -1536,8 +1522,8 @@ static void udev_load_interface(UDEVICE* pdev)
pdev->iface.free = udev_free;
}
static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev,
UINT16 bus_number, UINT16 dev_number)
static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev,
UINT16 bus_number, UINT16 dev_number)
{
int error;
ssize_t i, total_device;
@ -1549,19 +1535,21 @@ static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UD
for (i = 0; i < total_device; i++)
{
LIBUSB_DEVICE* dev = libusb_list[i];
LIBUSB_DEVICE_HANDLE* handle;
uint8_t cbus = libusb_get_bus_number(libusb_list[i]);
uint8_t caddr = libusb_get_device_address(libusb_list[i]);
if ((bus_number != libusb_get_bus_number(dev)) ||
(dev_number != libusb_get_device_address(dev)))
if ((bus_number != cbus) || (dev_number != caddr))
continue;
error = libusb_open(dev, &pdev->libusb_handle);
error = libusb_open(libusb_list[i], &handle);
if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error))
break;
/* get port number */
error = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers));
error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers));
libusb_close(handle);
if (error < 1)
{
@ -1579,40 +1567,29 @@ static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UD
WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path);
break;
}
libusb_free_device_list(libusb_list, 1);
if (error < 0)
return -1;
return 0;
}
static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev,
UINT16 bus_number, UINT16 dev_number)
{
int error;
ssize_t i, total_device;
LIBUSB_DEVICE** libusb_list;
LIBUSB_DEVICE_HANDLE* handle;
total_device = libusb_get_device_list(ctx, &libusb_list);
/* Look for device hub. */
error = -1;
for (i = 0; i < total_device; i++)
if (error == 0)
{
LIBUSB_DEVICE* dev = libusb_list[i];
error = -1;
if ((bus_number != libusb_get_bus_number(dev)) ||
(1 != libusb_get_device_address(dev))) /* Root hub allways first on bus. */
continue;
for (i = 0; i < total_device; i++)
{
LIBUSB_DEVICE_HANDLE* handle;
uint8_t cbus = libusb_get_bus_number(libusb_list[i]);
uint8_t caddr = libusb_get_device_address(libusb_list[i]);
WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number);
error = libusb_open(dev, &handle);
if ((bus_number != cbus) || (1 != caddr)) /* Root hub allways first on bus. */
continue;
if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error))
pdev->hub_handle = handle;
WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number);
error = libusb_open(libusb_list[i], &handle);
break;
if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error))
pdev->hub_handle = handle;
break;
}
}
libusb_free_device_list(libusb_list, 1);
@ -1663,26 +1640,30 @@ static IUDEVICE* udev_init(URBDRC_PLUGIN* urbdrc, libusb_context* context, LIBUS
if (urbdrc->listener_callback)
udev_set_channelManager(&pdev->iface, urbdrc->listener_callback->channel_mgr);
/* Get DEVICE handle */
status = udev_get_device_handle(urbdrc, context, pdev, bus_number, dev_number);
if (status != LIBUSB_SUCCESS)
{
struct libusb_device_descriptor desc;
const uint8_t port = libusb_get_port_number(pdev->libusb_dev);
libusb_get_device_descriptor(pdev->libusb_dev, &desc);
log_libusb_result(urbdrc->log, WLOG_ERROR,
"libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]", status,
bus_number, port, dev_number, desc.idVendor, desc.idProduct);
goto fail;
}
/* Get HUB handle */
status = udev_get_hub_handle(urbdrc, context, pdev, bus_number, dev_number);
if (status < 0)
pdev->hub_handle = NULL;
{
struct libusb_device_descriptor desc;
const uint8_t bus = libusb_get_bus_number(pdev->libusb_dev);
const uint8_t port = libusb_get_port_number(pdev->libusb_dev);
const uint8_t addr = libusb_get_device_address(pdev->libusb_dev);
libusb_get_device_descriptor(pdev->libusb_dev, &desc);
status = libusb_open(pdev->libusb_dev, &pdev->libusb_handle);
if (status != LIBUSB_SUCCESS)
{
log_libusb_result(urbdrc->log, WLOG_ERROR,
"libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]",
status, bus, port, addr, desc.idVendor, desc.idProduct);
goto fail;
}
}
pdev->devDescriptor = udev_new_descript(urbdrc, pdev->libusb_dev);
if (!pdev->devDescriptor)
@ -1753,6 +1734,8 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo
{
LIBUSB_DEVICE** libusb_list;
UDEVICE** array;
UINT16 bus_number;
UINT16 dev_number;
ssize_t i, total_device;
size_t num = 0;
@ -1769,27 +1752,23 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo
for (i = 0; i < total_device; i++)
{
LIBUSB_DEVICE* dev = libusb_list[i];
LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, dev);
LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, libusb_list[i]);
if ((descriptor->idVendor == idVendor) && (descriptor->idProduct == idProduct))
{
array[num] = (PUDEVICE)udev_init(urbdrc, ctx, dev, libusb_get_bus_number(dev),
libusb_get_device_address(dev));
bus_number = libusb_get_bus_number(libusb_list[i]);
dev_number = libusb_get_device_address(libusb_list[i]);
array[num] = (PUDEVICE)udev_init(urbdrc, ctx, libusb_list[i], bus_number, dev_number);
if (array[num] != NULL)
num++;
}
else
{
libusb_unref_device(dev);
}
free(descriptor);
}
fail:
libusb_free_device_list(libusb_list, 0);
libusb_free_device_list(libusb_list, 1);
*devArray = (IUDEVICE**)array;
return num;
}

View File

@ -195,12 +195,6 @@ static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE
/* register all device that match pid vid */
num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray);
if (num == 0)
{
WLog_Print(urbdrc->log, WLOG_WARN,
"Could not find or redirect any usb devices by id %04x:%04x", idVendor, idProduct);
}
for (i = 0; i < num; i++)
{
UINT32 id;
@ -511,7 +505,12 @@ static BOOL filter_by_class(uint8_t bDeviceClass, uint8_t bDeviceSubClass)
static BOOL append(char* dst, size_t length, const char* src)
{
return winpr_str_append(src, dst, length, NULL);
size_t slen = strlen(src);
size_t dlen = strnlen(dst, length);
if (dlen + slen >= length)
return FALSE;
strcat(dst, src);
return TRUE;
}
static BOOL device_is_filtered(struct libusb_device* dev,
@ -537,7 +536,7 @@ static BOOL device_is_filtered(struct libusb_device* dev,
for (x = 0; x < config->bNumInterfaces; x++)
{
int y;
uint8_t y;
const struct libusb_interface* ifc = &config->interface[x];
for (y = 0; y < ifc->num_altsetting; y++)
{
@ -581,8 +580,8 @@ static BOOL device_is_filtered(struct libusb_device* dev,
return filtered;
}
static int LIBUSB_CALL hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev,
libusb_hotplug_event event, void* user_data)
static int hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev,
libusb_hotplug_event event, void* user_data)
{
VID_PID_PAIR pair;
struct libusb_device_descriptor desc;
@ -835,7 +834,7 @@ static BOOL poll_libusb_events(UDEVMAN* udevman)
{
int rc = LIBUSB_SUCCESS;
struct timeval tv = { 0, 500 };
if (libusb_try_lock_events(udevman->context) == 0)
if (libusb_try_lock_events(udevman->context))
{
if (libusb_event_handling_ok(udevman->context))
{
@ -860,7 +859,7 @@ static BOOL poll_libusb_events(UDEVMAN* udevman)
return rc > 0;
}
static DWORD WINAPI poll_thread(LPVOID lpThreadParameter)
static DWORD poll_thread(LPVOID lpThreadParameter)
{
libusb_hotplug_callback_handle handle;
UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter;
@ -922,7 +921,7 @@ UINT freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS
udevman->next_device_id = BASE_USBDEVICE_NUM;
udevman->iface.plugin = pEntryPoints->plugin;
rc = libusb_init(&udevman->context);
if (rc != LIBUSB_SUCCESS)
goto fail;

View File

@ -134,7 +134,7 @@ struct _IUDEVICE
int (*bulk_or_interrupt_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback,
UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, BOOL NoAck, UINT32 BufferSize,
const BYTE* data, t_isoch_transfer_cb cb, UINT32 Timeout);
t_isoch_transfer_cb cb, UINT32 Timeout);
int (*select_configuration)(IUDEVICE* idev, UINT32 bConfigurationValue);

View File

@ -25,10 +25,8 @@ include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
if (NOT BUILTIN_CHANNELS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rdpgfx-client)
endif()
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -666,7 +666,7 @@ static void video_timer(VideoClientContext* video, UINT64 now)
presentation = frame->presentation;
priv->publishedFrames++;
memcpy(presentation->surfaceData, frame->surfaceData, frame->w * frame->h * 4ULL);
memcpy(presentation->surfaceData, frame->surfaceData, frame->w * frame->h * 4);
video->showSurface(video, presentation->surface);
@ -848,7 +848,7 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA* data)
frame->w = presentation->SourceWidth;
frame->h = presentation->SourceHeight;
frame->surfaceData = BufferPool_Take(priv->surfacePool, frame->w * frame->h * 4ULL);
frame->surfaceData = BufferPool_Take(priv->surfacePool, frame->w * frame->h * 4);
if (!frame->surfaceData)
{
WLog_ERR(TAG, "unable to allocate frame data");
@ -930,8 +930,6 @@ static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCall
Stream_Read_UINT16(s, data.PacketsInSample);
Stream_Read_UINT32(s, data.SampleNumber);
Stream_Read_UINT32(s, data.cbSample);
if (!Stream_CheckAndLogRequiredLength(TAG, s, data.cbSample))
return ERROR_INVALID_DATA;
data.pSample = Stream_Pointer(s);
/*

View File

@ -0,0 +1,7 @@
message("PRELOADING android cache")
set(CMAKE_TOOLCHAIN_FILE "$ANDROID_NDK/build/cmake/android.toolchain.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")
#set(ANDROID_SDK "${ANDROID_NDK}" CACHE PATH "android SDK")

View File

@ -0,0 +1,11 @@
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_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)

View File

@ -0,0 +1,7 @@
message("PRELOADING iOS 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_BUILD_TYPE "Debug" CACHE STRING "build type")
set (IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build")
set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "build with address sanitizer")
set (WITH_CLIENT OFF CACHE BOOL "disable iOS client")

View File

@ -0,0 +1,53 @@
message("PRELOADING cache")
set (BUILD_TESTING ON CACHE BOOL "testing")
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
set (BUILD_TESTING ON CACHE BOOL "build testing")
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_WAYLAND ON CACHE BOOL "wayland")
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
set (WITH_PCSC ON CACHE BOOL "PCSC")
set (WITH_JPEG ON CACHE BOOL "jpeg")
set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer")
set (WITH_GSM ON CACHE BOOL "gsm")
set (CHANNEL_URBDRC ON CACHE BOOL "urbdrc")
set (CHANNEL_URBDRC_CLIENT ON CACHE BOOL "urbdrc client")
set (WITH_SERVER ON CACHE BOOL "server side")
set (WITH_DEBUG_ALL OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_CAPABILITIES OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_CERTIFICATE OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_CHANNELS OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_CLIPRDR OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_RDPGFX OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_DVC OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_KBD OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_LICENSE OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_NEGO OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_NLA OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_NTLM OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_RAIL OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_RDP OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_RDPEI OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_REDIR OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_RDPDR OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_RFX OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_SCARD OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_SND OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_SVC OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_THREADS OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_TIMEZONE OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_TRANSPORT OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_TSG OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_TSMF OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_WND OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_X11 OFF CACHE BOOL "enable debug")
set (WITH_DEBUG_X11_CLIPRDR OFF CACHE BOOL "enable debug")
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)
set (WITH_PROXY_MODULES OFF CACHE BOOL "compile proxy modules")

View File

@ -0,0 +1,8 @@
message("PRELOADING mac cache")
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
set (WITH_CUPS ON CACHE BOOL "CUPS printing")
set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection")
set (WITH_X11 ON CACHE BOOL "Enable X11")
set (BUILD_TESTING ON CACHE BOOL "build testing")
set (WITH_SANITIZE_ADDRESS ON)

View File

@ -0,0 +1,11 @@
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_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)

View File

@ -0,0 +1,6 @@
message("PRELOADING windows cache")
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
set (WITH_SERVER "ON" CACHE BOOL "Build server binaries")
set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection")
set (BUILD_TESTING ON CACHE BOOL "build testing")
set (WITH_SANITIZE_ADDRESS ON)

View File

@ -43,10 +43,7 @@ if(FREERDP_VENDOR AND WITH_CLIENT)
add_subdirectory(iOS)
endif()
else()
option(WITH_CLIENT_MAC "Build native mac client" ON)
if (WITH_CLIENT_MAC)
add_subdirectory(Mac)
endif()
add_subdirectory(Mac)
endif()
endif()

View File

@ -80,7 +80,6 @@ struct wlf_clipboard
FILE* responseFile;
UINT32 responseFormat;
const char* responseMime;
CRITICAL_SECTION lock;
};
static BOOL wlf_mime_is_text(const char* mime)
@ -276,7 +275,7 @@ BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent*
return TRUE;
case UWAC_EVENT_CLIPBOARD_OFFER:
WLog_Print(clipboard->log, WLOG_DEBUG, "client announces mime %s", event->mime);
WLog_Print(clipboard->log, WLOG_INFO, "client announces mime %s", event->mime);
wlf_cliprdr_add_client_format(clipboard, event->mime);
return TRUE;
@ -388,8 +387,6 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char*
wfClipboard* clipboard = (wfClipboard*)context;
size_t x;
WINPR_UNUSED(seat);
EnterCriticalSection(&clipboard->lock);
clipboard->responseMime = NULL;
for (x = 0; x < ARRAYSIZE(mime_html); x++)
@ -430,8 +427,6 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char*
if (clipboard->responseMime != NULL)
{
if (clipboard->responseFile != NULL)
fclose(clipboard->responseFile);
clipboard->responseFile = fdopen(fd, "w");
if (clipboard->responseFile)
@ -441,7 +436,6 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char*
"failed to open clipboard file descriptor for MIME %s",
clipboard->responseMime);
}
LeaveCriticalSection(&clipboard->lock);
}
static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context)
@ -679,8 +673,6 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context,
const WCHAR* wdata = (const WCHAR*)formatDataResponse->requestedFormatData;
wfClipboard* clipboard = (wfClipboard*)context->custom;
EnterCriticalSection(&clipboard->lock);
if (size > INT_MAX * sizeof(WCHAR))
return ERROR_INTERNAL_ERROR;
@ -702,16 +694,10 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context,
break;
}
if (clipboard->responseFile)
{
fwrite(data, 1, size, clipboard->responseFile);
fclose(clipboard->responseFile);
clipboard->responseFile = NULL;
}
fwrite(data, 1, size, clipboard->responseFile);
fclose(clipboard->responseFile);
rc = CHANNEL_RC_OK;
free(cdata);
LeaveCriticalSection(&clipboard->lock);
return rc;
}
@ -843,24 +829,17 @@ static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegat
wfClipboard* wlf_clipboard_new(wlfContext* wfc)
{
rdpChannels* channels;
wfClipboard* clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard));
wfClipboard* clipboard;
if (!clipboard)
goto fail;
if (!(clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard))))
return NULL;
InitializeCriticalSection(&clipboard->lock);
clipboard->wfc = wfc;
channels = wfc->context.channels;
clipboard->log = WLog_Get(TAG);
clipboard->channels = channels;
clipboard->system = ClipboardCreate();
if (!clipboard->system)
goto fail;
clipboard->delegate = ClipboardGetDelegate(clipboard->system);
if (!clipboard->delegate)
goto fail;
clipboard->delegate->custom = clipboard;
/* TODO: set up a filesystem base path for local URI */
/* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */
@ -869,10 +848,6 @@ wfClipboard* wlf_clipboard_new(wlfContext* wfc)
clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success;
clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure;
return clipboard;
fail:
wlf_clipboard_free(clipboard);
return NULL;
}
void wlf_clipboard_free(wfClipboard* clipboard)
@ -883,12 +858,6 @@ void wlf_clipboard_free(wfClipboard* clipboard)
wlf_cliprdr_free_server_formats(clipboard);
wlf_cliprdr_free_client_formats(clipboard);
ClipboardDestroy(clipboard->system);
EnterCriticalSection(&clipboard->lock);
if (clipboard->responseFile)
fclose(clipboard->responseFile);
LeaveCriticalSection(&clipboard->lock);
DeleteCriticalSection(&clipboard->lock);
free(clipboard);
}

View File

@ -134,44 +134,26 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent*
}
BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev)
{
wlfContext* context;
if (!instance || !instance->context || !ev)
return FALSE;
context = (wlfContext*)instance->context;
ArrayList_Add(context->events, ev);
return TRUE;
}
BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev)
{
wlfContext* context;
if (!instance || !instance->context || !ev)
return FALSE;
context = (wlfContext*)instance->context;
ArrayList_Add(context->events, ev);
return TRUE;
}
static BOOL wlf_handle_wheel(freerdp* instance, uint32_t x, uint32_t y, uint32_t axis,
int32_t value)
{
rdpInput* input;
UINT16 flags = 0;
int32_t direction;
uint32_t avalue = abs(value);
uint32_t x, y;
uint32_t i;
input = instance->input;
if (!instance || !ev || !instance->input)
return FALSE;
x = ev->x;
y = ev->y;
if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
return FALSE;
input = instance->input;
direction = value;
switch (axis)
direction = ev->value;
switch (ev->axis)
{
case WL_POINTER_AXIS_VERTICAL_SCROLL:
flags |= PTR_FLAGS_WHEEL;
@ -194,102 +176,16 @@ static BOOL wlf_handle_wheel(freerdp* instance, uint32_t x, uint32_t y, uint32_t
* positive: 0 ... 0xFF -> slow ... fast
* negative: 0 ... 0xFF -> fast ... slow
*/
while (avalue > 0)
for (i = 0; i < abs(direction); i++)
{
const uint32_t cval = avalue > 0xFF ? 0xFF : avalue;
uint32_t cflags = flags | cval;
uint32_t cflags = flags | 0x78;
/* Convert negative values to 9bit twos complement */
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
cflags = (flags & 0xFF00) | (0x100 - cval);
cflags = (flags & 0xFF00) | (0x100 - (cflags & 0xFF));
if (!freerdp_input_send_mouse_event(input, cflags, (UINT16)x, (UINT16)y))
return FALSE;
avalue -= cval;
}
return TRUE;
}
BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev)
{
BOOL success = TRUE;
BOOL handle = FALSE;
size_t x;
wlfContext* context;
enum wl_pointer_axis_source source;
if (!instance || !ev || !instance->input || !instance->context)
return FALSE;
context = (wlfContext*)instance->context;
for (x = 0; x < ArrayList_Count(context->events); x++)
{
UwacEvent* ev = ArrayList_GetItem(context->events, x);
if (!ev)
continue;
if (ev->type == UWAC_EVENT_POINTER_SOURCE)
{
handle = TRUE;
source = ev->mouse_source.axis_source;
}
}
/* We need source events to determine how to interpret the data */
if (handle)
{
for (x = 0; x < ArrayList_Count(context->events); x++)
{
UwacEvent* ev = ArrayList_GetItem(context->events, x);
if (!ev)
continue;
switch (source)
{
/* If we have a mouse wheel, just use discrete data */
case WL_POINTER_AXIS_SOURCE_WHEEL:
#if defined(WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION)
case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
#endif
if (ev->type == UWAC_EVENT_POINTER_AXIS_DISCRETE)
{
/* Get the number of steps, multiply by default step width of 120 */
int32_t val = ev->mouse_axis.value * 0x78;
/* No wheel event received, success! */
if (!wlf_handle_wheel(instance, ev->mouse_axis.x, ev->mouse_axis.y,
ev->mouse_axis.axis, val))
success = FALSE;
}
break;
/* If we have a touch pad we get actual data, scale */
case WL_POINTER_AXIS_SOURCE_FINGER:
case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
if (ev->type == UWAC_EVENT_POINTER_AXIS)
{
double dval = wl_fixed_to_double(ev->mouse_axis.value);
int32_t val = dval * 0x78 / 10.0;
if (!wlf_handle_wheel(instance, ev->mouse_axis.x, ev->mouse_axis.y,
ev->mouse_axis.axis, val))
success = FALSE;
}
break;
default:
break;
}
}
}
ArrayList_Clear(context->events);
return success;
}
BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev)
{
wlfContext* context;
if (!instance || !instance->context || !ev)
return FALSE;
context = (wlfContext*)instance->context;
ArrayList_Add(context->events, ev);
return TRUE;
}

View File

@ -30,9 +30,6 @@ BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEven
BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev);
BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev);
BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev);
BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev);
BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev);
BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev);
BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev);
BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev);
BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev);

View File

@ -42,7 +42,7 @@ static BOOL wlf_Pointer_New(rdpContext* context, rdpPointer* pointer)
if (!ptr)
return FALSE;
ptr->size = pointer->width * pointer->height * 4ULL;
ptr->size = pointer->width * pointer->height * 4;
ptr->data = _aligned_malloc(ptr->size, 16);
if (!ptr->data)
@ -92,7 +92,7 @@ static BOOL wlf_Pointer_Set(rdpContext* context, const rdpPointer* pointer)
!wlf_scale_coordinates(context, &w, &h, FALSE))
return FALSE;
size = w * h * 4ULL;
size = w * h * 4;
data = malloc(size);
if (!data)

View File

@ -225,7 +225,6 @@ static BOOL wl_post_connect(freerdp* instance)
wlfContext* context;
rdpSettings* settings;
char* title = "FreeRDP";
char* app_id = "wlfreerdp";
UINT32 w, h;
if (!instance || !instance->context)
@ -267,7 +266,6 @@ static BOOL wl_post_connect(freerdp* instance)
UwacWindowSetFullscreenState(window, NULL, instance->context->settings->Fullscreen);
UwacWindowSetTitle(window, title);
UwacWindowSetAppId(window, app_id);
UwacWindowSetOpaqueRegion(context->window, 0, 0, w, h);
instance->update->BeginPaint = wl_begin_paint;
instance->update->EndPaint = wl_end_paint;
@ -333,15 +331,12 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
break;
case UWAC_EVENT_FRAME_DONE:
{
UwacReturnCode r;
EnterCriticalSection(&context->critical);
r = UwacWindowSubmitBuffer(context->window, false);
rc = UwacWindowSubmitBuffer(context->window, false);
LeaveCriticalSection(&context->critical);
if (r != UWAC_SUCCESS)
if (rc != UWAC_SUCCESS)
return FALSE;
}
break;
break;
case UWAC_EVENT_POINTER_ENTER:
if (!wlf_handle_pointer_enter(instance, &event.mouse_enter_leave))
@ -362,22 +357,12 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
break;
case UWAC_EVENT_POINTER_AXIS:
if (!wlf_handle_pointer_axis(instance, &event.mouse_axis))
return FALSE;
break;
case UWAC_EVENT_POINTER_AXIS_DISCRETE:
if (!wlf_handle_pointer_axis_discrete(instance, &event.mouse_axis))
if (!wlf_handle_pointer_axis(instance, &event.mouse_axis))
return FALSE;
break;
case UWAC_EVENT_POINTER_FRAME:
if (!wlf_handle_pointer_frame(instance, &event.mouse_frame))
return FALSE;
break;
case UWAC_EVENT_POINTER_SOURCE:
if (!wlf_handle_pointer_source(instance, &event.mouse_source))
return FALSE;
break;
case UWAC_EVENT_KEY:
@ -571,37 +556,8 @@ static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
return 1;
}
static void wlf_client_free(freerdp* instance, rdpContext* context)
{
wlfContext* wlf = (wlfContext*)instance->context;
if (!context)
return;
if (wlf->display)
UwacCloseDisplay(&wlf->display);
if (wlf->displayHandle)
CloseHandle(wlf->displayHandle);
ArrayList_Free(wlf->events);
DeleteCriticalSection(&wlf->critical);
}
static void* uwac_event_clone(const void* val)
{
UwacEvent* copy;
UwacEvent* ev = (UwacEvent*)val;
copy = calloc(1, sizeof(UwacEvent));
if (!copy)
return NULL;
*copy = *ev;
return copy;
}
static BOOL wlf_client_new(freerdp* instance, rdpContext* context)
{
wObject* obj;
UwacReturnCode status;
wlfContext* wfl = (wlfContext*)context;
@ -629,19 +585,26 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context)
if (!wfl->displayHandle)
return FALSE;
wfl->events = ArrayList_New(FALSE);
if (!wfl->events)
return FALSE;
obj = ArrayList_Object(wfl->events);
obj->fnObjectNew = uwac_event_clone;
obj->fnObjectFree = free;
InitializeCriticalSection(&wfl->critical);
return TRUE;
}
static void wlf_client_free(freerdp* instance, rdpContext* context)
{
wlfContext* wlf = (wlfContext*)instance->context;
if (!context)
return;
if (wlf->display)
UwacCloseDisplay(&wlf->display);
if (wlf->displayHandle)
CloseHandle(wlf->displayHandle);
DeleteCriticalSection(&wlf->critical);
}
static int wfl_client_start(rdpContext* context)
{
WINPR_UNUSED(context);

View File

@ -53,7 +53,6 @@ struct wlf_context
wlfDispContext* disp;
wLog* log;
CRITICAL_SECTION critical;
wArrayList* events;
};
BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP);

View File

@ -59,9 +59,11 @@ int main(int argc, char* argv[])
status = freerdp_client_settings_parse_command_line(context->settings, argc, argv, FALSE);
if (status)
{
BOOL list = settings->ListMonitors;
rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
if (settings->ListMonitors)
if (list)
xf_list_monitors(xfc);
goto out;

View File

@ -27,7 +27,6 @@
#endif
#include <assert.h>
#include <winpr/sspicli.h>
#include <float.h>
#include <X11/Xlib.h>
@ -815,6 +814,8 @@ void xf_lock_x11_(xfContext* xfc, const char* fkt)
else
XLockDisplay(xfc->display);
if (xfc->locked)
WLog_WARN(TAG, "%s:\t[%" PRIu32 "] recursive lock from %s", __FUNCTION__, xfc->locked, fkt);
xfc->locked++;
WLog_VRB(TAG, "%s:\t[%" PRIu32 "] from %s", __FUNCTION__, xfc->locked, fkt);
}
@ -1182,12 +1183,20 @@ static BOOL xf_pre_connect(freerdp* instance)
if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon)
{
int rc;
char login_name[MAX_PATH] = { 0 };
ULONG size = sizeof(login_name) - 1;
if (GetUserNameExA(NameSamCompatible, login_name, &size))
#ifdef HAVE_GETLOGIN_R
rc = getlogin_r(login_name, sizeof(login_name));
#else
strncpy(login_name, getlogin(), sizeof(login_name));
rc = 0;
#endif
if (rc == 0)
{
if (!freerdp_settings_set_string(settings, FreeRDP_Username, login_name))
settings->Username = _strdup(login_name);
if (!settings->Username)
return FALSE;
WLog_INFO(TAG, "No user name set. - Using login name: %s", settings->Username);
@ -1254,7 +1263,6 @@ static BOOL xf_post_connect(freerdp* instance)
context = instance->context;
settings = instance->settings;
update = context->update;
BOOL serverIsWindowsPlatform;
if (!gdi_init(instance, xf_get_local_color_format(xfc, TRUE)))
return FALSE;
@ -1324,8 +1332,7 @@ static BOOL xf_post_connect(freerdp* instance)
update->SetKeyboardIndicators = xf_keyboard_set_indicators;
update->SetKeyboardImeStatus = xf_keyboard_set_ime_status;
serverIsWindowsPlatform = (settings->OsMajorType == OSMAJORTYPE_WINDOWS);
if (!(xfc->clipboard = xf_clipboard_new(xfc, !serverIsWindowsPlatform)))
if (!(xfc->clipboard = xf_clipboard_new(xfc)))
return FALSE;
if (!(xfc->xfDisp = xf_disp_new(xfc)))
@ -1384,10 +1391,7 @@ static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 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);
if(type != LOGON_MSG_SESSION_CONTINUE)
{
xf_rail_disable_remoteapp_mode(xfc);
}
xf_rail_disable_remoteapp_mode(xfc);
return 1;
}
@ -1397,8 +1401,11 @@ static DWORD WINAPI xf_input_thread(LPVOID arg)
DWORD status;
DWORD nCount;
HANDLE events[3];
XEvent xevent;
wMessage msg;
wMessageQueue* queue;
int pending_status = 1;
int process_status = 1;
freerdp* instance = (freerdp*)arg;
xfContext* xfc = (xfContext*)instance->context;
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
@ -1427,7 +1434,26 @@ static DWORD WINAPI xf_input_thread(LPVOID arg)
if (WaitForSingleObject(events[1], 0) == WAIT_OBJECT_0)
{
if (!xf_process_x_events(xfc->context.instance))
do
{
xf_lock_x11(xfc);
pending_status = XPending(xfc->display);
xf_unlock_x11(xfc);
if (pending_status)
{
xf_lock_x11(xfc);
ZeroMemory(&xevent, sizeof(xevent));
XNextEvent(xfc->display, &xevent);
process_status = xf_event_process(instance, &xevent);
xf_unlock_x11(xfc);
if (!process_status)
break;
}
} while (pending_status);
if (!process_status)
{
running = FALSE;
break;
@ -1446,7 +1472,6 @@ static DWORD WINAPI xf_input_thread(LPVOID arg)
}
MessageQueue_PostQuit(queue, 0);
freerdp_abort_connect(xfc->context.instance);
ExitThread(0);
return 0;
}
@ -1464,7 +1489,7 @@ static BOOL handle_window_events(freerdp* instance)
{
if (!xf_process_x_events(instance))
{
WLog_DBG(TAG, "Closed from X11");
WLog_INFO(TAG, "Closed from X11");
return FALSE;
}
}
@ -1508,84 +1533,6 @@ static DWORD WINAPI xf_client_thread(LPVOID param)
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED)
exit_code = XF_EXIT_NEGO_FAILURE;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_LOGON_FAILURE)
exit_code = XF_EXIT_LOGON_FAILURE;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT)
exit_code = XF_EXIT_ACCOUNT_LOCKED_OUT;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_PRE_CONNECT_FAILED)
exit_code = XF_EXIT_PRE_CONNECT_FAILED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_UNDEFINED)
exit_code = XF_EXIT_CONNECT_UNDEFINED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_POST_CONNECT_FAILED)
exit_code = XF_EXIT_POST_CONNECT_FAILED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_DNS_ERROR)
exit_code = XF_EXIT_DNS_ERROR;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_DNS_NAME_NOT_FOUND)
exit_code = XF_EXIT_DNS_NAME_NOT_FOUND;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_FAILED)
exit_code = XF_EXIT_CONNECT_FAILED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR)
exit_code = XF_EXIT_MCS_CONNECT_INITIAL_ERROR;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_TLS_CONNECT_FAILED)
exit_code = XF_EXIT_TLS_CONNECT_FAILED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_INSUFFICIENT_PRIVILEGES)
exit_code = XF_EXIT_INSUFFICIENT_PRIVILEGES;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_CANCELLED)
exit_code = XF_EXIT_CONNECT_CANCELLED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED)
exit_code = XF_EXIT_SECURITY_NEGO_CONNECT_FAILED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
exit_code = XF_EXIT_CONNECT_TRANSPORT_FAILED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED)
exit_code = XF_EXIT_CONNECT_PASSWORD_EXPIRED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE)
exit_code = XF_EXIT_CONNECT_PASSWORD_MUST_CHANGE;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_KDC_UNREACHABLE)
exit_code = XF_EXIT_CONNECT_KDC_UNREACHABLE;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED)
exit_code = XF_EXIT_CONNECT_ACCOUNT_DISABLED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED)
exit_code = XF_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_CLIENT_REVOKED)
exit_code = XF_EXIT_CONNECT_CLIENT_REVOKED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_WRONG_PASSWORD)
exit_code = XF_EXIT_CONNECT_WRONG_PASSWORD;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_ACCESS_DENIED)
exit_code = XF_EXIT_CONNECT_ACCESS_DENIED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION)
exit_code = XF_EXIT_CONNECT_ACCOUNT_RESTRICTION;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED)
exit_code = XF_EXIT_CONNECT_ACCOUNT_EXPIRED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED)
exit_code = XF_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED;
else if (freerdp_get_last_error(instance->context) ==
FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS)
exit_code = XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS;
else
exit_code = XF_EXIT_CONN_FAILED;
}
@ -1750,7 +1697,7 @@ end:
DWORD xf_exit_code_from_disconnect_reason(DWORD reason)
{
if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS))
if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_NEGO_FAILURE))
return reason;
/* License error set */
else if (reason >= 0x100 && reason <= 0x10A)

View File

@ -1034,8 +1034,7 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard,
if (!delayRespond)
{
union
{
union {
XEvent* ev;
XSelectionEvent* sev;
} conv;
@ -1424,10 +1423,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
}
ret = xf_cliprdr_send_client_format_list_response(clipboard, TRUE);
if (xfc->remote_app)
xf_cliprdr_set_selection_owner(xfc, clipboard, CurrentTime);
else
xf_cliprdr_prepare_to_set_selection_owner(xfc, clipboard);
xf_cliprdr_prepare_to_set_selection_owner(xfc, clipboard);
return ret;
}
@ -1570,7 +1566,7 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context,
{
if (SrcSize == 0)
{
WLog_DBG(TAG, "skipping, empty data detected!");
WLog_INFO(TAG, "skipping, empty data detected!!!");
free(clipboard->respond);
clipboard->respond = NULL;
return CHANNEL_RC_OK;
@ -1615,8 +1611,7 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context,
xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize);
{
union
{
union {
XEvent* ev;
XSelectionEvent* sev;
} conv;
@ -1756,27 +1751,7 @@ static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
}
static BOOL xf_cliprdr_clipboard_is_valid_unix_filename(LPCWSTR filename)
{
LPCWSTR c;
if (!filename)
return FALSE;
if (filename[0] == L'\0')
return FALSE;
/* Reserved characters */
for (c = filename; *c; ++c)
{
if (*c == L'/')
return FALSE;
}
return TRUE;
}
xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
xfClipboard* xf_clipboard_new(xfContext* xfc)
{
int i, n = 0;
rdpChannels* channels;
@ -1905,13 +1880,6 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction)
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;
if (relieveFilenameRestriction)
{
WLog_DBG(TAG, "Relieving CLIPRDR filename restriction");
clipboard->delegate->IsFileNameComponentValid = xf_cliprdr_clipboard_is_valid_unix_filename;
}
return clipboard;
error:

View File

@ -25,7 +25,7 @@
#include <freerdp/client/cliprdr.h>
xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction);
xfClipboard* xf_clipboard_new(xfContext* xfc);
void xf_clipboard_free(xfClipboard* clipboard);
void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr);

View File

@ -93,7 +93,7 @@ static BOOL xf_update_last_sent(xfDispContext* xfDisp)
static BOOL xf_disp_sendResize(xfDispContext* xfDisp)
{
DISPLAY_CONTROL_MONITOR_LAYOUT layout = { 0 };
DISPLAY_CONTROL_MONITOR_LAYOUT layout;
xfContext* xfc;
rdpSettings* settings;
@ -242,24 +242,7 @@ static void xf_disp_OnTimer(void* context, TimerEventArgs* e)
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
return;
if (!xfDisp->activated || xfc->fullscreen)
return;
xf_disp_sendResize(xfDisp);
}
static void xf_disp_OnWindowStateChange(void* context, WindowStateChangeEventArgs* e)
{
xfContext* xfc;
xfDispContext* xfDisp;
rdpSettings* settings;
WINPR_UNUSED(e);
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
return;
if (!xfDisp->activated || !xfc->fullscreen)
if (!xfDisp->activated || settings->Fullscreen)
return;
xf_disp_sendResize(xfDisp);
@ -291,7 +274,6 @@ xfDispContext* xf_disp_new(xfContext* xfc)
PubSub_SubscribeActivated(xfc->context.pubSub, xf_disp_OnActivated);
PubSub_SubscribeGraphicsReset(xfc->context.pubSub, xf_disp_OnGraphicsReset);
PubSub_SubscribeTimer(xfc->context.pubSub, xf_disp_OnTimer);
PubSub_SubscribeWindowStateChange(xfc->context.pubSub, xf_disp_OnWindowStateChange);
return ret;
}
@ -305,7 +287,6 @@ void xf_disp_free(xfDispContext* disp)
PubSub_UnsubscribeActivated(disp->xfc->context.pubSub, xf_disp_OnActivated);
PubSub_UnsubscribeGraphicsReset(disp->xfc->context.pubSub, xf_disp_OnGraphicsReset);
PubSub_UnsubscribeTimer(disp->xfc->context.pubSub, xf_disp_OnTimer);
PubSub_UnsubscribeWindowStateChange(disp->xfc->context.pubSub, xf_disp_OnWindowStateChange);
}
free(disp);

View File

@ -24,8 +24,6 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <winpr/assert.h>
#include <freerdp/log.h>
#include <freerdp/locale/keyboard.h>
@ -35,7 +33,6 @@
#include "xf_disp.h"
#include "xf_input.h"
#include "xf_gfx.h"
#include "xf_graphics.h"
#include "xf_event.h"
#include "xf_input.h"
@ -265,37 +262,6 @@ static BOOL xf_event_execute_action_script(xfContext* xfc, const XEvent* event)
return TRUE;
}
void xf_adjust_coordinates_to_screen(xfContext* xfc, UINT32* x, UINT32* y)
{
rdpSettings* settings;
INT64 tx, ty;
if (!xfc || !xfc->context.settings || !y || !x)
return;
settings = xfc->context.settings;
tx = *x;
ty = *y;
if (!xfc->remote_app)
{
#ifdef WITH_XRENDER
if (xf_picture_transform_required(xfc))
{
double xScalingFactor = xfc->scaledWidth / (double)settings->DesktopWidth;
double yScalingFactor = xfc->scaledHeight / (double)settings->DesktopHeight;
tx = ((tx + xfc->offset_x) * xScalingFactor);
ty = ((ty + xfc->offset_y) * yScalingFactor);
}
#endif
}
CLAMP_COORDINATES(tx, ty);
*x = tx;
*y = ty;
}
void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y)
{
rdpSettings* settings;
@ -521,29 +487,6 @@ static BOOL xf_event_KeyRelease(xfContext* xfc, const XKeyEvent* event, BOOL app
return TRUE;
}
/* Release a key, but ignore the event in case of autorepeat.
*/
static BOOL xf_event_KeyReleaseOrIgnore(xfContext* xfc, const XKeyEvent* event, BOOL app)
{
WINPR_ASSERT(xfc);
WINPR_ASSERT(event);
if ((event->type == KeyRelease) && XEventsQueued(xfc->display, QueuedAfterReading))
{
XEvent nev = { 0 };
XPeekEvent(xfc->display, &nev);
if ((nev.type == KeyPress) && (nev.xkey.time == event->time) &&
(nev.xkey.keycode == event->keycode))
{
/* Key wasnt actually released */
return TRUE;
}
}
return xf_event_KeyRelease(xfc, event, app);
}
static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL app)
{
if (event->mode == NotifyGrab)
@ -563,7 +506,6 @@ static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL ap
/* Release all keys, should already be done at FocusOut but might be missed
* if the WM decided to use an alternate event order */
xf_keyboard_release_all_keypress(xfc);
xf_pointer_update_scale(xfc);
if (app)
{
@ -695,9 +637,6 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even
rdpSettings* settings;
settings = xfc->context.settings;
WLog_DBG(TAG, "%s: x=%" PRId32 ", y=%" PRId32 ", w=%" PRId32 ", h=%" PRId32, __func__, event->x,
event->y, event->width, event->height);
if (!app)
{
if (!xfc->window)
@ -740,42 +679,43 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even
/* ask the server to resize using the display channel */
xf_disp_handle_configureNotify(xfc, alignedWidth, alignedHeight);
}
return TRUE;
}
else
appWindow = xf_AppWindowFromX11Window(xfc, event->window);
if (appWindow)
{
appWindow = xf_AppWindowFromX11Window(xfc, event->window);
/*
* ConfigureNotify coordinates are expressed relative to the window parent.
* Translate these to root window coordinates.
*/
XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen), 0,
0, &appWindow->x, &appWindow->y, &childWindow);
appWindow->width = event->width;
appWindow->height = event->height;
if (appWindow)
/*
* Additional checks for not in a local move and not ignoring configure to send
* position update to server, also should the window not be focused then do not
* send to server yet (i.e. resizing using window decoration).
* The server will be updated when the window gets refocused.
*/
if (appWindow->decorations)
{
/*
* ConfigureNotify coordinates are expressed relative to the window parent.
* Translate these to root window coordinates.
*/
XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen),
0, 0, &appWindow->x, &appWindow->y, &childWindow);
appWindow->width = event->width;
appWindow->height = event->height;
/*
* Additional checks for not in a local move and not ignoring configure to send
* position update to server, also should the window not be focused then do not
* send to server yet (i.e. resizing using window decoration).
* The server will be updated when the window gets refocused.
*/
if (appWindow->decorations)
{
/* moving resizing using window decoration */
/* moving resizing using window decoration */
xf_rail_adjust_position(xfc, appWindow);
}
else
{
if ((!event->send_event || appWindow->local_move.state == LMS_NOT_ACTIVE) &&
!appWindow->rail_ignore_configure && xfc->focused)
xf_rail_adjust_position(xfc, appWindow);
}
else
{
if ((!event->send_event || appWindow->local_move.state == LMS_NOT_ACTIVE) &&
!appWindow->rail_ignore_configure && xfc->focused)
xf_rail_adjust_position(xfc, appWindow);
}
}
}
return xf_pointer_update_scale(xfc);
return TRUE;
}
static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app)
@ -788,14 +728,14 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app)
{
appWindow = xf_AppWindowFromX11Window(xfc, event->window);
if (appWindow && (appWindow->rail_state == WINDOW_SHOW))
if (appWindow)
{
/* local restore event */
/* This is now handled as part of the PropertyNotify
* Doing this here would inhibit the ability to restore a maximized window
* that is minimized back to the maximized state
*/
// xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
appWindow->is_mapped = TRUE;
}
}
@ -806,10 +746,6 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app)
static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL app)
{
xfAppWindow* appWindow;
WINPR_ASSERT(xfc);
WINPR_ASSERT(event);
xf_keyboard_release_all_keypress(xfc);
if (!app)
@ -829,9 +765,6 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL
static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, BOOL app)
{
WINPR_ASSERT(xfc);
WINPR_ASSERT(event);
/*
* This section handles sending the appropriate commands to the rail server
* when the window has been minimized, maximized, restored locally
@ -866,27 +799,18 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
if (status)
{
if (appWindow)
{
appWindow->maxVert = FALSE;
appWindow->maxHorz = FALSE;
}
for (i = 0; i < nitems; i++)
{
if ((Atom)((UINT16**)prop)[i] ==
XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False))
{
maxVert = TRUE;
if (appWindow)
appWindow->maxVert = TRUE;
}
if ((Atom)((UINT16**)prop)[i] ==
XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False))
{
maxHorz = TRUE;
if (appWindow)
appWindow->maxHorz = TRUE;
}
}
@ -903,17 +827,9 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
{
/* If the window is in the iconic state */
if (((UINT32)*prop == 3))
{
minimized = TRUE;
if (appWindow)
appWindow->minimized = TRUE;
}
else
{
minimized = FALSE;
if (appWindow)
appWindow->minimized = FALSE;
}
minimizedChanged = TRUE;
XFree(prop);
@ -922,30 +838,22 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event,
if (app)
{
WINPR_ASSERT(appWindow);
if (appWindow->maxVert && appWindow->maxHorz && !appWindow->minimized)
if (maxVert && maxHorz && !minimized &&
(appWindow->rail_state != WINDOW_SHOW_MAXIMIZED))
{
if (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED)
{
appWindow->rail_state = WINDOW_SHOW_MAXIMIZED;
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE);
}
appWindow->rail_state = WINDOW_SHOW_MAXIMIZED;
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE);
}
else if (appWindow->minimized)
else if (minimized && (appWindow->rail_state != WINDOW_SHOW_MINIMIZED))
{
if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
{
appWindow->rail_state = WINDOW_SHOW_MINIMIZED;
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE);
}
appWindow->rail_state = WINDOW_SHOW_MINIMIZED;
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE);
}
else
else if (!minimized && !maxVert && !maxHorz && (appWindow->rail_state != WINDOW_SHOW) &&
(appWindow->rail_state != WINDOW_HIDE))
{
if (appWindow->rail_state != WINDOW_SHOW && appWindow->rail_state != WINDOW_HIDE)
{
appWindow->rail_state = WINDOW_SHOW;
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
}
appWindow->rail_state = WINDOW_SHOW;
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
}
}
else if (minimizedChanged)
@ -1109,7 +1017,7 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event)
break;
case KeyRelease:
status = xf_event_KeyReleaseOrIgnore(xfc, &event->xkey, xfc->remote_app);
status = xf_event_KeyRelease(xfc, &event->xkey, xfc->remote_app);
break;
case FocusIn:

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