Compare commits
121 Commits
devel
...
v0.10-h264
Author | SHA1 | Date | |
---|---|---|---|
|
0579980e44 | ||
|
8bf9ed48af | ||
|
401cd845f8 | ||
|
5bbeb03848 | ||
|
689a2620d3 | ||
|
d56396b771 | ||
|
89277e5aea | ||
|
abb5714f8f | ||
|
6b98637bac | ||
|
1fcde20682 | ||
|
12c9e79dee | ||
|
d083920824 | ||
|
427f501862 | ||
|
be3e3a3d0a | ||
|
3c7b416375 | ||
|
3a2e0eb8cd | ||
|
099575056e | ||
|
48a6cd4060 | ||
|
9cb2afa052 | ||
|
565977bc81 | ||
|
1d52a418ad | ||
|
2a02056346 | ||
|
82bec9d1dc | ||
|
ace386d072 | ||
|
e59dc16be6 | ||
|
f3070aef15 | ||
|
6c9d56efc2 | ||
|
f4153a493d | ||
|
72892c1453 | ||
|
19bacc6e49 | ||
|
1c33f3d9af | ||
|
54932b55ef | ||
|
00b8b41344 | ||
|
4d9e9f91fa | ||
|
b343ca27b1 | ||
|
3108a85e86 | ||
|
4d4ecdcaa4 | ||
|
da34d1e69d | ||
|
5223672437 | ||
|
2938c3d7b3 | ||
|
4a90879555 | ||
|
a7d583a46d | ||
|
d6fce2f173 | ||
|
2546bfa842 | ||
|
1d30c81323 | ||
|
e83dcc52eb | ||
|
61b509f1d5 | ||
|
8ddbe77e7c | ||
|
029059ef3d | ||
|
9a21e37f1f | ||
|
0aa3a679c3 | ||
|
e070902310 | ||
|
90ca82fe52 | ||
|
4968a34cd6 | ||
|
7aa2b34ca0 | ||
|
2319f56268 | ||
|
a5ec4a3817 | ||
|
a430eb93cb | ||
|
0bef23f217 | ||
|
c32180ce5b | ||
|
84901958a5 | ||
|
dcaa31ef16 | ||
|
763c1c5855 | ||
|
0872f9378f | ||
|
53e13abef1 | ||
|
8c614cdf9c | ||
|
dad7766afc | ||
|
cc35ac63c9 | ||
|
7ea81186c6 | ||
|
3329f60318 | ||
|
492f8b5cf7 | ||
|
0a7e556d7d | ||
|
cb50f18da9 | ||
|
b45630e879 | ||
|
dfa52c1183 | ||
|
7030a74ab9 | ||
|
f688e680c9 | ||
|
252243ab6c | ||
|
9dbe504878 | ||
|
02dc01d31e | ||
|
2ee512ba52 | ||
|
40b0eaf455 | ||
|
fc34c2b4c8 | ||
|
a48ea06e9b | ||
|
04da549942 | ||
|
68f6113430 | ||
|
84fd2a510b | ||
|
01d3dedfdf | ||
|
8e08066bc8 | ||
|
ac67abe9b6 | ||
|
02c265c5a5 | ||
|
fb2a863d12 | ||
|
19b4905018 | ||
|
c5e6c4e117 | ||
|
9985737e9b | ||
|
790834a947 | ||
|
7700fcb1dc | ||
|
d6cf81a4da | ||
|
ab2430ac76 | ||
|
72d30061b0 | ||
|
a7115cced2 | ||
|
83f9d4ec17 | ||
|
d0edde791e | ||
|
99cf0e19f7 | ||
|
9b33d299d0 | ||
|
c3cb8554b6 | ||
|
12ff5d4814 | ||
|
8a1e6f74f7 | ||
|
d769b402bc | ||
|
ab698c3d58 | ||
|
355a71fe6d | ||
|
ee37eb2803 | ||
|
74c2f7c4a7 | ||
|
66a8e93f3c | ||
|
9f422cc306 | ||
|
dc6ac9758b | ||
|
bfecd1887b | ||
|
b0a30a3581 | ||
|
1917b9c747 | ||
|
e00236193f | ||
|
6272ae6018 |
@ -4,7 +4,7 @@ FreeBSD_task:
|
|||||||
SSL: libressl
|
SSL: libressl
|
||||||
matrix:
|
matrix:
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-13-2
|
image_family: freebsd-13-3
|
||||||
prepare_script:
|
prepare_script:
|
||||||
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check imlib2 freetype2 cmocka
|
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check imlib2 freetype2 cmocka
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
|
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@ -113,7 +113,8 @@ jobs:
|
|||||||
--disable-pixman"
|
--disable-pixman"
|
||||||
CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
|
CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
|
||||||
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
|
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
|
||||||
--enable-pixman --with-imlib2 --with-freetype2 --enable-tests"
|
--enable-pixman --with-imlib2 --with-freetype2 --enable-tests
|
||||||
|
--enable-x264"
|
||||||
CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-mp3lame
|
CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-mp3lame
|
||||||
--enable-opus --enable-rfxcodec --enable-painter
|
--enable-opus --enable-rfxcodec --enable-painter
|
||||||
--disable-pixman --with-imlib2 --with-freetype2
|
--disable-pixman --with-imlib2 --with-freetype2
|
||||||
@ -132,7 +133,7 @@ jobs:
|
|||||||
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH_${{ matrix.arch }}" >> $GITHUB_ENV
|
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||||
echo "CFLAGS=$CFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
|
echo "CFLAGS=$CFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||||
echo "LDFLAGS=$LDFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
|
echo "LDFLAGS=$LDFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: "Install Dependencies"
|
- name: "Install Dependencies"
|
||||||
# See https://github.com/actions/runner-images/issues/7192
|
# See https://github.com/actions/runner-images/issues/7192
|
||||||
run: |
|
run: |
|
||||||
@ -173,9 +174,9 @@ jobs:
|
|||||||
id: os
|
id: os
|
||||||
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
|
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Cache cppcheck
|
- name: Cache cppcheck
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
env:
|
env:
|
||||||
cache-name: cache-cppcheck
|
cache-name: cache-cppcheck
|
||||||
with:
|
with:
|
||||||
@ -202,9 +203,9 @@ jobs:
|
|||||||
id: os
|
id: os
|
||||||
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
|
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Cache astyle
|
- name: Cache astyle
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
env:
|
env:
|
||||||
cache-name: cache-astyle
|
cache-name: cache-astyle
|
||||||
with:
|
with:
|
||||||
@ -213,6 +214,6 @@ jobs:
|
|||||||
- run: sudo scripts/install_astyle_dependencies_with_apt.sh
|
- run: sudo scripts/install_astyle_dependencies_with_apt.sh
|
||||||
- run: scripts/install_astyle.sh $ASTYLE_REPO $ASTYLE_VER
|
- run: scripts/install_astyle.sh $ASTYLE_REPO $ASTYLE_VER
|
||||||
- name: Format code with astyle
|
- name: Format code with astyle
|
||||||
run: scripts/run_astyle.sh
|
run: scripts/run_astyle.sh -v $ASTYLE_VER
|
||||||
- name: Check code formatting
|
- name: Check code formatting
|
||||||
run: git diff --exit-code
|
run: git diff --exit-code
|
||||||
|
865
NEWS.md
865
NEWS.md
@ -1,651 +1,262 @@
|
|||||||
# Release notes for xrdp v0.9.19 (2022/03/17)
|
# Release notes for xrdp v0.10.1 (2024/07/31)
|
||||||
|
|
||||||
## General announcements
|
## General announcements
|
||||||
* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
|
|
||||||
|
|
||||||
## New features
|
A clipboard bugfix included in this release is sponsored by Krämer Pferdesport GmbH & Co KG. We very much appreciate the sponsorship.
|
||||||
* Both inbound and outbound clipboards can now be restricted for text, files or images [Sponsored by @CyberTrust @clear-code and @kenhys] (#2087)
|
|
||||||
|
|
||||||
## Bug fixes
|
Please consider sponsoring or making a donation to the project if you like xrdp. We accept financial contributions via [Open Collective](https://opencollective.com/xrdp-project). Direct donations to each developer via GitHub Sponsors are also welcomed.
|
||||||
* [CVE-2022-23613](https://www.cve.org/CVERecord?id=CVE-2022-23613): Privilege escalation on xrdp-sesman (This fix is also in the out-of-band v0.9.18.1 release)
|
|
||||||
* The versions of imlib2 used on RHEL 7 and 8 are now detected correctly (#2118)
|
|
||||||
* Some situations where zombie processes could exist have been resolved (#2146, #2151, #2168)
|
|
||||||
* Some null-pointer exceptions which can happen in the logging module have been addressed (#2149)
|
|
||||||
* Some minor logging errors have been corrected (#2152)
|
|
||||||
* The signal handling in sesman has been reworked to prevent race conditions when a child exits. This has also made it possible to reliably reload the sesman configuration with SIGHUP (#1729, #2168)
|
|
||||||
|
|
||||||
## Internal changes
|
|
||||||
* Versions 0.13 and later of checklib can undefine the pre-processor symbol `HAVE_STDINT_H`. The xrdp tests now build successfully against these versions (#2124)
|
|
||||||
* OpenSSL packaging changes (#2130):-
|
|
||||||
- The OpenSSL 3 EVP interface is now fully supported
|
|
||||||
- When building against OpenSSL 3, an internal implementation of the RC4 cipher is used instead of the implementation from the OpenSSL legacy provider
|
|
||||||
- The wrapping of the OpenSSL library has been improved which should make it simpler to provide an alternative cryptographic provider in the future, if required
|
|
||||||
- The logging of TLS/non-TLS security negotiation has been improved
|
|
||||||
* cppcheck version used for CI bumped to 2.7 (#2140)
|
|
||||||
* The `s_check()` macro which is easily mis-used has been removed (#2144)
|
|
||||||
* Status values for the DRDYNVC channel are now available in `libxrdp/xrdp_channel.h`
|
|
||||||
|
|
||||||
## Changes for packagers or developers
|
|
||||||
* On OpenSSL 3 systems, there is now no need to build with the `-Wno-error=deprecated-declarations` flag
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
|
|
||||||
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
|
|
||||||
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.18.1 (2022/02/08)
|
|
||||||
|
|
||||||
This is a security fix release that includes fixes for the following privilege escalation vulnerability.
|
|
||||||
|
|
||||||
* [CVE-2022-23613: Privilege escalation on xrdp-sesman](https://www.cve.org/CVERecord?id=CVE-2022-23613)
|
|
||||||
|
|
||||||
Users who uses xrdp v0.9.17 or v0.9.18 are recommended to update to this version.
|
|
||||||
|
|
||||||
## Special thanks
|
|
||||||
|
|
||||||
Thanks to [Gilad Kleinman](https://github.com/giladkl) reporting the vulnerability and reviewing fix.
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.18 (2022/01/10)
|
|
||||||
|
|
||||||
## General announcements
|
|
||||||
* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
|
|
||||||
* Special thanks for @trishume for contributing code to the RFX codec
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Backgrounds and logos on the login screen can now be zoomed and scaled (#1962)
|
|
||||||
* Small change for Alpine Linux support (#2005)
|
|
||||||
* loongarch support (#2057)
|
|
||||||
* Improved Fail2ban support (#1976)
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Logging is improved for security protocol level decisions (#1974, #1975)
|
|
||||||
* An unnecessary log error message which is always generated when running neutrinordp has been removed (#2016)
|
|
||||||
* An incorrect development log message has been fixed (#2074)
|
|
||||||
* Some informational and error messages written to the console on stdout have been removed or replaced with log messages (#2078 #2080)
|
|
||||||
* Failure to attach to the memory area shared with xorgxrdp is now logged (#2065)
|
|
||||||
* A regression in the VNC module logging which might cause a connection to drop out has been identified and fixed (#1989)
|
|
||||||
* Remote drive redirection now works if printer redirection is also requested by the client (#327)
|
|
||||||
* Some file names could not be copied from the client to the server over the clipboard. This is now fixed (#1992, #1995)
|
|
||||||
* A config value has been added which allows copy-pasting of files to work with Nautilus for GNOME 3 versions >= 3.29.92 (#1994, #1996)
|
|
||||||
* Clipboard now works properly when files can't be read (#1997 #2001)
|
|
||||||
* (xorgxrdp v0.2.18) The screen is fully refreshed after initialising shared memory which should fix black screen problems like #1964
|
|
||||||
* An incorrect initialisation reported by @qarmin has been fixed (#1909)
|
|
||||||
* Some minor memory leaks have been fixed (#2014 #2028)
|
|
||||||
* A hard hang in chansrv when copying files from the remote system has been addressed (#2032)
|
|
||||||
* Users can now capitalise username and password on the login screen if required (#2061)
|
|
||||||
* Some failed size checks in the fastpath code with `--enable-devel-streamcheck` have been addressed (#2066,#2070)
|
|
||||||
* Log level for clipboard restriction has been promoted from DEVEL DEBUG to INFO (#2088)
|
|
||||||
* A buffer overflow in the RFX codec associated with large screens has been fixed (#2087)
|
|
||||||
|
|
||||||
## Internal changes
|
|
||||||
* Some 64-bit packages are removed during the 32-bit CI build process in an attempt to make this more robust (#1985)
|
|
||||||
* Minor improvements to error checking and logging for file copy-paste (#1996)
|
|
||||||
* Now uses cppcheck 2.6 for CI builds (#2008)
|
|
||||||
* Generated systemd unit files now ignored by git (#2006)
|
|
||||||
* More internal tests (#2015)
|
|
||||||
* Some unnecessary files have been removed from the distribution (#2030)
|
|
||||||
* The `which` command in shell scripts has been replaced with `command -v` (#2067)
|
|
||||||
* Additional unit tests added for `g_file_get_size()` (#1988)
|
|
||||||
* A compiler warning with -O3 on gcc 11.1 has been addressed (#2105)
|
|
||||||
* An unused declaration for xrdp_wm_drdynvc_up has been removed (#2098)
|
|
||||||
* The SCP V0 code has been unified, which will make it easier to update and replace (#2011)
|
|
||||||
* Monitor processing unit tests for existing xrdp_sec function have been added (#1932)
|
|
||||||
* The librfxcodec has been updated as part of #2087, and also to add stack frames to assemble code to assist debugging
|
|
||||||
|
|
||||||
## Changes for packagers or developers
|
|
||||||
* The `--with-imlib2` option has been added. If xrdp is built with imlib2, the login screen supports more image formats for the background and logo, and better quality zooming and scaling (#1962)
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
|
|
||||||
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
|
|
||||||
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.17 (2021/08/31)
|
|
||||||
|
|
||||||
## General announcements
|
|
||||||
* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* The IP address, port, and user name of NeutrinoRDP Proxy connection are logged in xrdp.log - these connections may not have a sesman log to use (#1873)
|
|
||||||
* The performance settings for NeutrinoRDP can be now configured (#1903)
|
|
||||||
* Support for Alpine Linux in startwm.sh (#1965)
|
|
||||||
* clipboard: log file transfer for the purpose of audit (#1954)
|
|
||||||
* Client's Keyboard layout now can be overridden by xrdp configuration for debugging purposes (#1952)
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* PAM_USER environment variable is not set when using pam_exec module (#1882)
|
|
||||||
* Allow common channel settings to be overridden for modules as well as chansrv (#1899)
|
|
||||||
* The text only-copy/paste interface for the VNC module (used only when chansrv is not active) has been improved (#1900)
|
|
||||||
* The unsupported `tcutils` utility has been removed (#1943)
|
|
||||||
* The quality of TLS logging has been improved (#1926)
|
|
||||||
* Keyboard information is now passed correctly through NeuutrinoRDP, and can be overridden if required (#1934)
|
|
||||||
* A message is now logged in the sesman log for unsuccessful login attempts detailing the user used (#1947)
|
|
||||||
|
|
||||||
|
|
||||||
## Internal changes
|
|
||||||
* astyle formatting is now checked during CI builds (#1879)
|
|
||||||
* Generalise development build options, and add --enable-devel-streamcheck (#1887)
|
|
||||||
* Now uses cppcheck 2.5 for CI builds (#1938)
|
|
||||||
* The SCP protocol is now using a standard `struct trans` for messaging rather than its own thing (#1925)
|
|
||||||
|
|
||||||
## Changes for packagers or developers
|
|
||||||
* The `--enable-xrdpdebug` developer option has been replaced with finer-grained `--enable-devel-*` options. Consequently, specifying `--enable-xrdpdebug` is now an error (#1913)
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
|
|
||||||
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
|
|
||||||
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.16 (2021/04/30)
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* On-the-fly resolution change now supported for Xvnc and Xorg (#448, #1820) - thanks to @Nexarian for this significant first contribution. See the following YouTube video for a demo.
|
|
||||||
* [Windows] https://youtu.be/cZ0ebieZHeA
|
|
||||||
* [Mac] https://youtu.be/6kfAkyLUgFY
|
|
||||||
* xrdp can now use key algorithms other than RSA for TLS (#1776)
|
|
||||||
* Do not spit on the console 2nd stage (inspired by Debian) #1762
|
|
||||||
* Unified and improved logging (#1742, #1767, #1802, #1806, #1807, #1826, #1843) - thanks to @aquesnel for this detailed work.
|
|
||||||
* Other logging level fixes (#1864)
|
|
||||||
* chansrv can now work on `DISPLAY=:0` so it can be used with x11vnc/Vino/etc sessions (#1849)
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix some regressions in sesman auth modules (#1769)
|
|
||||||
* Minor manpage fixes (#1787)
|
|
||||||
* Fix TS_PLAY_SOUND_PDU_DATA to set the correct frequency and duration (#1793)
|
|
||||||
* Fix password leakage to logs in NeutrinoRDP module (#1872) - thanks to @TOMATO-ONE for reporting.
|
|
||||||
|
|
||||||
## Internal changes
|
|
||||||
* cppcheck version for CI bumped to 2.4 (#1771, #1836)
|
|
||||||
* FreeBSD version for CI bumped to 12-2 (#1804)
|
|
||||||
* Support for check unit test framework added (#1843, #1860)
|
|
||||||
* FreeBSD FUSE module now compiles under CI but needs additional work (#1856)
|
|
||||||
* Compilation support added for additional Debian platforms (#1818)
|
|
||||||
* Refactoring:-
|
|
||||||
* Confusing preprocessor macro USE_NOPAM replaced with USE_PAM (#1800)
|
|
||||||
* Window manager states in xrdp executable now use symbolic constants instead of numbers (#1803)
|
|
||||||
* Documentation improvements
|
|
||||||
* KRDC added to client list (#1817)
|
|
||||||
* Platform support tier added (#1822)
|
|
||||||
* README file revised (#1863)
|
|
||||||
* Don't install test+development executables by default (#1858)
|
|
||||||
|
|
||||||
## Changes for packagers
|
|
||||||
These changes are likely to impact operating system package builders and those building xrdp from source.
|
|
||||||
* (#1843, #1860) This release introduces an additional optional compile-time dependency on the `check` unit test framework. The dependency is recommended when packaging for compile-time tests.
|
|
||||||
* (#1858) The executables `memtest` and `tcp_proxy` are no longer copied to the sbin directory on a package install.
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
|
|
||||||
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
|
|
||||||
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.15 (2020/12/28)
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Allow token sign in without autologon for SSO (#1667 #1668)
|
|
||||||
* Norwegian keyboard support (#1675)
|
|
||||||
* Improved config support for chansrv (#1635)
|
|
||||||
* Unified chansrv, sesman and libxrdp logging (#1633 #1708 #1738) - thanks to @aquesnel
|
|
||||||
* Support SUSE move to /usr/etc (#1702)
|
|
||||||
* Parameters may now be specified for user-specified shell (#1270 #1695)
|
|
||||||
* xrdp executables now allow alternative config files to be specified with -c (#1588 #1650 #1651)
|
|
||||||
* sesrun improvements (#1741)
|
|
||||||
* Drive redirection location can now be specified (#1048)
|
|
||||||
* Now compiles on RISC-V (#1761)
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Additional buffer overflow checks (#1662)
|
|
||||||
* FUSE support now builds on 32-bit platforms (#1682)
|
|
||||||
* genkeymap array size conflict fixed (#1691)
|
|
||||||
* Buffering issue with neutrinordp over a slow link fixed (#1608 1634)
|
|
||||||
* Various documentation fixes (#1704 #1741 #1755 #1759)
|
|
||||||
* Prevent PAM info message from causing authentication failure (#1727)
|
|
||||||
* Cosmetic fixes for minor issues (#1751 #1755 #1749)
|
|
||||||
* Try harder to clean up socket files on session exit (#1740 #1756)
|
|
||||||
* xrdp-chansrv become defunct in docker while file copy (#1658)
|
|
||||||
|
|
||||||
## Internal changes
|
|
||||||
* Compilation warnings with newer compilers (#1659 #1680)
|
|
||||||
* Continuation Integration checks on 32-bit platforms now include FUSE support (#1682)
|
|
||||||
* Continuation Integration builds now default to the Ubuntu Focal platform (#1666)
|
|
||||||
* FUSE type tidy-ups (#1686)
|
|
||||||
* Switch from Travis CI to GitHub Actions (#1728 #1732)
|
|
||||||
* Easier to set up console logging for utilities (#1711)
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.14 (2020/08/31)
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* VNC multi-monitor support if you are using a suitable Xvnc server #1343
|
|
||||||
* VNC sessions now resize by default on reconnection if you are using a suitable Xvnc server #1343
|
|
||||||
* Support Slackware for PAM #1558 #1560
|
|
||||||
* Support Programmer Dvorak Keyboard #1663
|
|
||||||
|
|
||||||
**[HEADS UP]** The VNC changes are significant. They described in more detail on the following wiki page.
|
|
||||||
* [Xvnc backend : Multi monitor and resize support](https://github.com/neutrinolabs/xrdp/wiki/Xvnc-backend-:-Multi-monitor-and-resize-support)
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix odd shift key behavior (workaround) #397 #1522
|
|
||||||
* Fix Xorg path in the document for Arch Linux #1448 #1529
|
|
||||||
* Fix Xorg path in the document for CentOS 8 #1646 #1647
|
|
||||||
* Fix internal username/password buffer is smaller than RDP protocol specification #1648 #1653
|
|
||||||
* Fix possible memory out-of-bounds accesses #1549
|
|
||||||
* Fix memory allocation overflow #1557
|
|
||||||
* Prevent chansrv input channels being scanned during a server reset #1595
|
|
||||||
* Ignore TS_MULTIFRAGMENTUPDATE_CAPABILITYSET from client if fp disabled #1593
|
|
||||||
* Minor manpage fixes #1611
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* CI error fixes
|
|
||||||
* Introduce cppcheck
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.13.1 (2020/06/30)
|
|
||||||
|
|
||||||
This is a security fix release that includes fixes for the following local buffer overflow vulnerability.
|
|
||||||
|
|
||||||
* [CVE-2020-4044: Local users can perform a buffer overflow attack against the xrdp-sesman service and then impersonate it](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-4044)
|
|
||||||
|
|
||||||
This update is recommended for all xrdp users.
|
|
||||||
|
|
||||||
## Special thanks
|
|
||||||
|
|
||||||
Thanks to [Ashley Newson](https://github.com/ashleynewson) reporting the vulnerability and reviewing fix.
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.13 (2020/03/11)
|
|
||||||
|
|
||||||
This release is an intermediate bugfix release. The previous version v0.9.12 has some regressions on drive redirection.
|
|
||||||
|
|
||||||
## Bug fixes (drive redirection related)
|
|
||||||
* Fix chansrv crashes with segmentation fault (regression in #1449) #1487
|
|
||||||
* Drive redirection now supports Guacamole client #1505 #1507
|
|
||||||
* Prevent a coredump in the event of a corrupted file system #1507
|
|
||||||
* Resolve double-free in `chansrv_fuse` #1469
|
|
||||||
|
|
||||||
## Bug fixes (other)
|
|
||||||
* Fix the issue `xrdp --version | less` will show empty output #1471 #1472
|
|
||||||
* Fix some warnings found by cppcheck #1479 #1481 #1484 #1485
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Add FreeBSD CI test #1466
|
|
||||||
* Move Microsoft-defined constants into separate includes #1470
|
|
||||||
* Perform cppcheck during CI test #1493
|
|
||||||
* Support mousex button 8/9 #1478
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.12 (2019/12/28)
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix "The log reference is NULL" error when sesman startup #1425
|
|
||||||
* Fix behavior when shmem_id changes #1439
|
|
||||||
* Make vsock config accept -1 for cid and port #1441
|
|
||||||
* Cleanup refresh rect and check stream bounds #1437
|
|
||||||
* Significant improvements in drive redirection #1449
|
|
||||||
* Fix build on macOS Catalina #1462
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Proprietary microphone redirection via rdpsnd is now default off
|
|
||||||
RDP compatible microphone redirection is on instead #1427
|
|
||||||
* Skip connecting to chansrv when no channels enabled #1393
|
|
||||||
* Add openSUSE's pam rules #1442
|
|
||||||
* Do not terminate xrdp daemon when caught SIGHUP #1319
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.11 (2019/08/19)
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Suppress output (do not draw screen when client window is minimized) #1330
|
|
||||||
* Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369
|
|
||||||
* Now xrdp can listen on more than one port #1124 #1366
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix the issue audio redirection sometimes sounds with long delay #1363
|
|
||||||
* Check term event for more responsive shutdown #1372
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.11 (2019/08/19)
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Suppress output (do not draw screen when client window is minimized) #1330
|
|
||||||
* Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369
|
|
||||||
* Now xrdp can listen on more than one port #1124 #1366
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix the issue audio redirection sometimes sounds with long delay #1363
|
|
||||||
* Check term event for more responsive shutdown #1372
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.10 (2019/04/18)
|
|
||||||
|
|
||||||
## Special thanks
|
|
||||||
Thank you for matt335672 contributing to lots of improvements in drive redirection!
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Restrict outbound (server->client) clipboard transfer, configured in `sesman.ini` #1298
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix the issue libscp v1 not setting width but height twice #1293
|
|
||||||
* Fix the issue reconnecting to session causes duplicate drive entries in fuse fs #1299
|
|
||||||
* Fix default_wm and reconnect_sh refer wrong path after sesman caught SIGUP #1315 #1331
|
|
||||||
* Shutdown xrdp more responsively #1325
|
|
||||||
* Improve remote file lookup in drive redirection #996 #1327
|
|
||||||
* Overwriting & appending to existing files is are now supported #1327
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Add Danish Keyboard #1290
|
|
||||||
* Put xrdp- prefix to some executables appear in man page #1313
|
|
||||||
* Replace some URLs from SF.net to xrdp.org #1313
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.9 (2018/12/25)
|
|
||||||
|
|
||||||
## Release cycle
|
|
||||||
From the next release, release cycle will be changed from quarterly to every
|
|
||||||
4 months. xrdp will be released in April, August, December.
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Disconnection by idle timeout (requires xorgxrdp v0.2.9 or later) #1227
|
|
||||||
* Glyph cache v2 (fixes no font issue on iOS/macOS/Android client) #367 #1235
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix xrdp-chansrv crashes caused in drive redirection #1202 #1225
|
|
||||||
* Fix build with FDK AAC v2 #1257
|
|
||||||
* Do not enable RemoteApp if the INFO_RAIL flag is not set (RDP-RDP proxy) #1253
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Add Spanish Latin Amarican keyboard #1237 #1240 #1244
|
|
||||||
* Dynamic channel improvements #1222 #1224
|
|
||||||
* Remove some deprecated sesman session types #1232
|
|
||||||
* Refactoring and cleanups
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
|
||||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.8 (2018/09/25)
|
|
||||||
|
|
||||||
## Deprecation notice
|
|
||||||
We removed TLSv1 and TLSv1.1 from the default config. The current default is TLSv1.2
|
|
||||||
and TLSv1.3. Users can whenever re-enable these early TLS versions by editing xrdp.
|
|
||||||
To use TLSv1.3, OpenSSL or LibreSSL must support TLSv1.3. You can know the OpenSSL
|
|
||||||
or LibreSSL version by `xrdp --version` command that compiled with xrdp.
|
|
||||||
|
|
||||||
## Other topics
|
|
||||||
|
|
||||||
Pulseaudio modules has been removed from xrdp source tree since it is actually
|
|
||||||
independent and not part of xrdp. The repository has been moved to:
|
|
||||||
https://github.com/neutrinolabs/pulseaudio-module-xrdp
|
|
||||||
|
|
||||||
If you want to use audio redirection, make sure install the module separately.
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Add TLSv1.3 support #1193
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Ensure unmount redirected drive on fatal X error #1140
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Show more helpful message if xrdp-dis failed #1206
|
|
||||||
* Pass pulse socket name via environment variable #1198
|
|
||||||
* Fix xrdp's log path in man page #1168
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.7 (2018/06/29)
|
|
||||||
|
|
||||||
## Deprecation notice
|
|
||||||
x11rdp has been removed from xrdp reposiory and stored in the separate repository.
|
|
||||||
Checkout [x11rdp repository](https://github.com/neutrionlabs/x11rdp) if you still need x11rdp.
|
|
||||||
In most cases, [xorgxrdp](https://github.com/neutrinolabs/xorgxrdp) can replace x11rdp.
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Fix endianness detection on ppc64el #1082
|
|
||||||
* Fix a bug xrdp file copy slow #1112 #1132
|
|
||||||
* Copy the PAM session environment for the reconnect script #1120
|
|
||||||
* Accept fullpath for DefaultWindowManager, ReconnectScript #1147
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Add PAM support for Arch Linux #1078
|
|
||||||
* Show OpenSSL version to '--version' CLI option #1096
|
|
||||||
* Separate x11rdp from xrdp repository #1104
|
|
||||||
* Support sesrun start xorgxrdp sessions #1108
|
|
||||||
* Show configure summary when configure is done #1126 #1134 #1137
|
|
||||||
* Less spit on the console when sesman starts #1142
|
|
||||||
* Fix memory leaks #1146
|
|
||||||
* Separate rc script for FreeBSD into xrdp and xrdp-sesman #1153
|
|
||||||
* Improve documents and helps
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.6 (2018/03/26)
|
|
||||||
|
|
||||||
## Compatibility notice
|
|
||||||
Exclamation mark (`!`) has been removed from comment out symbol of config files.
|
|
||||||
Use number sign (`#`) or semicolon (`;`) instead. As a result of this change, now
|
|
||||||
you can use exclamation mark as config value such as in `tls_ciphers`.
|
|
||||||
|
|
||||||
```
|
|
||||||
tls_ciphers=HIGH:!aNULL:!eNULL:!EXPORT:!RC4
|
|
||||||
```
|
|
||||||
|
|
||||||
See also: #1033
|
|
||||||
|
|
||||||
## macOS supports
|
|
||||||
Please note that xrdp still doesn't support macOS officially so far.
|
|
||||||
However, a volunteer is working on macOS compatibility.
|
|
||||||
|
|
||||||
* Generate dylibs for macOS #1015
|
|
||||||
* Add PAM support for macOS #1021
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* Make listen check before daemon fork #988
|
|
||||||
* Fix xrdp sometimes become zombie processes #1000
|
|
||||||
* Include hostname in sesman password file name #1006 #1007 #1076
|
|
||||||
* Fix default startwm.sh to use bash explicitly #1009 #1049
|
|
||||||
* Fix the issue FreeBSD doesn't acknowledge terminated sessions #1016 #1030
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Add Swiss French keyboard #1053
|
|
||||||
* Improve perfect forward secrecy, explicitly enable ECDHE/DHE #1024 #1052 #1063
|
|
||||||
* Lots of leak fixes, cleanups and refactoring
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.5 (2017/12/27)
|
|
||||||
|
|
||||||
## Security fixes
|
## Security fixes
|
||||||
* Fix local denial of service [CVE-2017-16927](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16927) #958 #979
|
* Unauthenticated RDP security scan finding / partial auth bypass (no CVE). Thanks to @txtdawg for reporting this.
|
||||||
|
|
||||||
## New features
|
## New features
|
||||||
* Add a new log level TRACE more verbose than DEBUG #835 #944
|
* GFX-RFX lossy compression levels are now selectable depending on connection type on the client (#3183, backport of #2973)
|
||||||
* SSH agent forwarding via RDP #867 #868 FreeRDP/FreeRDP#4122
|
|
||||||
* Support horizontal wheel properly #928
|
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
|
* A regression in the code for creating the chansrv FUSE directory has been fixed (#3088, backport of #3082)
|
||||||
|
* Fix a systemd dependency ("network-online.target") (#3088, backport of #3086)
|
||||||
|
* A problem in session list processing which could result in incorrect display assignments has been fixed (#3088, backport of #3103)
|
||||||
|
* A problem in GFX resizing which could lead to a SEGV in xrdp has been fixed (#3088, backport of #3107)
|
||||||
|
* A problem with the US Dvorak keyboard layout has been resolved (#3088, backport of #3112)
|
||||||
|
* A regression bug when pasting image to LibreOffice has been fixed [Sponsored by Krämer Pferdesport GmbH & Co KG] (#3102 #3120)
|
||||||
|
* Fix a regression when the server tries to negotiate GFX when max_bpp is not high enough (#3118 #3122)
|
||||||
|
* Fix a GFX multi-monitor screen placing issue on minimise/maximize (#3075 #3127)
|
||||||
|
* Fix an issue some files are not included properly in release tarball (#3149 #3150)
|
||||||
|
* Using 'I' in the session selection policy now works correctly (#3167 #3171)
|
||||||
|
* A potential name buffer overflow in the redirector has been fixed [no security implications] (#3175)
|
||||||
|
* Screens wider than 4096 pixels should now be supported (#3083)
|
||||||
|
* An unnecessary licensing exchange during connection setup has been removed. This was causing problems for FIPS-compliant clients (#3132 backport of #3143)
|
||||||
|
|
||||||
* Avoid use of hard-coded sesman port #895
|
## Internal changes
|
||||||
* Workaround for corrupted display with Windows Server 2008 using NeutrinoRDP #869
|
* FreeBSD CI bumped to 13.3 (#3088, backport of #3104)
|
||||||
* Fix glitch in audio redirection by AAC #910 #936
|
|
||||||
* Implement vsock support #930 #935 #948
|
|
||||||
* Avoid 100% CPU usage on SSL accept #956
|
|
||||||
|
|
||||||
## Other changes
|
## Changes for users
|
||||||
* Add US Dvorak keyboard #929
|
* None since v0.10.0.
|
||||||
* Suppress some misleading logs #964
|
* If moving from v0.9.x, read the v0.10.0 release note.
|
||||||
* Add Finnish keyboard #972
|
|
||||||
* Add more user-friendlier description about Xorg config #974
|
|
||||||
* Renew pulseaudio document #984 #985
|
|
||||||
* Lots of cleanups and refactoring
|
|
||||||
|
|
||||||
## Known issues
|
## Changes for packagers or developers
|
||||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
* None since v0.10.0.
|
||||||
|
* If moving from v0.9.x, read the v0.10.0 release note.
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.4 (2017/09/28)
|
# Release notes for xrdp v0.10.0 (2024/05/10)
|
||||||
|
|
||||||
## New features
|
This section notes changes since the [v0.10 branch](#branch-v010) was created.
|
||||||
* Accept prefill credentials in base64 form #153 #811
|
|
||||||
* Indroduce AAC encoder to audio redirection (requires Windows 10 client)
|
|
||||||
|
|
||||||
## Bugfixes
|
## General announcements
|
||||||
* Fix ocasional SEGV in drive redirection #838
|
The biggest news of this release is that [Graphic Pipeline Extension](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/da5c75f9-cd99-450c-98c4-014a496942b0) also called GFX in short has been supported. xrdp v0.10 with GFX achieves more frame rates and less bandwidth compared to v0.9. There is a significant performance improvement especially if the client is Windows 11's mstsc.exe or Microsoft Remote Desktop for Mac. GFX H.264/AVC 444 mode and hardware-accelerated encoding are not supported in this version yet.
|
||||||
* Fix client's IP addresses in xrdp-sesman.log are always logged as `0.0.0.0` #878 #882
|
|
||||||
* Fix `ls_background_image` didn't accept full path #776 #853
|
|
||||||
* Fix misuse of hidelogwindow #414 #876
|
|
||||||
* Fix WTSVirtualChannelWrite return code #859
|
|
||||||
* Fix no longer needed socket files remained in the socket dir #812 #831
|
|
||||||
* Make creating socket path a bit more robust #823
|
|
||||||
|
|
||||||
## Other changes
|
GFX implementation in xrdp is sponsored by an enterprise sponsor. @CyberTrust is also one of the sponsors. We very much appreciate the sponsorship. It helped us to accelerate xrdp development and land GFX earlier!
|
||||||
* Add Belgian keyboard #858
|
|
||||||
* Add a PAM file for FreeBSD #824
|
|
||||||
* Several refactorings and cosmetic changes
|
|
||||||
|
|
||||||
## Known issues
|
Please consider sponsoring or making a donation to the project if you like xrdp. We accept financial contributions via [Open Collective](https://opencollective.com/xrdp-project). Direct donations to each developer via GitHub Sponsors are also welcomed.
|
||||||
* Windows 10 (1703) shows black blank screen in RemoteFX mode
|
|
||||||
* This issue is already fixed at Insider Preview build 16273
|
|
||||||
|
|
||||||
-----------------------
|
## Highlights
|
||||||
|
This section describes the most user-visible new or changed features in xrdp since v0.9.19. See [Branch v0.10](#branch-v010) for all changes relative to v0.9.19.
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.3.1 (2017/08/16)
|
* Added GFX support with multi-monitor support (including monitor hot plug/unplug) (#2256 #2338 #2595 #2879 #2891 #2911 #2929 #2933)
|
||||||
|
* Touchpad inertial scrolling (#2364, #2424). Thanks to new contributor @seflerZ
|
||||||
This release fixes a trivial packaging issue #848 occurred in v0.9.3. The issue only affects systemd systems. This release is principally for distro packagers or users who compile & install xrdp from source.
|
* New look of login screen (#2366)
|
||||||
|
* Scaled login screen on higher DPI monitors (#2341, #2427, #2435)
|
||||||
Users who running xrdp on these systems don't need to upgrade from v0.9.3 to v0.9.3.1.
|
* This feature works automatically when monitor DPI information is sent by the client (i.e. a full-screen session)
|
||||||
|
* Native platform tools are now provided to manipulate .fv1 format font files.
|
||||||
* Linux systems without systemd
|
* The format of the date and time in the log file has been changed to ISO 8601 with milliseconds (#2386 #2541)
|
||||||
* non-Linux systems such as BSD operating systems
|
* xrdp-sesman now supports a `--reload` switch to allow for the configuration to be changed when sessions are active (#2416)
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.3 (2017/07/15)
|
|
||||||
|
|
||||||
## New features
|
|
||||||
* Log user-friendly messages when certificate/privkey is inaccessible
|
|
||||||
|
|
||||||
## Bugfixes
|
|
||||||
* Now sesman sets mandatory LOGNAME environment variable #725
|
|
||||||
* Now sesman ensures socket directory present #801
|
|
||||||
* Exit with failure status if port already in use #644
|
|
||||||
* Eliminate some hard coded paths
|
|
||||||
* Fix glitches with IPv4 struct initialization #803
|
|
||||||
* Fix some keyboard layout integration (UK, Spanish)
|
|
||||||
* Fix handle OS when IPv6 disabled #714
|
|
||||||
* Fix issues around systemd session #778
|
|
||||||
* Fix protocol error when 32 bit color and non RemoteFX session #737 #804
|
|
||||||
* Fix sesadmin shows error when no sessions #797
|
|
||||||
* Fix TLS spins 100% CPU #728
|
|
||||||
* Fix Xvnc backend disconnects when some data copied to clipboard #755
|
|
||||||
* Pick up the first section if given section(domain) doesn't match anything #750
|
|
||||||
|
|
||||||
## Other changes
|
|
||||||
* Change xrdp-chansrv log path to include display number
|
|
||||||
* Optimize startwm.sh for SUSE
|
|
||||||
* Several cleanups and optimizations
|
|
||||||
|
|
||||||
## Known issues
|
|
||||||
* Windows 10 (1703) shows black blank screen in RemoteFX mode
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.2 (2017/03/30)
|
|
||||||
## New features
|
|
||||||
* RemoteFX codec support is now enabled by default.
|
|
||||||
* Bitmap updates support is now enabled by default.
|
|
||||||
* TLS ciphers suites and version is now logged.
|
|
||||||
* Connected computer name is now logged.
|
|
||||||
* Switched to Xorg (xorgxrdp) as the default backend now.
|
|
||||||
* Miscellaneous RemoteFX codec mode improvements.
|
|
||||||
* Socket directory is configurable at the compile time.
|
|
||||||
|
|
||||||
## Bugfixes
|
|
||||||
* Parallels client for MacOS / iOS can now connect (audio redirection must be disabled on client or xrdp server though).
|
|
||||||
* MS RDP client for iOS can now connect using TLS security layer.
|
|
||||||
* MS RDP client for Android can now connect to xrdp.
|
|
||||||
* Large resolutions (4K) can be used with RemoteFX graphics.
|
|
||||||
* Multiple RemoteApps can be opened throguh NeutrinoRDP proxy.
|
|
||||||
* tls_ciphers in xrdp.ini is not limited to 63 chars anymore, it's variable-length.
|
|
||||||
* Fixed an issue where tls_ciphers were ignored and rdp security layer could be used instead.
|
|
||||||
* Kill disconnected sessions feature is working with Xorg (xorgxrdp) backend.
|
|
||||||
* Miscellaneous code cleanup and memory issues fixes.
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
# Release notes for xrdp v0.9.1 (2016/12/21)
|
|
||||||
## New features
|
|
||||||
* New xorgxrdp backend using existing Xorg with additional modules
|
|
||||||
* Improvements to X11rdp backend
|
|
||||||
* Support for IPv6 (disabled by default)
|
|
||||||
* Initial support for RemoteFX Codec (disabled by default)
|
|
||||||
* Support for TLS security layer (preferred over RDP layer if supported by the client)
|
|
||||||
* Support for disabling deprecated SSLv3 protocol and for selecting custom cipher suites in xrdp.ini
|
|
||||||
* Support for bidirectional fastpath (enabled in both directions by default)
|
|
||||||
* Support clients that don't support drawing orders, such as MS RDP client for Android, ChromeRDP (disabled by default)
|
|
||||||
* More configurable login screen
|
|
||||||
* Support for new virtual channels:
|
|
||||||
* rdpdr: device redirection
|
|
||||||
* rdpsnd: audio output
|
|
||||||
* cliprdr: clipboard
|
|
||||||
* xrdpvr: xrdp video redirection channel (can be used along with NeutrinoRDP client)
|
|
||||||
* Support for disabling virtual channels globally or by session type
|
|
||||||
* Allow to specify the path for backends (Xorg, X11rdp, Xvnc)
|
|
||||||
* Added files for systemd support
|
|
||||||
* Multi-monitor support
|
|
||||||
* xrdp-chansrv stroes logs in `${XDG_DATA_HOME}/xrdp` now
|
|
||||||
|
|
||||||
## Security fixes
|
## Security fixes
|
||||||
* User's password could be recovered from the Xvnc password file
|
None
|
||||||
* X11 authentication was not used
|
|
||||||
|
## New features
|
||||||
|
* If the client announces support for the Image RemoteFX codec it is logged (back-port of #2946)
|
||||||
|
|
||||||
|
## Bug fixes
|
||||||
|
* Fix some monitor hotplug issues (#2951)
|
||||||
|
* GFX: Fix disconnect on resize of busy windows (#2962 #2957)
|
||||||
|
* Fall back to IPv4 if IPv6 capable but don't have an IPv6 address set (#2967 #2957)
|
||||||
|
* Remove tcutils channel from xrdp.ini (#2970 #2957)
|
||||||
|
* Don't generate a corefile when generating SIGSEGV during unit testing (#2987)
|
||||||
|
* If the drdynvc static channel isn't available, disable GFX gracefully (#3003)
|
||||||
|
* A buffer misconfiguration which affects performance on high bandwidth, high latency links has been addressed (cherry-pick of #2910)
|
||||||
|
* A permissions fix for the socketdir update in #2731 has been issued (cherry-pick of #3011)
|
||||||
|
|
||||||
|
## Internal changes
|
||||||
|
* Adjust log level not too verbose (#2954 #2972 #2957)
|
||||||
|
* Migrate GitHub actions to Node 20 (#2955 #2957)
|
||||||
|
* Bump copyright year and make easier to bump (#2956 #2957)
|
||||||
|
* Remove duplicate DEBUG output (#2976 #2977)
|
||||||
|
* Add script to make release tarball (#2983)
|
||||||
|
* Syscall filter for xrdp updated (cherry-pick of #3017)
|
||||||
|
* GFX memory usage for large screens is greatly improved (cherry-pick of #3013)
|
||||||
|
* librfxcodec SSE2 performance improvements (#3032)
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
* On-the-fly resolution change with the Microsoft Store version of Remote Desktop client sometimes crashes on connect (#1869)
|
||||||
|
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
|
||||||
|
|
||||||
|
## Changes for users
|
||||||
|
* If moving from v0.9.x, read the '[User changes](#user-changes)' for the v0.10 branch below.
|
||||||
|
|
||||||
|
## Changes for packagers or developers
|
||||||
|
* If moving from v0.9.x, read the '[User changes](#user-changes)' and '[Significant changes for packagers or developers section](#significant-changes-for-packagers-or-developers)' sections for the v0.10 branch below.
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
# Branch v0.10
|
||||||
|
|
||||||
|
This branch was forked from development on 2024-02-08 in preparation for testing and release of v0.10.1.
|
||||||
|
|
||||||
|
The changes in this section are relative to version v0.9.19 of xrdp.
|
||||||
|
|
||||||
|
## User changes
|
||||||
|
* The [x11rdp](/neutrinolabs/x11rdp) X server is no longer supported. Users will need to move to xorgxrdp (#2489)
|
||||||
|
* Running xrdp and xrdp-sesman on separate hosts is no longer supported.
|
||||||
|
* There are some changes to `xrdp.ini` and `sesman.ini` which break backwards compatibility. In particular:-
|
||||||
|
* `sesman.ini/Globals/ListenAddress` is not longer used. A warning message is generated if this is found in the configuration, but the configuration will continue to work.
|
||||||
|
* `sesman.ini/Globals/ListenPort` is now a path to a socket, or an unqualified socket in a default directory. If the old default value `3350` is found, a warning is generated and a default value is used instead. The configuration will continue to work.
|
||||||
|
* The `ip` and `pamsessionmng` parameters are no longer required in sections in `xrdp.ini` to locate the sesman port. Unnecessary usages of this parameter now generate warnings. The configuration will continue to work.
|
||||||
|
* The 'C' field for the session allocation policy has been replaced with `Policy=Separate`. This field is has a very specific specialist purpose, and will not be used by the vast majority of users. The renaming makes it much clearer what is happening (#2251 #2239). Any uses of the 'C' field will generate warnings, **and the configuration will require updating**
|
||||||
|
* The format of the date and time in the log file has been changed to ISO 8601 with milliseconds (#2386 #2541)
|
||||||
|
|
||||||
|
Users are urged to heed any generated configuration warnings and update their configurations. Later major versions of xrdp may remove these warnings, or introduce other behaviours for the affected parameters.
|
||||||
|
|
||||||
|
## Security fixes
|
||||||
|
|
||||||
|
This branch provides following important security fixes reported by [Team BT5 (BoB 11th)](https://github.com/Team-BT5). We appreciate their great help with making and reviewing patches for them.
|
||||||
|
|
||||||
|
* [CVE-2022-23468](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23468)
|
||||||
|
* [CVE-2022-23477](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23477)
|
||||||
|
* [CVE-2022-23478](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23478)
|
||||||
|
* [CVE-2022-23479](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23479)
|
||||||
|
* [CVE-2022-23480](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23480)
|
||||||
|
* [CVE-2022-23481](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23481)
|
||||||
|
* [CVE-2022-23483](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23483)
|
||||||
|
* [CVE-2022-23482](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23482)
|
||||||
|
* [CVE-2022-23484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23484)
|
||||||
|
* [CVE-2022-23493](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23493)
|
||||||
|
|
||||||
|
The following issue was reported by [@gafusss](https://github.com/gafusss)
|
||||||
|
* [CVE-2023-40184](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-40184)
|
||||||
|
|
||||||
|
Other security fixes:-
|
||||||
|
* [CVE-2023-42822: Unchecked access to font glyph info](https://www.cve.org/CVERecord?id=CVE-2023-42822)
|
||||||
|
|
||||||
|
## New features
|
||||||
|
* Added GFX support with multi-monitor support (including monitor hot plug/unplug) (#2256 #2338 #2595 #2879 #2891 #2911 #2929 #2933)
|
||||||
|
* Add Ulalaca that enables remote access to macOS's native screen (developed by [team unstablers](https://unstabler.pl/))
|
||||||
|
* Ulalaca is still heavy in development, not suitable for production use yet
|
||||||
|
* `sessionbroker` and `sessionprojector` are also required, see also [README](https://github.com/unstabler/ulalaca)
|
||||||
|
* Scaled login screen on higher DPI monitors (#2341, #2427, #2435)
|
||||||
|
* This feature works automatically when monitor DPI information is sent by the client (i.e. a full-screen session)
|
||||||
|
* Native platform tools are now provided to manipulate .fv1 format font files.
|
||||||
|
* Touchpad inertial scrolling (#2364, #2424). Thanks to new contributor @seflerZ
|
||||||
|
* New look of login screen (#2366)
|
||||||
|
* Record codec GUID to identify unknown codc (#2401)
|
||||||
|
* OpenSuSE Tumbleweed move to /usr/lib/pam.d is now supported in the installation scripts (#2413)
|
||||||
|
* xrdp-sesman now supports a `--reload` switch to allow for the configuration to be changed when sessions are active (#2416)
|
||||||
|
* VNC backend session now supports extra mouse buttons 6, 7 and 8 (#2426)
|
||||||
|
* `LogFile=<stdout>` redirects log to stdout, which is useful for debugging (#2407)
|
||||||
|
* xrdp-sesrun and xrdp-sesadmin can now authenticate automatically as the logged-in user without a password (#2472)
|
||||||
|
* Empty passwords are no longer automatically passed though to sesman for authentication (#2487)
|
||||||
|
* BSD setusercontext() is now supported (#2225, #2473)
|
||||||
|
* The FUSE mount path can now be qualified with the display name or display string (#2528)
|
||||||
|
* Debian: use startup command from /usr/share/xsession if DISPLAY_SESSION is set (#2522)
|
||||||
|
* The directory where PAM configuration files is installed can now be set with `--with-pamconfdir` (#2552 #2557)
|
||||||
|
* Some classes of 'blue screen' failures have been addressed:-
|
||||||
|
* X server failures are now reported as a separate error from window manager (#2592)
|
||||||
|
* sesman failures are reported immediately (#2640)
|
||||||
|
* Allow longer UserWindowManager strings (#2651)
|
||||||
|
* Some changes have been made to made it easier to implement AppArmor support in the future (#2265):-
|
||||||
|
* `g_file_open()` has been replaced with `g_file_open_ro()` and `g_file_open_rw()` calls
|
||||||
|
* the starting of the X server with no-new-privileges can now be disabled by the administrator
|
||||||
|
* On systemd-based systems, system call filtering is used to restrict the system calls that the xrdp process can make (#2697 #2719)
|
||||||
|
* GNOME and KDE keyrings should now be supported out-of-the-box on Debian and Arch (#2776)
|
||||||
|
* Implement vsock support for FreeBSD #2798
|
||||||
|
* Side buttons on some mice are now supported by NeutrinoRDP (#2864). Thanks to new contributor @naruhito for this patch.
|
||||||
|
* Support for the Elbrus E2K architecture (#2872). Thanks to new contributor @r-a-sattarov for this patch.
|
||||||
|
* Just log Image RemoteFX codec (#2946)
|
||||||
|
|
||||||
|
## Bug fixes
|
||||||
|
* A missing directive to link libxrdpapi with libcommon has been added (#2185)
|
||||||
|
* Some sesman config warning messages could be lost. This has now been fixed (#2198)
|
||||||
|
* Moving sesman to a Unix domain socket fixes a number of issues related to firewalls and Ipv4/v6 connectivity issues (#1596 #1805 #1855)
|
||||||
|
* Secondary groups are now added correctly on Linux from /etc/security/group.conf (#1978).
|
||||||
|
* The `--disable-static` switch for `configure` now works (#1467 #2257)
|
||||||
|
* Windows RDS compatibility has been improved, so some old clients (e.g. Wyse Sx0) can now be used again with xrdp in non-TLS mode (#2166)
|
||||||
|
* PAM_RHOST is now set for the PAM stack (#2251, #392)
|
||||||
|
* A minor spacing issue in a sesman log message has been fixed (#2282)
|
||||||
|
* MSTSC crashes when resolution is changed by maximizing on a different monitor (#2291 #2300)
|
||||||
|
* Fix swapped `require_credentials`/`enable_token_login` config options in xrdp.ini manpage (#2391)
|
||||||
|
* Passwords are no longer left on the heap in sesman (#1599 #2438)
|
||||||
|
* Set permissions on pcsc socket dir to owner only (#2454 #2459)
|
||||||
|
* The Kerberos authentication module has been reworked and tested (#2453)
|
||||||
|
* Minor documentation fixes (#2481 #2581)
|
||||||
|
* The correct message is now generated when the session limit is reached (#642)
|
||||||
|
* sesman now returns better information to xrdp when session creation fails (#909, #1921)
|
||||||
|
* MaxLoginRetry limit for sesman now works (#1739)
|
||||||
|
* On systems where the same user can have multiple names, the correct session is now reconnected (#1823)
|
||||||
|
* On FreeBSD, the correct peer is now logged for xorgxrdp connections (#146)
|
||||||
|
* In some situations, xrdp sessions can be bootstrapped on system startup (#1303)
|
||||||
|
* Don't try to listen on the scard socket if it isn't there (#2504)
|
||||||
|
* Fix some noise of MP3/AAC audio redirection and add some parameters to tweak sounds (#2519 #2608)
|
||||||
|
* Memory management fixes to list module (#2536 #2575)
|
||||||
|
* Session is not now started until X server is fully active (#2492)
|
||||||
|
* Fix potential NULL dereferences in chansrv (#2573)
|
||||||
|
* An erroneous free in the smartcard handling code has been removed (#2607)
|
||||||
|
* An unnecessary 'check.h' include was removed which prevented compilation on Arch systems (#2649)
|
||||||
|
* No user session created with xrdp and pam_systemd_home account module (#1684)
|
||||||
|
* Homedir gets not correctly created at first login (#350)
|
||||||
|
* pam_setcred never returns xrdp-sesman is hung (#1323)
|
||||||
|
* chansrv should no longer hang occasionally in developer builds on session exit (#2145)
|
||||||
|
* Environment variables set by PAM modules are no longer restricted to around 250 characters (#2711)
|
||||||
|
* Checking group membership should now work better on systems using directory services (#2806 #2815)
|
||||||
|
* Pasting more than 32K characters of text to the clipboard now succeeds (#1839 #2810)
|
||||||
|
* An incompatibility with FreeRDP 2.11.2 in the drive redirector has been fixed (#2834 #2838)
|
||||||
|
* Unicode bugs have been fixed (#942 #2603)
|
||||||
|
|
||||||
|
## Internal changes
|
||||||
|
* SCP (Sesman Control Protocol) has been refactored from separate V0 and V1 protocols to a simplified V2 protocol running on top of a new library 'libipm' (#2163).
|
||||||
|
* libipm provides a way to pass file descriptors between processes (#2494)
|
||||||
|
* SCP connections are now only supported on top of Unix Domain Sockets (#2207 #2235 #2247)
|
||||||
|
* Monitor processing logic, which was in two places, has now been unified (#1895 #2301)
|
||||||
|
* Simplifications to transport connect logic (#2204)
|
||||||
|
* The fields in `struct trans` and `struct xrdp_client_info` used for storing client addressing information have been simplified (#2251)
|
||||||
|
* A couple of string utility functions have been added to parse character strings like the one used for the session allocation policy (#2251)
|
||||||
|
* cppcheck version used for CI bumped to 2.13.0 (#2520 #2737 #2785 #2886). Note that #2785 greatly increases cppcheck scan times.
|
||||||
|
* cppcheck install script no longer installs z3 for cppcheck >= 2.8 (#2782)
|
||||||
|
* The physical desktop size information sent from the client is now recorded in more situations (#2310)
|
||||||
|
* Simple maintenance improvements (#2354)
|
||||||
|
* An opaque type is now used for the auth_info handle used by the sesman auth module (#2362)
|
||||||
|
* CI updates to cope with github upgrades (#2394)
|
||||||
|
* GUIDs created for new sessions are now compliant with RFC4122 random UUIDs (#2420)
|
||||||
|
* Some 'magic numbers' have been replaced with constants (#2421)
|
||||||
|
* FreeBSD CI now runs a 'make check' (#2490)
|
||||||
|
* FreeBSD CI now runs on FreeBSD 13.2 (#2621 #2896)
|
||||||
|
* Some logging improvements on audio redirection (#2537)
|
||||||
|
* Extra executables : waitforx (#2492 #2591 #2586) xrdp-sesexec (#2644)
|
||||||
|
* The poll() system call now replaces select() for monitoring file descriptors (#2497 #2568)
|
||||||
|
* sigaction() now replaces signal() for increased portability (#2813)
|
||||||
|
* Other portability changes (#2909)
|
||||||
|
* Some extra convenience functions were added for handling lists of strings (#2576)
|
||||||
|
* `g_malloc`, `g_free`, `g_memset`, `g_memcpy`, and `g_memmove` are now macros. These should not be used in new code (#2609)
|
||||||
|
* config_ac.h is now used consistently (#2667)
|
||||||
|
* as mentioned above, `g_file_open()` has been replaced with `g_file_open_ro()` and `g_file_open_rw()` calls
|
||||||
|
* The separate fifo packages in the common directory and chansrv have now been merged (#2686)
|
||||||
|
* Unicode conversions are now provided by explicit functions rather than relying on C library `mbstowcs()`/`wcstombs()` functions (#2794)
|
||||||
|
* Some test timeouts have been increased for slow CI machines (#2901)
|
||||||
|
* `g_obj_wait()` can now take a zero timeout (#2904)
|
||||||
|
* POSIX shared memory is now used to communicate with `xorgxrdp` rather than System-V shared memory (#2709 #2786 #2889)
|
||||||
|
|
||||||
|
## Significant changes for packagers or developers
|
||||||
|
* The libscp.so shared library is replaced with libipm.so
|
||||||
|
* A new shared library libsesman.so contains shared code for sesman and related executables (#2601)
|
||||||
|
* The default setting for `--with-socketdir` is now `/var/run/xrdp` rather than `/tmp/.xrdp`. The new setting works for installations where `/tmp` is polyinstantiated ( see #1482 for more details)
|
||||||
|
* The permissions of the socketdir have changed from 1777 to 755 (owned by root). Within this directory are the sesman socket and user-specific directories. The user-specific directories store the session sockets used by each user (#2731).
|
||||||
|
It is recommended not to use the same `--with-socketdir` setting for v0.9.x and v0.10.x packages as the differing permissions can cause problems on package downgrades. See #3066 for an example of where this can be a problem.
|
||||||
|
* Passing `--disable-static` to `configure` prevents unused static libraries being installed by `make install`.
|
||||||
|
* The `simple.c` example xrdpapi program has been updated to work with logging changes, and is now built as part of the CI (#2276)
|
||||||
|
* If the `xrdp-mkfv1` utility is to be built, the switch `--with-freetype2` must be passed to `./configure`.
|
||||||
|
* Minimum supported autoconf version is now 2.69 (#2408)
|
||||||
|
* Add xrdp-sesman.system to distributed files (#2466 #2467)
|
||||||
|
* A developer-only utility to exercise the auth module selected at configure time has been provided (#2453)
|
||||||
|
* Extra executables have been added to this release in pkglibexecdir
|
||||||
|
* The default systemd unit files have been changed to no longer fork (#2672)
|
@ -71,6 +71,6 @@ libcommon_la_SOURCES = \
|
|||||||
$(PIXMAN_SOURCES)
|
$(PIXMAN_SOURCES)
|
||||||
|
|
||||||
libcommon_la_LIBADD = \
|
libcommon_la_LIBADD = \
|
||||||
-lpthread -lrt \
|
-lpthread \
|
||||||
$(OPENSSL_LIBS) \
|
$(OPENSSL_LIBS) \
|
||||||
$(DLOPEN_LIBS)
|
$(DLOPEN_LIBS)
|
||||||
|
@ -58,6 +58,10 @@
|
|||||||
#define SEC_TAG_CLI_4 0xc004 /* CS_CLUSTER? */
|
#define SEC_TAG_CLI_4 0xc004 /* CS_CLUSTER? */
|
||||||
#define SEC_TAG_CLI_MONITOR 0xc005 /* CS_MONITOR */
|
#define SEC_TAG_CLI_MONITOR 0xc005 /* CS_MONITOR */
|
||||||
#define SEC_TAG_CLI_MONITOR_EX 0xc008 /* CS_MONITOR_EX */
|
#define SEC_TAG_CLI_MONITOR_EX 0xc008 /* CS_MONITOR_EX */
|
||||||
|
#define SEC_TAG_SRV_INFO 0x0c01 /* SC_CORE */
|
||||||
|
#define SEC_TAG_SRV_CRYPT 0x0c02 /* SC_SECURITY */
|
||||||
|
#define SEC_TAG_SRV_CHANNELS 0x0c03 /* SC_NET? */
|
||||||
|
|
||||||
|
|
||||||
/* Client Core Data: colorDepth, postBeta2ColorDepth (2.2.1.3.2) */
|
/* Client Core Data: colorDepth, postBeta2ColorDepth (2.2.1.3.2) */
|
||||||
#define RNS_UD_COLOR_4BPP 0xCA00
|
#define RNS_UD_COLOR_4BPP 0xCA00
|
||||||
@ -74,6 +78,7 @@
|
|||||||
|
|
||||||
/* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */
|
/* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */
|
||||||
#define RNS_UD_CS_WANT_32BPP_SESSION 0x0002
|
#define RNS_UD_CS_WANT_32BPP_SESSION 0x0002
|
||||||
|
#define RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU 0x0040
|
||||||
#define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100
|
#define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100
|
||||||
|
|
||||||
/* Client Core Data: connectionType (2.2.1.3.2) */
|
/* Client Core Data: connectionType (2.2.1.3.2) */
|
||||||
@ -158,9 +163,16 @@
|
|||||||
#define RDP5_NO_CURSOR_SHADOW 0x20
|
#define RDP5_NO_CURSOR_SHADOW 0x20
|
||||||
#define RDP5_NO_CURSORSETTINGS 0x40 /* disables cursor blinking */
|
#define RDP5_NO_CURSORSETTINGS 0x40 /* disables cursor blinking */
|
||||||
|
|
||||||
|
/* LICENSE_PREAMBLE (2.2.1.12.1.1) */
|
||||||
|
#define ERROR_ALERT 0xff
|
||||||
|
#define PREAMBLE_VERSION_3_0 0x03
|
||||||
|
|
||||||
/* LICENSE_BINARY_BLOB (2.2.1.12.1.2) */
|
/* LICENSE_BINARY_BLOB (2.2.1.12.1.2) */
|
||||||
#define LICENCE_TAG_USER 0x000f /* BB_CLIENT_USER_NAME_BLOB */
|
#define BB_ERROR_BLOB 0x0004
|
||||||
#define LICENCE_TAG_HOST 0x0010 /* BB_CLIENT_MACHINE_NAME_BLOB */
|
|
||||||
|
/* LICENSE_ERROR_MESSAGE (2.2.1.12.1.3) */
|
||||||
|
#define STATUS_VALID_CLIENT 0x00000007
|
||||||
|
#define ST_NO_TRANSITION 0x00000002
|
||||||
|
|
||||||
/* Maps to generalCapabilitySet in T.128 page 138 */
|
/* Maps to generalCapabilitySet in T.128 page 138 */
|
||||||
|
|
||||||
@ -448,17 +460,14 @@
|
|||||||
#define RDP_DATA_PDU_LOGON 38
|
#define RDP_DATA_PDU_LOGON 38
|
||||||
#define RDP_DATA_PDU_FONT2 39
|
#define RDP_DATA_PDU_FONT2 39
|
||||||
#define RDP_DATA_PDU_DISCONNECT 47
|
#define RDP_DATA_PDU_DISCONNECT 47
|
||||||
|
#define PDUTYPE2_MONITOR_LAYOUT_PDU 55
|
||||||
|
|
||||||
/* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */
|
/* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */
|
||||||
/* TODO: to be renamed */
|
#define SEC_EXCHANGE_PKT 0x0001
|
||||||
#define SEC_CLIENT_RANDOM 0x0001 /* SEC_EXCHANGE_PKT? */
|
|
||||||
#define SEC_ENCRYPT 0x0008
|
#define SEC_ENCRYPT 0x0008
|
||||||
#define SEC_LOGON_INFO 0x0040 /* SEC_INFO_PKT */
|
#define SEC_INFO_PKT 0x0040
|
||||||
#define SEC_LICENCE_NEG 0x0080 /* SEC_LICENSE_PKT */
|
#define SEC_LICENSE_PKT 0x0080
|
||||||
|
#define SEC_LICENSE_ENCRYPT_CS 0x0280
|
||||||
#define SEC_TAG_SRV_INFO 0x0c01 /* SC_CORE */
|
|
||||||
#define SEC_TAG_SRV_CRYPT 0x0c02 /* SC_SECURITY */
|
|
||||||
#define SEC_TAG_SRV_CHANNELS 0x0c03 /* SC_NET? */
|
|
||||||
|
|
||||||
/* Slow-Path Input Event: messageType (2.2.8.1.1.3.1.1) */
|
/* Slow-Path Input Event: messageType (2.2.8.1.1.3.1.1) */
|
||||||
/* TODO: to be renamed */
|
/* TODO: to be renamed */
|
||||||
|
@ -378,6 +378,7 @@ g_tcp_socket(void)
|
|||||||
{
|
{
|
||||||
switch (errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
|
case EPROTONOSUPPORT: /* if IPv6 is supported, but don't have an IPv6 address */
|
||||||
case EAFNOSUPPORT: /* if IPv6 not supported, retry IPv4 */
|
case EAFNOSUPPORT: /* if IPv6 not supported, retry IPv4 */
|
||||||
LOG(LOG_LEVEL_INFO, "IPv6 not supported, falling back to IPv4");
|
LOG(LOG_LEVEL_INFO, "IPv6 not supported, falling back to IPv4");
|
||||||
rv = (int)socket(AF_INET, SOCK_STREAM, 0);
|
rv = (int)socket(AF_INET, SOCK_STREAM, 0);
|
||||||
@ -433,23 +434,6 @@ g_tcp_socket(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
option_len = sizeof(option_value);
|
|
||||||
|
|
||||||
if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *)&option_value,
|
|
||||||
&option_len) == 0)
|
|
||||||
{
|
|
||||||
if (option_value < (1024 * 32))
|
|
||||||
{
|
|
||||||
option_value = 1024 * 32;
|
|
||||||
option_len = sizeof(option_value);
|
|
||||||
if (setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *)&option_value,
|
|
||||||
option_len) < 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "g_tcp_socket: setsockopt() failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,23 @@ struct display_size_description
|
|||||||
unsigned int session_height;
|
unsigned int session_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum client_resize_mode
|
||||||
|
{
|
||||||
|
CRMODE_NONE,
|
||||||
|
CRMODE_SINGLE_SCREEN,
|
||||||
|
CRMODE_MULTI_SCREEN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum xrdp_capture_code
|
||||||
|
{
|
||||||
|
CC_SIMPLE = 0,
|
||||||
|
CC_SUF_A16 = 1,
|
||||||
|
CC_SUF_RFX = 2,
|
||||||
|
CC_SUF_A2 = 3,
|
||||||
|
CC_GFX_PRO = 4,
|
||||||
|
CC_GFX_A2 = 5
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the xrdp client
|
* Information about the xrdp client
|
||||||
*
|
*
|
||||||
@ -163,7 +180,7 @@ struct xrdp_client_info
|
|||||||
int mcs_early_capability_flags;
|
int mcs_early_capability_flags;
|
||||||
|
|
||||||
int max_fastpath_frag_bytes;
|
int max_fastpath_frag_bytes;
|
||||||
int capture_code;
|
int pad0; /* unused */
|
||||||
int capture_format;
|
int capture_format;
|
||||||
|
|
||||||
char certificate[1024];
|
char certificate[1024];
|
||||||
@ -218,6 +235,12 @@ struct xrdp_client_info
|
|||||||
|
|
||||||
int large_pointer_support_flags;
|
int large_pointer_support_flags;
|
||||||
int gfx;
|
int gfx;
|
||||||
|
|
||||||
|
// Can we resize the desktop by using a Deactivation-Reactivation Sequence?
|
||||||
|
enum client_resize_mode client_resize_mode;
|
||||||
|
|
||||||
|
int pad1; /* unused; unicode_input_state */
|
||||||
|
enum xrdp_capture_code capture_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum xrdp_encoder_flags
|
enum xrdp_encoder_flags
|
||||||
@ -237,6 +260,6 @@ enum xrdp_encoder_flags
|
|||||||
|
|
||||||
/* yyyymmdd of last incompatible change to xrdp_client_info */
|
/* yyyymmdd of last incompatible change to xrdp_client_info */
|
||||||
/* also used for changes to all the xrdp installed headers */
|
/* also used for changes to all the xrdp installed headers */
|
||||||
#define CLIENT_INFO_CURRENT_VERSION 20230425
|
#define CLIENT_INFO_CURRENT_VERSION 20240514
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
configure.ac
11
configure.ac
@ -1,7 +1,8 @@
|
|||||||
# Process this file with autoconf to produce a configure script
|
# Process this file with autoconf to produce a configure script
|
||||||
|
|
||||||
AC_PREREQ([2.69])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([xrdp], [0.9.80], [xrdp-devel@googlegroups.com])
|
AC_INIT([xrdp], [0.10.1], [xrdp-devel@googlegroups.com])
|
||||||
|
AC_DEFINE([VERSION_YEAR], 2024, [Copyright year])
|
||||||
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
|
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
|
||||||
AM_INIT_AUTOMAKE([1.7.2 foreign])
|
AM_INIT_AUTOMAKE([1.7.2 foreign])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
@ -166,7 +167,10 @@ AC_ARG_ENABLE(pixman, AS_HELP_STRING([--enable-pixman],
|
|||||||
[Use pixman library (default: no)]),
|
[Use pixman library (default: no)]),
|
||||||
[], [enable_pixman=no])
|
[], [enable_pixman=no])
|
||||||
AM_CONDITIONAL(XRDP_PIXMAN, [test x$enable_pixman = xyes])
|
AM_CONDITIONAL(XRDP_PIXMAN, [test x$enable_pixman = xyes])
|
||||||
|
AC_ARG_ENABLE(x264, AS_HELP_STRING([--enable-x264],
|
||||||
|
[Use x264 library (default: no)]),
|
||||||
|
[], [enable_x264=no])
|
||||||
|
AM_CONDITIONAL(XRDP_X264, [test x$enable_x264 = xyes])
|
||||||
AC_ARG_ENABLE(painter, AS_HELP_STRING([--disable-painter],
|
AC_ARG_ENABLE(painter, AS_HELP_STRING([--disable-painter],
|
||||||
[Do not use included painter library (default: no)]),
|
[Do not use included painter library (default: no)]),
|
||||||
[], [enable_painter=yes])
|
[], [enable_painter=yes])
|
||||||
@ -466,6 +470,8 @@ fi
|
|||||||
|
|
||||||
AS_IF( [test "x$enable_pixman" = "xyes"] , [PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.1.0)] )
|
AS_IF( [test "x$enable_pixman" = "xyes"] , [PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.1.0)] )
|
||||||
|
|
||||||
|
AS_IF( [test "x$enable_x264" = "xyes"] , [PKG_CHECK_MODULES(XRDP_X264, x264 >= 0.3.0)] )
|
||||||
|
|
||||||
# checking for TurboJPEG
|
# checking for TurboJPEG
|
||||||
if test "x$enable_tjpeg" = "xyes"
|
if test "x$enable_tjpeg" = "xyes"
|
||||||
then
|
then
|
||||||
@ -623,6 +629,7 @@ echo " fdkaac $enable_fdkaac"
|
|||||||
echo " jpeg $enable_jpeg"
|
echo " jpeg $enable_jpeg"
|
||||||
echo " turbo jpeg $enable_tjpeg"
|
echo " turbo jpeg $enable_tjpeg"
|
||||||
echo " rfxcodec $enable_rfxcodec"
|
echo " rfxcodec $enable_rfxcodec"
|
||||||
|
echo " x264 $enable_x264"
|
||||||
echo " painter $enable_painter"
|
echo " painter $enable_painter"
|
||||||
echo " pixman $enable_pixman"
|
echo " pixman $enable_pixman"
|
||||||
echo " fuse $enable_fuse"
|
echo " fuse $enable_fuse"
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
if USE_FREETYPE2
|
|
||||||
MKFV1_MAN = xrdp-mkfv1.8
|
|
||||||
else
|
|
||||||
MKFV1_MAN =
|
|
||||||
endif
|
|
||||||
|
|
||||||
man_MANS = \
|
man_MANS = \
|
||||||
xrdp-dis.1 \
|
xrdp-dis.1 \
|
||||||
sesman.ini.5 \
|
sesman.ini.5 \
|
||||||
@ -15,10 +9,13 @@ man_MANS = \
|
|||||||
xrdp-sesadmin.8 \
|
xrdp-sesadmin.8 \
|
||||||
xrdp-sesman.8 \
|
xrdp-sesman.8 \
|
||||||
xrdp-sesrun.8 \
|
xrdp-sesrun.8 \
|
||||||
xrdp-dumpfv1.8 \
|
xrdp-dumpfv1.8
|
||||||
$(MKFV1_MAN)
|
|
||||||
|
|
||||||
EXTRA_DIST = $(man_MANS:=.in)
|
EXTRA_DIST = xrdp-mkfv1.8.in $(man_MANS:=.in)
|
||||||
|
|
||||||
|
if USE_FREETYPE2
|
||||||
|
man_MANS += xrdp-mkfv1.8
|
||||||
|
endif
|
||||||
|
|
||||||
SUBST_VARS = sed \
|
SUBST_VARS = sed \
|
||||||
-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
|
-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
|
||||||
|
@ -133,9 +133,12 @@ by \fBseparator\fP.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBrequire_credentials\fP=\fI[true|false]\fP
|
\fBrequire_credentials\fP=\fI[true|false]\fP
|
||||||
If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients to include username and
|
If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients
|
||||||
password initial connection phase. In other words, xrdp doesn't allow clients to show login
|
to include username and password initial connection phase. In other
|
||||||
screen if set to true. If not specified, defaults to \fBfalse\fP.
|
words, xrdp doesn't allow clients to show login screen if set to true.
|
||||||
|
It follows that an incorrect password will cause the login to immediately
|
||||||
|
fail without displaying the login screen. If not specified, defaults
|
||||||
|
to \fBfalse\fP.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBsecurity_layer\fP=\fI[tls|rdp|negotiate]\fP
|
\fBsecurity_layer\fP=\fI[tls|rdp|negotiate]\fP
|
||||||
@ -177,7 +180,9 @@ If set to \fB1\fP, \fBtrue\fP or \fByes\fP, no buffering will be performed in th
|
|||||||
\fBtcp_send_buffer_bytes\fP=\fIbuffer_size\fP
|
\fBtcp_send_buffer_bytes\fP=\fIbuffer_size\fP
|
||||||
.TP
|
.TP
|
||||||
\fBtcp_recv_buffer_bytes\fP=\fIbuffer_size\fP
|
\fBtcp_recv_buffer_bytes\fP=\fIbuffer_size\fP
|
||||||
Specify send/recv buffer sizes in bytes. The default value depends on operating system.
|
Specify send/recv buffer sizes in bytes. The default value depends on
|
||||||
|
the operating system. It is recommended not to set these on systems with
|
||||||
|
dynamic TCP buffer sizing
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBtls_ciphers\fP=\fIcipher_suite\fP
|
\fBtls_ciphers\fP=\fIcipher_suite\fP
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
Description=xrdp daemon
|
Description=xrdp daemon
|
||||||
Documentation=man:xrdp(8) man:xrdp.ini(5)
|
Documentation=man:xrdp(8) man:xrdp.ini(5)
|
||||||
Requires=xrdp-sesman.service
|
Requires=xrdp-sesman.service
|
||||||
After=network.target xrdp-sesman.service
|
After=network-online.target xrdp-sesman.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=exec
|
Type=exec
|
||||||
@ -10,9 +10,7 @@ EnvironmentFile=-@sysconfdir@/sysconfig/xrdp
|
|||||||
EnvironmentFile=-@sysconfdir@/default/xrdp
|
EnvironmentFile=-@sysconfdir@/default/xrdp
|
||||||
ExecStart=@sbindir@/xrdp $XRDP_OPTIONS --nodaemon
|
ExecStart=@sbindir@/xrdp $XRDP_OPTIONS --nodaemon
|
||||||
SystemCallArchitectures=native
|
SystemCallArchitectures=native
|
||||||
SystemCallFilter=@basic-io @file-system @io-event @ipc @network-io @process
|
SystemCallFilter=@system-service
|
||||||
SystemCallFilter=@signal @system-service ioctl madvise sysinfo uname
|
|
||||||
SystemCallErrorNumber=EPERM
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit ab9b65cee1d96eefe154de721fb375f7a4d3946a
|
Subproject commit c6b41afa6986d5e6df18778a342b407cae40e1b5
|
@ -1136,43 +1136,10 @@ libxrdp_orders_send_font(struct xrdp_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Note : if this is called on a multimon setup, the client is resized
|
|
||||||
* to a single monitor */
|
|
||||||
int EXPORT_CC
|
int EXPORT_CC
|
||||||
libxrdp_reset(struct xrdp_session *session,
|
libxrdp_reset(struct xrdp_session *session)
|
||||||
unsigned int width, unsigned int height, int bpp)
|
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_reset:");
|
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_reset:");
|
||||||
if (session->client_info != 0)
|
|
||||||
{
|
|
||||||
struct xrdp_client_info *client_info = session->client_info;
|
|
||||||
|
|
||||||
/* older client can't resize */
|
|
||||||
if (client_info->build <= 419)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if same (and only one monitor on client) don't need to do anything */
|
|
||||||
if (client_info->display_sizes.session_width == width &&
|
|
||||||
client_info->display_sizes.session_height == height &&
|
|
||||||
client_info->bpp == bpp &&
|
|
||||||
(client_info->display_sizes.monitorCount == 0 || client_info->multimon == 0))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
client_info->display_sizes.session_width = width;
|
|
||||||
client_info->display_sizes.session_height = height;
|
|
||||||
client_info->display_sizes.monitorCount = 0;
|
|
||||||
client_info->bpp = bpp;
|
|
||||||
client_info->multimon = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "libxrdp_reset: session->client_info is NULL");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this will send any lingering orders */
|
/* this will send any lingering orders */
|
||||||
if (xrdp_orders_reset((struct xrdp_orders *)session->orders) != 0)
|
if (xrdp_orders_reset((struct xrdp_orders *)session->orders) != 0)
|
||||||
@ -1439,6 +1406,23 @@ libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
int
|
||||||
|
libxrdp_drdynvc_start(struct xrdp_session *session)
|
||||||
|
{
|
||||||
|
struct xrdp_rdp *rdp;
|
||||||
|
struct xrdp_sec *sec;
|
||||||
|
struct xrdp_channel *chan;
|
||||||
|
|
||||||
|
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_drdynvc_start:");
|
||||||
|
|
||||||
|
rdp = (struct xrdp_rdp *) (session->rdp);
|
||||||
|
sec = rdp->sec_layer;
|
||||||
|
chan = sec->chan_layer;
|
||||||
|
return xrdp_channel_drdynvc_start(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
int
|
int
|
||||||
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
||||||
@ -1801,6 +1785,19 @@ libxrdp_send_session_info(struct xrdp_session *session, const char *data,
|
|||||||
static void
|
static void
|
||||||
sanitise_extended_monitor_attributes(struct monitor_info *monitor_layout)
|
sanitise_extended_monitor_attributes(struct monitor_info *monitor_layout)
|
||||||
{
|
{
|
||||||
|
if (monitor_layout->physical_width == 0
|
||||||
|
&& monitor_layout->physical_width == 0
|
||||||
|
&& monitor_layout->orientation == 0
|
||||||
|
&& monitor_layout->desktop_scale_factor == 0
|
||||||
|
&& monitor_layout->device_scale_factor == 0)
|
||||||
|
{
|
||||||
|
/* Module expects us to provide defaults */
|
||||||
|
monitor_layout->orientation = ORIENTATION_LANDSCAPE;
|
||||||
|
monitor_layout->desktop_scale_factor = 100;
|
||||||
|
monitor_layout->device_scale_factor = 100;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* if EITHER physical_width or physical_height are
|
/* if EITHER physical_width or physical_height are
|
||||||
* out of range, BOTH must be ignored.
|
* out of range, BOTH must be ignored.
|
||||||
*/
|
*/
|
||||||
@ -1891,16 +1888,16 @@ libxrdp_process_monitor_stream(struct stream *s,
|
|||||||
{
|
{
|
||||||
uint32_t num_monitor;
|
uint32_t num_monitor;
|
||||||
uint32_t monitor_index;
|
uint32_t monitor_index;
|
||||||
|
struct monitor_info monitors[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS];
|
||||||
struct monitor_info *monitor_layout;
|
struct monitor_info *monitor_layout;
|
||||||
struct xrdp_rect all_monitors_encompassing_bounds = {0};
|
|
||||||
int got_primary = 0;
|
|
||||||
int monitor_struct_stream_check_bytes;
|
int monitor_struct_stream_check_bytes;
|
||||||
const char *monitor_struct_stream_check_message;
|
const char *monitor_struct_stream_check_message;
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:");
|
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:");
|
||||||
if (description == NULL)
|
if (description == NULL)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream: description was"
|
LOG_DEVEL(LOG_LEVEL_ERROR,
|
||||||
|
"libxrdp_process_monitor_stream: description was"
|
||||||
" null. Valid pointer to allocated description expected.");
|
" null. Valid pointer to allocated description expected.");
|
||||||
return SEC_PROCESS_MONITORS_ERR;
|
return SEC_PROCESS_MONITORS_ERR;
|
||||||
}
|
}
|
||||||
@ -1948,7 +1945,7 @@ libxrdp_process_monitor_stream(struct stream *s,
|
|||||||
" from [MS-RDPEDISP] 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT.";
|
" from [MS-RDPEDISP] 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT.";
|
||||||
}
|
}
|
||||||
|
|
||||||
description->monitorCount = num_monitor;
|
memset(monitors, 0, sizeof(monitors[0]) * num_monitor);
|
||||||
|
|
||||||
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
|
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
|
||||||
{
|
{
|
||||||
@ -1960,7 +1957,8 @@ libxrdp_process_monitor_stream(struct stream *s,
|
|||||||
return SEC_PROCESS_MONITORS_ERR;
|
return SEC_PROCESS_MONITORS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_layout = description->minfo + monitor_index;
|
monitor_layout = &monitors[monitor_index];
|
||||||
|
|
||||||
if (full_parameters != 0)
|
if (full_parameters != 0)
|
||||||
{
|
{
|
||||||
in_uint32_le(s, monitor_layout->flags);
|
in_uint32_le(s, monitor_layout->flags);
|
||||||
@ -2026,8 +2024,6 @@ libxrdp_process_monitor_stream(struct stream *s,
|
|||||||
in_uint32_le(s, monitor_layout->desktop_scale_factor);
|
in_uint32_le(s, monitor_layout->desktop_scale_factor);
|
||||||
in_uint32_le(s, monitor_layout->device_scale_factor);
|
in_uint32_le(s, monitor_layout->device_scale_factor);
|
||||||
|
|
||||||
sanitise_extended_monitor_attributes(monitor_layout);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT
|
* 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT
|
||||||
*/
|
*/
|
||||||
@ -2056,130 +2052,10 @@ libxrdp_process_monitor_stream(struct stream *s,
|
|||||||
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
|
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monitor_index == 0)
|
|
||||||
{
|
|
||||||
all_monitors_encompassing_bounds.left = monitor_layout->left;
|
|
||||||
all_monitors_encompassing_bounds.top = monitor_layout->top;
|
|
||||||
all_monitors_encompassing_bounds.right = monitor_layout->right;
|
|
||||||
all_monitors_encompassing_bounds.bottom = monitor_layout->bottom;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
all_monitors_encompassing_bounds.left =
|
|
||||||
MIN(monitor_layout->left,
|
|
||||||
all_monitors_encompassing_bounds.left);
|
|
||||||
all_monitors_encompassing_bounds.top =
|
|
||||||
MIN(monitor_layout->top,
|
|
||||||
all_monitors_encompassing_bounds.top);
|
|
||||||
all_monitors_encompassing_bounds.right =
|
|
||||||
MAX(all_monitors_encompassing_bounds.right,
|
|
||||||
monitor_layout->right);
|
|
||||||
all_monitors_encompassing_bounds.bottom =
|
|
||||||
MAX(all_monitors_encompassing_bounds.bottom,
|
|
||||||
monitor_layout->bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitor_layout->is_primary == TS_MONITOR_PRIMARY)
|
|
||||||
{
|
|
||||||
got_primary = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!got_primary)
|
return libxrdp_init_display_size_description(
|
||||||
{
|
num_monitor, monitors, description);
|
||||||
/* no primary monitor was set,
|
|
||||||
* choose the leftmost monitor as primary.
|
|
||||||
*/
|
|
||||||
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
|
|
||||||
{
|
|
||||||
monitor_layout = description->minfo + monitor_index;
|
|
||||||
if (monitor_layout->left
|
|
||||||
== all_monitors_encompassing_bounds.left
|
|
||||||
&& monitor_layout->top
|
|
||||||
== all_monitors_encompassing_bounds.top)
|
|
||||||
{
|
|
||||||
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set wm geometry if the encompassing area is well formed.
|
|
||||||
Otherwise, log and return an error.
|
|
||||||
*/
|
|
||||||
if (all_monitors_encompassing_bounds.right
|
|
||||||
> all_monitors_encompassing_bounds.left
|
|
||||||
&& all_monitors_encompassing_bounds.bottom
|
|
||||||
> all_monitors_encompassing_bounds.top)
|
|
||||||
{
|
|
||||||
description->session_width =
|
|
||||||
all_monitors_encompassing_bounds.right
|
|
||||||
- all_monitors_encompassing_bounds.left + 1;
|
|
||||||
description->session_height =
|
|
||||||
all_monitors_encompassing_bounds.bottom
|
|
||||||
- all_monitors_encompassing_bounds.top + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream:"
|
|
||||||
" The area encompassing the monitors is not a"
|
|
||||||
" well-formed rectangle. Received"
|
|
||||||
" (top: %d, left: %d, right: %d, bottom: %d)."
|
|
||||||
" This will prevent initialization.",
|
|
||||||
all_monitors_encompassing_bounds.top,
|
|
||||||
all_monitors_encompassing_bounds.left,
|
|
||||||
all_monitors_encompassing_bounds.right,
|
|
||||||
all_monitors_encompassing_bounds.bottom);
|
|
||||||
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure virtual desktop size is OK
|
|
||||||
* 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR)
|
|
||||||
*/
|
|
||||||
if (description->session_width
|
|
||||||
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH
|
|
||||||
|| description->session_width
|
|
||||||
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH
|
|
||||||
|| description->session_height
|
|
||||||
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT
|
|
||||||
|| description->session_height
|
|
||||||
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR,
|
|
||||||
"libxrdp_process_monitor_stream: Client supplied virtual"
|
|
||||||
" desktop width or height is invalid."
|
|
||||||
" Allowed width range: min %d, max %d. Width received: %d."
|
|
||||||
" Allowed height range: min %d, max %d. Height received: %d",
|
|
||||||
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH,
|
|
||||||
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH,
|
|
||||||
description->session_width,
|
|
||||||
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT,
|
|
||||||
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT,
|
|
||||||
description->session_width);
|
|
||||||
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* keep a copy of non negative monitor info values for xrdp_wm usage */
|
|
||||||
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
|
|
||||||
{
|
|
||||||
monitor_layout = description->minfo_wm + monitor_index;
|
|
||||||
|
|
||||||
g_memcpy(monitor_layout,
|
|
||||||
description->minfo + monitor_index,
|
|
||||||
sizeof(struct monitor_info));
|
|
||||||
|
|
||||||
monitor_layout->left =
|
|
||||||
monitor_layout->left - all_monitors_encompassing_bounds.left;
|
|
||||||
monitor_layout->top =
|
|
||||||
monitor_layout->top - all_monitors_encompassing_bounds.top;
|
|
||||||
monitor_layout->right =
|
|
||||||
monitor_layout->right - all_monitors_encompassing_bounds.left;
|
|
||||||
monitor_layout->bottom =
|
|
||||||
monitor_layout->bottom - all_monitors_encompassing_bounds.top;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -2283,6 +2159,163 @@ libxrdp_process_monitor_ex_stream(struct stream *s,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
int
|
||||||
|
libxrdp_init_display_size_description(
|
||||||
|
unsigned int num_monitor,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
struct display_size_description *description)
|
||||||
|
{
|
||||||
|
unsigned int monitor_index;
|
||||||
|
struct monitor_info *monitor_layout;
|
||||||
|
struct xrdp_rect all_monitors_encompassing_bounds = {0};
|
||||||
|
int got_primary = 0;
|
||||||
|
|
||||||
|
/* Caller should have checked this, so don't log an error */
|
||||||
|
if (num_monitor > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
|
||||||
|
{
|
||||||
|
return SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
description->monitorCount = num_monitor;
|
||||||
|
for (monitor_index = 0 ; monitor_index < num_monitor; ++monitor_index)
|
||||||
|
{
|
||||||
|
monitor_layout = &description->minfo[monitor_index];
|
||||||
|
*monitor_layout = monitors[monitor_index];
|
||||||
|
sanitise_extended_monitor_attributes(monitor_layout);
|
||||||
|
|
||||||
|
if (monitor_index == 0)
|
||||||
|
{
|
||||||
|
all_monitors_encompassing_bounds.left = monitor_layout->left;
|
||||||
|
all_monitors_encompassing_bounds.top = monitor_layout->top;
|
||||||
|
all_monitors_encompassing_bounds.right = monitor_layout->right;
|
||||||
|
all_monitors_encompassing_bounds.bottom = monitor_layout->bottom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
all_monitors_encompassing_bounds.left =
|
||||||
|
MIN(monitor_layout->left,
|
||||||
|
all_monitors_encompassing_bounds.left);
|
||||||
|
all_monitors_encompassing_bounds.top =
|
||||||
|
MIN(monitor_layout->top,
|
||||||
|
all_monitors_encompassing_bounds.top);
|
||||||
|
all_monitors_encompassing_bounds.right =
|
||||||
|
MAX(all_monitors_encompassing_bounds.right,
|
||||||
|
monitor_layout->right);
|
||||||
|
all_monitors_encompassing_bounds.bottom =
|
||||||
|
MAX(all_monitors_encompassing_bounds.bottom,
|
||||||
|
monitor_layout->bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor_layout->is_primary == TS_MONITOR_PRIMARY)
|
||||||
|
{
|
||||||
|
if (got_primary)
|
||||||
|
{
|
||||||
|
// Already got one - don't have two
|
||||||
|
monitor_layout->is_primary = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
got_primary = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!got_primary)
|
||||||
|
{
|
||||||
|
/* no primary monitor was set,
|
||||||
|
* choose the leftmost monitor as primary.
|
||||||
|
*/
|
||||||
|
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
|
||||||
|
{
|
||||||
|
monitor_layout = description->minfo + monitor_index;
|
||||||
|
if (monitor_layout->left
|
||||||
|
== all_monitors_encompassing_bounds.left
|
||||||
|
&& monitor_layout->top
|
||||||
|
== all_monitors_encompassing_bounds.top)
|
||||||
|
{
|
||||||
|
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set wm geometry if the encompassing area is well formed.
|
||||||
|
Otherwise, log and return an error.
|
||||||
|
*/
|
||||||
|
if (all_monitors_encompassing_bounds.right
|
||||||
|
> all_monitors_encompassing_bounds.left
|
||||||
|
&& all_monitors_encompassing_bounds.bottom
|
||||||
|
> all_monitors_encompassing_bounds.top)
|
||||||
|
{
|
||||||
|
description->session_width =
|
||||||
|
all_monitors_encompassing_bounds.right
|
||||||
|
- all_monitors_encompassing_bounds.left + 1;
|
||||||
|
description->session_height =
|
||||||
|
all_monitors_encompassing_bounds.bottom
|
||||||
|
- all_monitors_encompassing_bounds.top + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "libxrdp_init_display_size_description:"
|
||||||
|
" The area encompassing the monitors is not a"
|
||||||
|
" well-formed rectangle. Received"
|
||||||
|
" (top: %d, left: %d, right: %d, bottom: %d)."
|
||||||
|
" This will prevent initialization.",
|
||||||
|
all_monitors_encompassing_bounds.top,
|
||||||
|
all_monitors_encompassing_bounds.left,
|
||||||
|
all_monitors_encompassing_bounds.right,
|
||||||
|
all_monitors_encompassing_bounds.bottom);
|
||||||
|
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure virtual desktop size is OK
|
||||||
|
* 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR)
|
||||||
|
*/
|
||||||
|
if (description->session_width
|
||||||
|
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH
|
||||||
|
|| description->session_width
|
||||||
|
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH
|
||||||
|
|| description->session_height
|
||||||
|
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT
|
||||||
|
|| description->session_height
|
||||||
|
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR,
|
||||||
|
"libxrdp_init_display_size_description: Calculated virtual"
|
||||||
|
" desktop width or height is invalid."
|
||||||
|
" Allowed width range: min %d, max %d. Width received: %d."
|
||||||
|
" Allowed height range: min %d, max %d. Height received: %d",
|
||||||
|
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH,
|
||||||
|
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH,
|
||||||
|
description->session_width,
|
||||||
|
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT,
|
||||||
|
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT,
|
||||||
|
description->session_width);
|
||||||
|
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep a copy of non negative monitor info values for xrdp_wm usage */
|
||||||
|
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
|
||||||
|
{
|
||||||
|
monitor_layout = description->minfo_wm + monitor_index;
|
||||||
|
|
||||||
|
*monitor_layout = description->minfo[monitor_index];
|
||||||
|
|
||||||
|
monitor_layout->left =
|
||||||
|
monitor_layout->left - all_monitors_encompassing_bounds.left;
|
||||||
|
monitor_layout->top =
|
||||||
|
monitor_layout->top - all_monitors_encompassing_bounds.top;
|
||||||
|
monitor_layout->right =
|
||||||
|
monitor_layout->right - all_monitors_encompassing_bounds.left;
|
||||||
|
monitor_layout->bottom =
|
||||||
|
monitor_layout->bottom - all_monitors_encompassing_bounds.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
int EXPORT_CC
|
int EXPORT_CC
|
||||||
libxrdp_planar_compress(char *in_data, int width, int height,
|
libxrdp_planar_compress(char *in_data, int width, int height,
|
||||||
|
@ -437,6 +437,10 @@ int
|
|||||||
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
||||||
int data_pdu_type);
|
int data_pdu_type);
|
||||||
int
|
int
|
||||||
|
xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s,
|
||||||
|
int data_pdu_type, int channel_id,
|
||||||
|
int compress);
|
||||||
|
int
|
||||||
xrdp_rdp_send_fastpath(struct xrdp_rdp *self, struct stream *s,
|
xrdp_rdp_send_fastpath(struct xrdp_rdp *self, struct stream *s,
|
||||||
int data_pdu_type);
|
int data_pdu_type);
|
||||||
int
|
int
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "xrdp_rail.h"
|
#include "xrdp_rail.h"
|
||||||
|
|
||||||
struct list;
|
struct list;
|
||||||
|
struct monitor_info;
|
||||||
|
|
||||||
/* struct xrdp_client_info moved to xrdp_client_info.h */
|
/* struct xrdp_client_info moved to xrdp_client_info.h */
|
||||||
|
|
||||||
@ -195,8 +196,7 @@ libxrdp_orders_send_font(struct xrdp_session *session,
|
|||||||
struct xrdp_font_char *font_char,
|
struct xrdp_font_char *font_char,
|
||||||
int font_index, int char_index);
|
int font_index, int char_index);
|
||||||
int
|
int
|
||||||
libxrdp_reset(struct xrdp_session *session,
|
libxrdp_reset(struct xrdp_session *session);
|
||||||
unsigned int width, unsigned int height, int bpp);
|
|
||||||
int
|
int
|
||||||
libxrdp_orders_send_raw_bitmap2(struct xrdp_session *session,
|
libxrdp_orders_send_raw_bitmap2(struct xrdp_session *session,
|
||||||
int width, int height, int bpp, char *data,
|
int width, int height, int bpp, char *data,
|
||||||
@ -241,6 +241,8 @@ int
|
|||||||
libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
|
libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
|
||||||
int is_disabled);
|
int is_disabled);
|
||||||
int
|
int
|
||||||
|
libxrdp_drdynvc_start(struct xrdp_session *session);
|
||||||
|
int
|
||||||
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
||||||
int flags, struct xrdp_drdynvc_procs *procs,
|
int flags, struct xrdp_drdynvc_procs *procs,
|
||||||
int *chan_id);
|
int *chan_id);
|
||||||
@ -346,4 +348,21 @@ int EXPORT_CC
|
|||||||
libxrdp_process_monitor_ex_stream(struct stream *s,
|
libxrdp_process_monitor_ex_stream(struct stream *s,
|
||||||
struct display_size_description *description);
|
struct display_size_description *description);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a list of monitors into a full description
|
||||||
|
*
|
||||||
|
* Monitor data is sanitised during the conversion
|
||||||
|
*
|
||||||
|
* @param num_monitor Monitor count (> 0)
|
||||||
|
* @param monitors List of monitors
|
||||||
|
* @param[out] description Display size description
|
||||||
|
*
|
||||||
|
* @return 0 if the data is processed, non-zero if there is an error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
libxrdp_init_display_size_description(
|
||||||
|
unsigned int num_monitor,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
struct display_size_description *description);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,6 +48,7 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
|
|||||||
struct stream *s;
|
struct stream *s;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
struct display_size_description *description;
|
struct display_size_description *description;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
@ -74,14 +75,13 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
|
|||||||
|
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
|
|
||||||
if (xrdp_rdp_send_data(self, s, 0x37) != 0)
|
// [MS-RDPBCGR]
|
||||||
{
|
// - 2.2.12.1 - ...the pduSource field MUST be set to zero.
|
||||||
free_stream(s);
|
// - 3.3.5.12.1 - The contents of this PDU SHOULD NOT be compressed
|
||||||
return 1;
|
rv = xrdp_rdp_send_data_from_channel(self, s,
|
||||||
}
|
PDUTYPE2_MONITOR_LAYOUT_PDU, 0, 0);
|
||||||
|
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
return 0;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -120,6 +120,45 @@ xrdp_caps_process_general(struct xrdp_rdp *self, struct stream *s,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static int
|
||||||
|
xrdp_caps_process_bitmap(struct xrdp_rdp *self, struct stream *s,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
/* [MS-RDPBCGR] 2.2.7.1.2 */
|
||||||
|
int desktopResizeFlag;
|
||||||
|
if (len < 14 + 2)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "Not enough bytes in the stream: "
|
||||||
|
"len 16, remaining %d", len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_uint8s(s, 14);
|
||||||
|
in_uint16_le(s, desktopResizeFlag);
|
||||||
|
|
||||||
|
/* Work out what kind of client resizing we can do from the server */
|
||||||
|
int early_cap_flags = self->client_info.mcs_early_capability_flags;
|
||||||
|
if (desktopResizeFlag == 0)
|
||||||
|
{
|
||||||
|
self->client_info.client_resize_mode = CRMODE_NONE;
|
||||||
|
LOG(LOG_LEVEL_INFO, "Client cannot be resized by xrdp");
|
||||||
|
}
|
||||||
|
else if ((early_cap_flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) == 0)
|
||||||
|
{
|
||||||
|
self->client_info.client_resize_mode = CRMODE_SINGLE_SCREEN;
|
||||||
|
LOG(LOG_LEVEL_INFO, "Client supports single-screen resizes by xrdp");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->client_info.client_resize_mode = CRMODE_MULTI_SCREEN;
|
||||||
|
LOG(LOG_LEVEL_INFO, "Client supports multi-screen resizes by xrdp");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* Process [MS-RDPBCGR] TS_ORDER_CAPABILITYSET (2.2.7.1.3) message.
|
* Process [MS-RDPBCGR] TS_ORDER_CAPABILITYSET (2.2.7.1.3) message.
|
||||||
@ -603,6 +642,12 @@ xrdp_caps_process_codecs(struct xrdp_rdp *self, struct stream *s, int len)
|
|||||||
g_memcpy(self->client_info.h264_prop, s->p, i1);
|
g_memcpy(self->client_info.h264_prop, s->p, i1);
|
||||||
self->client_info.h264_prop_len = i1;
|
self->client_info.h264_prop_len = i1;
|
||||||
}
|
}
|
||||||
|
/* other known codec but not supported yet */
|
||||||
|
else if (g_memcmp(codec_guid, XR_CODEC_GUID_IMAGE_REMOTEFX, 16) == 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_caps_process_codecs: Image RemoteFX(%s), codec id [%d], properties len [%d]",
|
||||||
|
codec_guid_str, codec_id, codec_properties_length);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_WARNING, "xrdp_caps_process_codecs: unknown(%s), codec id [%d], properties len [%d]",
|
LOG(LOG_LEVEL_WARNING, "xrdp_caps_process_codecs: unknown(%s), codec id [%d], properties len [%d]",
|
||||||
@ -760,7 +805,8 @@ xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
|
|||||||
break;
|
break;
|
||||||
case CAPSTYPE_BITMAP:
|
case CAPSTYPE_BITMAP:
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
|
LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
|
||||||
"capabilitySetType = CAPSTYPE_BITMAP - Ignored");
|
"capabilitySetType = CAPSTYPE_BITMAP");
|
||||||
|
xrdp_caps_process_bitmap(self, s, len);
|
||||||
break;
|
break;
|
||||||
case CAPSTYPE_ORDER:
|
case CAPSTYPE_ORDER:
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
|
LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
|
||||||
@ -1331,8 +1377,11 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send Monitor Layout PDU for dual monitor */
|
/* send Monitor Layout PDU for multi-monitor */
|
||||||
if (self->client_info.display_sizes.monitorCount > 0 &&
|
int early_cap_flags = self->client_info.mcs_early_capability_flags;
|
||||||
|
|
||||||
|
if ((early_cap_flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) != 0 &&
|
||||||
|
self->client_info.display_sizes.monitorCount > 0 &&
|
||||||
self->client_info.multimon == 1)
|
self->client_info.multimon == 1)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_send_demand_active: sending monitor layout pdu");
|
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_send_demand_active: sending monitor layout pdu");
|
||||||
|
@ -752,46 +752,63 @@ xrdp_channel_drdynvc_send_capability_request(struct xrdp_channel *self)
|
|||||||
int
|
int
|
||||||
xrdp_channel_drdynvc_start(struct xrdp_channel *self)
|
xrdp_channel_drdynvc_start(struct xrdp_channel *self)
|
||||||
{
|
{
|
||||||
int index;
|
int rv = 0;
|
||||||
int count;
|
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||||
struct mcs_channel_item *ci;
|
"xrdp_channel_drdynvc_start: drdynvc_channel_id %d",
|
||||||
struct mcs_channel_item *dci;
|
self->drdynvc_channel_id);
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: drdynvc_channel_id %d", self->drdynvc_channel_id);
|
|
||||||
if (self->drdynvc_channel_id != -1)
|
if (self->drdynvc_channel_id != -1)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: already started");
|
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||||
return 0;
|
"xrdp_channel_drdynvc_start: already started");
|
||||||
}
|
|
||||||
dci = NULL;
|
|
||||||
count = self->mcs_layer->channel_list->count;
|
|
||||||
for (index = 0; index < count; index++)
|
|
||||||
{
|
|
||||||
ci = (struct mcs_channel_item *)
|
|
||||||
list_get_item(self->mcs_layer->channel_list, index);
|
|
||||||
if (ci != NULL)
|
|
||||||
{
|
|
||||||
if (g_strcasecmp(ci->name, "drdynvc") == 0)
|
|
||||||
{
|
|
||||||
dci = ci;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dci != NULL)
|
|
||||||
{
|
|
||||||
self->drdynvc_channel_id = (dci->chanid - MCS_GLOBAL_CHANNEL) - 1;
|
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG,
|
|
||||||
"Initializing Dynamic Virtual Channel with channel id %d",
|
|
||||||
self->drdynvc_channel_id);
|
|
||||||
xrdp_channel_drdynvc_send_capability_request(self);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_WARNING,
|
int index;
|
||||||
"Dynamic Virtual Channel named 'drdynvc' not found, "
|
int count;
|
||||||
"channel not initialized");
|
struct mcs_channel_item *ci;
|
||||||
|
struct mcs_channel_item *dci;
|
||||||
|
dci = NULL;
|
||||||
|
count = self->mcs_layer->channel_list->count;
|
||||||
|
for (index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
ci = (struct mcs_channel_item *)
|
||||||
|
list_get_item(self->mcs_layer->channel_list, index);
|
||||||
|
if (ci != NULL)
|
||||||
|
{
|
||||||
|
if (g_strcasecmp(ci->name, DRDYNVC_SVC_CHANNEL_NAME) == 0)
|
||||||
|
{
|
||||||
|
dci = ci;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dci == NULL)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Static channel '%s' not found.",
|
||||||
|
DRDYNVC_SVC_CHANNEL_NAME);
|
||||||
|
rv = -1;
|
||||||
|
}
|
||||||
|
else if (dci->disabled)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Static channel '%s' is disabled.",
|
||||||
|
DRDYNVC_SVC_CHANNEL_NAME);
|
||||||
|
rv = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->drdynvc_channel_id = (dci->chanid - MCS_GLOBAL_CHANNEL) - 1;
|
||||||
|
LOG_DEVEL(LOG_LEVEL_DEBUG, DRDYNVC_SVC_CHANNEL_NAME
|
||||||
|
"Initializing Dynamic Virtual Channel with channel id %d",
|
||||||
|
self->drdynvc_channel_id);
|
||||||
|
xrdp_channel_drdynvc_send_capability_request(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Dynamic channels will not be available");
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -585,11 +585,13 @@ xrdp_rdp_send(struct xrdp_rdp *self, struct stream *s, int pdu_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Send a [MS-RDPBCGR] Data PDU with for the given pduType2 with the headers
|
/* Send a [MS-RDPBCGR] Data PDU for the given pduType2 from
|
||||||
|
* the specified source with the headers
|
||||||
added and data compressed */
|
added and data compressed */
|
||||||
int
|
int
|
||||||
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s,
|
||||||
int data_pdu_type)
|
int data_pdu_type, int channel_id,
|
||||||
|
int compress)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
int ctype;
|
int ctype;
|
||||||
@ -614,7 +616,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
|||||||
clen = len;
|
clen = len;
|
||||||
tocomplen = pdulen - 18;
|
tocomplen = pdulen - 18;
|
||||||
|
|
||||||
if (self->client_info.rdp_compression && self->session->up_and_running)
|
if (compress && self->client_info.rdp_compression &&
|
||||||
|
self->session->up_and_running)
|
||||||
{
|
{
|
||||||
mppc_enc = self->mppc_enc;
|
mppc_enc = self->mppc_enc;
|
||||||
if (compress_rdp(mppc_enc, (tui8 *)(s->p + 18), tocomplen))
|
if (compress_rdp(mppc_enc, (tui8 *)(s->p + 18), tocomplen))
|
||||||
@ -643,7 +646,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE,
|
LOG_DEVEL(LOG_LEVEL_TRACE,
|
||||||
"xrdp_rdp_send_data: compress_rdp failed, sending "
|
"xrdp_rdp_send_data_from_channel: "
|
||||||
|
"compress_rdp failed, sending "
|
||||||
"uncompressed data. type %d, flags %d",
|
"uncompressed data. type %d, flags %d",
|
||||||
mppc_enc->protocol_type, mppc_enc->flags);
|
mppc_enc->protocol_type, mppc_enc->flags);
|
||||||
}
|
}
|
||||||
@ -652,11 +656,11 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
|||||||
/* TS_SHARECONTROLHEADER */
|
/* TS_SHARECONTROLHEADER */
|
||||||
out_uint16_le(s, pdulen); /* totalLength */
|
out_uint16_le(s, pdulen); /* totalLength */
|
||||||
out_uint16_le(s, pdutype); /* pduType */
|
out_uint16_le(s, pdutype); /* pduType */
|
||||||
out_uint16_le(s, self->mcs_channel); /* pduSource */
|
out_uint16_le(s, channel_id); /* pduSource */
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [MS-RDPBCGR] TS_SHARECONTROLHEADER "
|
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [MS-RDPBCGR] TS_SHARECONTROLHEADER "
|
||||||
"totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, "
|
"totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, "
|
||||||
"pduSource %d", pdulen, PDUTYPE_TO_STR(pdutype & 0xf),
|
"pduSource %d", pdulen, PDUTYPE_TO_STR(pdutype & 0xf),
|
||||||
pdutype & 0xf, ((pdutype & 0xfff0) >> 4), self->mcs_channel);
|
pdutype & 0xf, ((pdutype & 0xfff0) >> 4), channel_id);
|
||||||
|
|
||||||
/* TS_SHAREDATAHEADER */
|
/* TS_SHAREDATAHEADER */
|
||||||
out_uint32_le(s, self->share_id);
|
out_uint32_le(s, self->share_id);
|
||||||
@ -673,13 +677,26 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
|||||||
|
|
||||||
if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0)
|
if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "xrdp_rdp_send_data: xrdp_sec_send failed");
|
LOG(LOG_LEVEL_ERROR, "xrdp_rdp_send_data_from_channel: "
|
||||||
|
"xrdp_sec_send failed");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Send a [MS-RDPBCGR] Data PDU on the MCS channel for the given pduType2
|
||||||
|
* with the headers added and data compressed */
|
||||||
|
int
|
||||||
|
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
||||||
|
int data_pdu_type)
|
||||||
|
{
|
||||||
|
return xrdp_rdp_send_data_from_channel(self, s, data_pdu_type,
|
||||||
|
self->mcs_channel, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* returns the fastpath rdp byte count */
|
/* returns the fastpath rdp byte count */
|
||||||
int
|
int
|
||||||
@ -1306,7 +1323,6 @@ xrdp_rdp_process_data_font(struct xrdp_rdp *self, struct stream *s)
|
|||||||
self->session->callback(self->session->id, 0x555a, 0, 0,
|
self->session->callback(self->session->id, 0x555a, 0, 0,
|
||||||
0, 0);
|
0, 0);
|
||||||
}
|
}
|
||||||
xrdp_channel_drdynvc_start(self->sec_layer->chan_layer);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -43,207 +43,6 @@ static tui8 g_pad_92[48] =
|
|||||||
92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92
|
92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Licensing request v2 PDU
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
|
|
||||||
* [MS-RDPELE] SERVER_LICENSE_REQUEST with PREAMBLE_VERSION_2_0
|
|
||||||
*/
|
|
||||||
/* some compilers need unsigned char to avoid warnings */
|
|
||||||
static tui8 g_lic1[322] =
|
|
||||||
{
|
|
||||||
/* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
|
|
||||||
* flags (2) = 0x0080 (SEC_LICENSE_PKT)
|
|
||||||
* flagsHi (2) = unused (arbitrary data)
|
|
||||||
* [MS-RDPBCGR] LICENSE_PREAMBLE
|
|
||||||
* bMsgType (1) = 0x01 (LICENSE_REQUEST)
|
|
||||||
* flags (1) = 0x02 (PREAMBLE_VERSION_2_0)
|
|
||||||
* wMsgSize (2) = 318 (excludes the 4 bytes TS_SECURITY_HEADER Basic)
|
|
||||||
*/
|
|
||||||
0x80, 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3e, 0x01,
|
|
||||||
/* [MS-RDPELE] SERVER_LICENSE_REQUEST
|
|
||||||
* ServerRandom (32) = <see hex below>
|
|
||||||
*/
|
|
||||||
0x7b, 0x3c, 0x31, 0xa6, 0xae, 0xe8, 0x74, 0xf6,
|
|
||||||
0xb4, 0xa5, 0x03, 0x90, 0xe7, 0xc2, 0xc7, 0x39,
|
|
||||||
0xba, 0x53, 0x1c, 0x30, 0x54, 0x6e, 0x90, 0x05,
|
|
||||||
0xd0, 0x05, 0xce, 0x44, 0x18, 0x91, 0x83, 0x81,
|
|
||||||
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - ProductInfo
|
|
||||||
* [MS-RDPELE] PRODUCT_INFO
|
|
||||||
* dwVersion (4) = 0x00040000
|
|
||||||
* cbCompanyName (4) = 0x0000002c (44)
|
|
||||||
*/
|
|
||||||
0x00, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00,
|
|
||||||
/*
|
|
||||||
* pbCompanyName (44) = UTF-16("Microsoft Corporation")
|
|
||||||
* cbProductId (4) = 0x00000008 (8)
|
|
||||||
*/
|
|
||||||
0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00,
|
|
||||||
0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00,
|
|
||||||
0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00,
|
|
||||||
0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00,
|
|
||||||
0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00,
|
|
||||||
0x6e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
|
||||||
/*
|
|
||||||
* pbProductId (8) = UTF-16("236")
|
|
||||||
*/
|
|
||||||
0x32, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00,
|
|
||||||
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - KeyExchangeList
|
|
||||||
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
|
|
||||||
* wBlobType (2) = 0x000d (BB_KEY_EXCHG_ALG_BLOB)
|
|
||||||
* wBlobLen (2) = 0x0004 (4)
|
|
||||||
* blobData (4) = 0x00000001 (KEY_EXCHANGE_ALG_RSA)
|
|
||||||
*/
|
|
||||||
0x0d, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - ServerCertificate
|
|
||||||
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
|
|
||||||
* wBlobType (2) = BB_CERTIFICATE_BLOB (0x0003)
|
|
||||||
* wBlobLen (2) = 0x00b8 (184)
|
|
||||||
* blobData = <SERVER_CERTIFICATE>
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] SERVER_CERTIFICATE
|
|
||||||
* dwVersion (31 bits) = 0x00000001 (CERT_CHAIN_VERSION_1)
|
|
||||||
* t (1 bit) = 0 (temporary certificate)
|
|
||||||
*/
|
|
||||||
0x03, 0x00, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
/*
|
|
||||||
* certData = <PROPRIETARYSERVERCERTIFICATE>
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] PROPRIETARYSERVERCERTIFICATE
|
|
||||||
* dwSigAlgId (4) = 0x00000001 (SIGNATURE_ALG_RSA)
|
|
||||||
* dwKeyAlgId (4) = 0x00000001 (KEY_EXCHANGE_ALG_RSA)
|
|
||||||
* wPublicKeyBlobType (2) = 0x0006 (BB_RSA_KEY_BLOB)
|
|
||||||
* wPublicKeyBlobLen (2) = 0x005c (92)
|
|
||||||
* PublicKeyBlob = <RSA_PUBLIC_KEY>
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] RSA_PUBLIC_KEY
|
|
||||||
* magic (4) = 0x31415352
|
|
||||||
* keylen (4) = 0x00000048 (72)
|
|
||||||
* bitlen (4) = 0x00000200 (512)
|
|
||||||
* datalen (4) = 0x0000003f (63)
|
|
||||||
* pubExp (4) = 0x00010001 (65537)
|
|
||||||
*/
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31,
|
|
||||||
0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
|
|
||||||
0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
|
|
||||||
/*
|
|
||||||
* modulus (72) = <see hex below>
|
|
||||||
*/
|
|
||||||
0x01, 0xc7, 0xc9, 0xf7, 0x8e, 0x5a, 0x38, 0xe4,
|
|
||||||
0x29, 0xc3, 0x00, 0x95, 0x2d, 0xdd, 0x4c, 0x3e,
|
|
||||||
0x50, 0x45, 0x0b, 0x0d, 0x9e, 0x2a, 0x5d, 0x18,
|
|
||||||
0x63, 0x64, 0xc4, 0x2c, 0xf7, 0x8f, 0x29, 0xd5,
|
|
||||||
0x3f, 0xc5, 0x35, 0x22, 0x34, 0xff, 0xad, 0x3a,
|
|
||||||
0xe6, 0xe3, 0x95, 0x06, 0xae, 0x55, 0x82, 0xe3,
|
|
||||||
0xc8, 0xc7, 0xb4, 0xa8, 0x47, 0xc8, 0x50, 0x71,
|
|
||||||
0x74, 0x29, 0x53, 0x89, 0x6d, 0x9c, 0xed, 0x70,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - ServerCertificate
|
|
||||||
* [MS-RDPBCGR] LICENSE_BINARY_BLOB - blobData
|
|
||||||
* [MS-RDPBCGR] SERVER_CERTIFICATE - certData
|
|
||||||
* [MS-RDPBCGR] PROPRIETARYSERVERCERTIFICATE
|
|
||||||
* wSignatureBlobType (2) = 0x0008 (BB_RSA_SIGNATURE_BLOB)
|
|
||||||
* wSignatureBlobLen (2) = 0x0048 (72)
|
|
||||||
* SignatureBlob (72) = <see hex below, calculated using [MS-RDPBCGR] 5.3.3.1.2>
|
|
||||||
*/
|
|
||||||
0x08, 0x00, 0x48, 0x00, 0xa8, 0xf4, 0x31, 0xb9,
|
|
||||||
0xab, 0x4b, 0xe6, 0xb4, 0xf4, 0x39, 0x89, 0xd6,
|
|
||||||
0xb1, 0xda, 0xf6, 0x1e, 0xec, 0xb1, 0xf0, 0x54,
|
|
||||||
0x3b, 0x5e, 0x3e, 0x6a, 0x71, 0xb4, 0xf7, 0x75,
|
|
||||||
0xc8, 0x16, 0x2f, 0x24, 0x00, 0xde, 0xe9, 0x82,
|
|
||||||
0x99, 0x5f, 0x33, 0x0b, 0xa9, 0xa6, 0x94, 0xaf,
|
|
||||||
0xcb, 0x11, 0xc3, 0xf2, 0xdb, 0x09, 0x42, 0x68,
|
|
||||||
0x29, 0x56, 0x58, 0x01, 0x56, 0xdb, 0x59, 0x03,
|
|
||||||
0x69, 0xdb, 0x7d, 0x37, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* <last 4 bytes of SignatureBlob>
|
|
||||||
*
|
|
||||||
* [MS-RDPELE] SERVER_LICENSE_REQUEST - ScopeList
|
|
||||||
* [MS-RDPELE] SCOPE_LIST
|
|
||||||
* ScopeCount (4) = 0x00000001 (1)
|
|
||||||
* ScopeArray = <LICENSE_BINARY_BLOB>
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
|
|
||||||
* wBlobType (2) = 0x000e (BB_SCOPE_BLOB)
|
|
||||||
* wBlobLen (2) = 0x000e (14)
|
|
||||||
* blobData (14) = ISO-8859-1("microsoft.com")
|
|
||||||
*/
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x0e, 0x00, 0x0e, 0x00, 0x6d, 0x69, 0x63, 0x72,
|
|
||||||
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f,
|
|
||||||
0x6d, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Licensing success response v2 PDU
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
|
|
||||||
* [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT
|
|
||||||
*/
|
|
||||||
/* some compilers need unsigned char to avoid warnings */
|
|
||||||
static tui8 g_lic2[20] =
|
|
||||||
{
|
|
||||||
/* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
|
|
||||||
* flags (2) = 0x0080 (SEC_LICENSE_PKT)
|
|
||||||
* flagsHi (2) = unused (arbitrary data)
|
|
||||||
* [MS-RDPBCGR] LICENSE_PREAMBLE
|
|
||||||
* bMsgType (1) = 0xff (ERROR_ALERT)
|
|
||||||
* flags (1) = 0x02 (PREAMBLE_VERSION_2_0)
|
|
||||||
* wMsgSize (2) = 0x10 (16, excludes the 4 bytes TS_SECURITY_HEADER Basic)
|
|
||||||
*/
|
|
||||||
0x80, 0x00, 0x10, 0x00, 0xff, 0x02, 0x10, 0x00,
|
|
||||||
/*
|
|
||||||
* [MS-RDPBCGR] LICENSE_ERROR_MESSAGE
|
|
||||||
* dwErrorCode (4) = 0x00000007 (STATUS_VALID_CLIENT)
|
|
||||||
* dwStateTransition (4) = 0x00000002 (ST_NO_TRANSITION)
|
|
||||||
* bbErrorInfo = <LICENSE_BINARY_BLOB>
|
|
||||||
*/
|
|
||||||
0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
||||||
/*
|
|
||||||
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
|
|
||||||
* wBlobType (2) = 0x1428 <ignored by client> (should be 0x0004 BB_ERROR_BLOB)
|
|
||||||
* wBlobLen (2) = 0x0000 (0)
|
|
||||||
*/
|
|
||||||
0x28, 0x14, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Licensing success response v3 PDU
|
|
||||||
*
|
|
||||||
* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
|
|
||||||
* [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT
|
|
||||||
*
|
|
||||||
* used for Media Center Edition
|
|
||||||
*/
|
|
||||||
/* some compilers need unsigned char to avoid warnings */
|
|
||||||
static tui8 g_lic3[20] =
|
|
||||||
{
|
|
||||||
/* S */
|
|
||||||
/* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
|
|
||||||
* flags (2) = 0x0280 (SEC_LICENSE_PKT | SEC_LICENSE_ENCRYPT_CS)
|
|
||||||
* flagsHi (2) = unused (arbitrary data)
|
|
||||||
* [MS-RDPBCGR] LICENSE_PREAMBLE
|
|
||||||
* bMsgType (1) = 0xff (ERROR_ALERT)
|
|
||||||
* flags (1) = 0x03 (PREAMBLE_VERSION_3_0)
|
|
||||||
* wMsgSize (2) = 0x0010 (16, excludes the 4 bytes TS_SECURITY_HEADER Basic)
|
|
||||||
*/
|
|
||||||
0x80, 0x02, 0x10, 0x00, 0xff, 0x03, 0x10, 0x00,
|
|
||||||
/*
|
|
||||||
* [MS-RDPBCGR] LICENSE_ERROR_MESSAGE
|
|
||||||
* dwErrorCode (4) = 0x00000007 (STATUS_VALID_CLIENT)
|
|
||||||
* dwStateTransition (4) = 0x00000002 (ST_NO_TRANSITION)
|
|
||||||
* bbErrorInfo = <LICENSE_BINARY_BLOB>
|
|
||||||
*/
|
|
||||||
0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
||||||
/*
|
|
||||||
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
|
|
||||||
* wBlobType (2) = 0x99f3 <ignored by client> (should be 0x0004 BB_ERROR_BLOB)
|
|
||||||
* wBlobLen (2) = 0x0000 (0)
|
|
||||||
*/
|
|
||||||
0xf3, 0x99, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
static const tui8 g_fips_reverse_table[256] =
|
static const tui8 g_fips_reverse_table[256] =
|
||||||
{
|
{
|
||||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||||
@ -1012,6 +811,25 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we require credentials, don't continue if they're not provided
|
||||||
|
if (self->rdp_layer->client_info.require_credentials)
|
||||||
|
{
|
||||||
|
if ((flags & RDP_LOGON_AUTO) == 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "Server is configured to require that the "
|
||||||
|
"client enable auto logon with credentials, but the client did "
|
||||||
|
"not request auto logon.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (len_user == 0 || len_password == 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "Server is configured to require that the "
|
||||||
|
"client enable auto logon with credentials, but the client did "
|
||||||
|
"not supply both a username and password.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & RDP_LOGON_AUTO)
|
if (flags & RDP_LOGON_AUTO)
|
||||||
{
|
{
|
||||||
if (ts_info_utf16_in(s, len_password, self->rdp_layer->client_info.password, sizeof(self->rdp_layer->client_info.password)) != 0)
|
if (ts_info_utf16_in(s, len_password, self->rdp_layer->client_info.password, sizeof(self->rdp_layer->client_info.password)) != 0)
|
||||||
@ -1033,18 +851,12 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Skip the password
|
||||||
if (!s_check_rem_and_log(s, len_password + 2, "Parsing [MS-RDPBCGR] TS_INFO_PACKET Password"))
|
if (!s_check_rem_and_log(s, len_password + 2, "Parsing [MS-RDPBCGR] TS_INFO_PACKET Password"))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
in_uint8s(s, len_password + 2);
|
in_uint8s(s, len_password + 2);
|
||||||
if (self->rdp_layer->client_info.require_credentials)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "Server is configured to require that the "
|
|
||||||
"client enable auto logon with credentials, but the client did "
|
|
||||||
"not request auto logon.");
|
|
||||||
return 1; /* credentials on cmd line is mandatory */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (self->rdp_layer->client_info.domain_user_separator[0] != '\0'
|
if (self->rdp_layer->client_info.domain_user_separator[0] != '\0'
|
||||||
&& self->rdp_layer->client_info.domain[0] != '\0')
|
&& self->rdp_layer->client_info.domain[0] != '\0')
|
||||||
@ -1159,43 +971,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* returns error */
|
|
||||||
static int
|
|
||||||
xrdp_sec_send_lic_initial(struct xrdp_sec *self)
|
|
||||||
{
|
|
||||||
struct stream *s;
|
|
||||||
|
|
||||||
|
|
||||||
make_stream(s);
|
|
||||||
init_stream(s, 8192);
|
|
||||||
|
|
||||||
if (xrdp_mcs_init(self->mcs_layer, s) != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_send_lic_initial: xrdp_mcs_init failed");
|
|
||||||
free_stream(s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_uint8a(s, g_lic1, sizeof(g_lic1));
|
|
||||||
s_mark_end(s);
|
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPELE] SERVER_LICENSE_REQUEST");
|
|
||||||
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] SERVER_LICENSE_REQUEST failed");
|
|
||||||
free_stream(s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_stream(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* Send a [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT
|
* Send a [MS-RDPBCGR] Server License Error PDU (2.2.1.12) with
|
||||||
* See also: [MS-RDPELE] 1.3.3 Licensing PDU Flows
|
* STATUS_VALID_CLIENT
|
||||||
*/
|
*/
|
||||||
/* returns error */
|
/* returns error */
|
||||||
static int
|
static int
|
||||||
@ -1213,45 +992,34 @@ xrdp_sec_send_lic_response(struct xrdp_sec *self)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_uint8a(s, g_lic2, sizeof(g_lic2));
|
/* [MS-RDPBCGR] TS_SECURITY_HEADER */
|
||||||
|
/* A careful reading of [MS-RDPBCGR] 2.2.1.12 shows that a securityHeader
|
||||||
|
* MUST be included, and provided the flag fields of the header does
|
||||||
|
* not contain SEC_ENCRYPT, it is always possible to send a basic
|
||||||
|
* security header */
|
||||||
|
out_uint16_le(s, SEC_LICENSE_PKT | SEC_LICENSE_ENCRYPT_CS); /* flags */
|
||||||
|
out_uint16_le(s, 0); /* flagsHi */
|
||||||
|
|
||||||
|
/* [MS-RDPBCGR] LICENSE_VALID_CLIENT_DATA */
|
||||||
|
/* preamble (LICENSE_PREAMBLE) */
|
||||||
|
out_uint8(s, ERROR_ALERT);
|
||||||
|
out_uint8(s, PREAMBLE_VERSION_3_0);
|
||||||
|
out_uint16_le(s, 16); /* Message size, including pre-amble */
|
||||||
|
|
||||||
|
/* validClientMessage */
|
||||||
|
/* From [MS-RDPBCGR] 2.2.12.1, dwStateTransition must be ST_NO_TRANSITION,
|
||||||
|
* and the bbErrorInfo field must contain an empty blob of type
|
||||||
|
* BB_ERROR_BLOB */
|
||||||
|
out_uint32_le(s, STATUS_VALID_CLIENT); /* dwErrorCode */
|
||||||
|
out_uint32_le(s, ST_NO_TRANSITION); /* dwStateTransition */
|
||||||
|
out_uint16_le(s, BB_ERROR_BLOB); /* wBlobType */
|
||||||
|
out_uint16_le(s, 0); /* wBlobLen */
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT");
|
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPBCGR] Server License Error PDU with STATUS_VALID_CLIENT");
|
||||||
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
|
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT failed");
|
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPBCGR] Server License Error PDU with STATUS_VALID_CLIENT failed");
|
||||||
free_stream(s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_stream(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* returns error */
|
|
||||||
static int
|
|
||||||
xrdp_sec_send_media_lic_response(struct xrdp_sec *self)
|
|
||||||
{
|
|
||||||
struct stream *s;
|
|
||||||
|
|
||||||
make_stream(s);
|
|
||||||
init_stream(s, 8192);
|
|
||||||
|
|
||||||
if (xrdp_mcs_init(self->mcs_layer, s) != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_send_media_lic_response: xrdp_mcs_init failed");
|
|
||||||
free_stream(s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_uint8a(s, g_lic3, sizeof(g_lic3));
|
|
||||||
s_mark_end(s);
|
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT");
|
|
||||||
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT failed");
|
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1620,7 +1388,7 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & SEC_CLIENT_RANDOM) /* 0x01 TS_SECURITY_PACKET */
|
if (flags & SEC_EXCHANGE_PKT) /* 0x01 TS_SECURITY_PACKET */
|
||||||
{
|
{
|
||||||
if (!s_check_rem_and_log(s, 4, "Parsing [MS-RDPBCGR] TS_SECURITY_PACKET"))
|
if (!s_check_rem_and_log(s, 4, "Parsing [MS-RDPBCGR] TS_SECURITY_PACKET"))
|
||||||
{
|
{
|
||||||
@ -1659,7 +1427,7 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & SEC_LOGON_INFO) /* 0x40 SEC_INFO_PKT */
|
if (flags & SEC_INFO_PKT)
|
||||||
{
|
{
|
||||||
if (xrdp_sec_process_logon_info(self, s) != 0)
|
if (xrdp_sec_process_logon_info(self, s) != 0)
|
||||||
{
|
{
|
||||||
@ -1667,31 +1435,6 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->rdp_layer->client_info.is_mce)
|
|
||||||
{
|
|
||||||
if (xrdp_sec_send_media_lic_response(self) != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_media_lic_response failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_sec_recv: out 'send demand active'");
|
|
||||||
return -1; /* special error that means send demand active */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xrdp_sec_send_lic_initial(self) != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_lic_initial failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*chan = 1; /* just set a non existing channel and exit */
|
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_sec_recv: out channel 1 (non-existing channel)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & SEC_LICENCE_NEG) /* 0x80 SEC_LICENSE_PKT */
|
|
||||||
{
|
|
||||||
if (xrdp_sec_send_lic_response(self) != 0)
|
if (xrdp_sec_send_lic_response(self) != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_lic_response failed");
|
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_lic_response failed");
|
||||||
@ -2146,6 +1889,12 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s)
|
|||||||
LOG(LOG_LEVEL_WARNING,
|
LOG(LOG_LEVEL_WARNING,
|
||||||
"client requested gfx protocol with insufficient color depth");
|
"client requested gfx protocol with insufficient color depth");
|
||||||
}
|
}
|
||||||
|
else if (client_info->max_bpp > 0 && client_info->max_bpp < 32)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Client requested gfx protocol "
|
||||||
|
"but the server configuration is limited to %d bpp.",
|
||||||
|
client_info->max_bpp);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_INFO, "client supports gfx protocol");
|
LOG(LOG_LEVEL_INFO, "client supports gfx protocol");
|
||||||
|
10
mc/mc.h
10
mc/mc.h
@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
struct source_info;
|
struct source_info;
|
||||||
|
|
||||||
|
/* Defined in xrdp_client_info.h */
|
||||||
|
struct monitor_info;
|
||||||
|
|
||||||
struct mod
|
struct mod
|
||||||
{
|
{
|
||||||
int size; /* size of this struct */
|
int size; /* size of this struct */
|
||||||
@ -81,7 +84,10 @@ struct mod
|
|||||||
int box_left, int box_top,
|
int box_left, int box_top,
|
||||||
int box_right, int box_bottom,
|
int box_right, int box_bottom,
|
||||||
int x, int y, char *data, int data_len);
|
int x, int y, char *data, int data_len);
|
||||||
int (*server_reset)(struct mod *v, int width, int height, int bpp);
|
int (*client_monitor_resize)(struct mod *v, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors);
|
||||||
|
int (*server_monitor_resize_done)(struct mod *v);
|
||||||
int (*server_get_channel_count)(struct mod *v);
|
int (*server_get_channel_count)(struct mod *v);
|
||||||
int (*server_query_channel)(struct mod *v, int index,
|
int (*server_query_channel)(struct mod *v, int index,
|
||||||
char *channel_name,
|
char *channel_name,
|
||||||
@ -92,7 +98,7 @@ struct mod
|
|||||||
int total_data_len, int flags);
|
int total_data_len, int flags);
|
||||||
int (*server_bell_trigger)(struct mod *v);
|
int (*server_bell_trigger)(struct mod *v);
|
||||||
int (*server_chansrv_in_use)(struct mod *v);
|
int (*server_chansrv_in_use)(struct mod *v);
|
||||||
tintptr server_dumby[100 - 27]; /* align, 100 minus the number of server
|
tintptr server_dumby[100 - 28]; /* align, 100 minus the number of server
|
||||||
functions above */
|
functions above */
|
||||||
/* common */
|
/* common */
|
||||||
tintptr handle; /* pointer to self as long */
|
tintptr handle; /* pointer to self as long */
|
||||||
|
@ -877,8 +877,12 @@ lxrdp_server_version_message(struct mod *mod)
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
static int
|
static int
|
||||||
lxrdp_server_monitor_resize(struct mod *mod, int width, int height)
|
lxrdp_server_monitor_resize(struct mod *mod, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress)
|
||||||
{
|
{
|
||||||
|
*in_progress = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,10 @@ struct mod
|
|||||||
int (*mod_suppress_output)(struct mod *mod, int suppress,
|
int (*mod_suppress_output)(struct mod *mod, int suppress,
|
||||||
int left, int top, int right, int bottom);
|
int left, int top, int right, int bottom);
|
||||||
int (*mod_server_monitor_resize)(struct mod *mod,
|
int (*mod_server_monitor_resize)(struct mod *mod,
|
||||||
int width, int height);
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress);
|
||||||
int (*mod_server_monitor_full_invalidate)(struct mod *mod,
|
int (*mod_server_monitor_full_invalidate)(struct mod *mod,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
int (*mod_server_version_message)(struct mod *mod);
|
int (*mod_server_version_message)(struct mod *mod);
|
||||||
@ -126,7 +129,10 @@ struct mod
|
|||||||
int box_left, int box_top,
|
int box_left, int box_top,
|
||||||
int box_right, int box_bottom,
|
int box_right, int box_bottom,
|
||||||
int x, int y, char *data, int data_len);
|
int x, int y, char *data, int data_len);
|
||||||
int (*server_reset)(struct mod *v, int width, int height, int bpp);
|
int (*client_monitor_resize)(struct mod *v, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors);
|
||||||
|
int (*server_monitor_resize_done)(struct mod *v);
|
||||||
int (*server_get_channel_count)(struct mod *v);
|
int (*server_get_channel_count)(struct mod *v);
|
||||||
int (*server_query_channel)(struct mod *v, int index,
|
int (*server_query_channel)(struct mod *v, int index,
|
||||||
char *channel_name,
|
char *channel_name,
|
||||||
@ -191,7 +197,7 @@ struct mod
|
|||||||
int flags, int frame_id);
|
int flags, int frame_id);
|
||||||
int (*server_session_info)(struct mod *v, const char *data,
|
int (*server_session_info)(struct mod *v, const char *data,
|
||||||
int data_bytes);
|
int data_bytes);
|
||||||
tintptr server_dumby[100 - 46]; /* align, 100 minus the number of server
|
tintptr server_dumby[100 - 47]; /* align, 100 minus the number of server
|
||||||
functions above */
|
functions above */
|
||||||
/* common */
|
/* common */
|
||||||
tintptr handle; /* pointer to self as long */
|
tintptr handle; /* pointer to self as long */
|
||||||
|
@ -95,7 +95,8 @@ in
|
|||||||
libfdk-aac-dev \
|
libfdk-aac-dev \
|
||||||
libimlib2-dev \
|
libimlib2-dev \
|
||||||
libopus-dev \
|
libopus-dev \
|
||||||
libpixman-1-dev"
|
libpixman-1-dev \
|
||||||
|
libx264-dev"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "unsupported feature set: $FEATURE_SET"
|
echo "unsupported feature set: $FEATURE_SET"
|
||||||
|
65
scripts/make_release_tarball.sh
Executable file
65
scripts/make_release_tarball.sh
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Script to generate release tarball
|
||||||
|
#
|
||||||
|
# This script will generate release tarball. If the repository HEAD is not
|
||||||
|
# tagged, the script will be aborted. Target GitHub repository, branch can be
|
||||||
|
# customized by GH_* envirnment variable.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# Just execute the script. This script is intended to be run by maintainers
|
||||||
|
# so build dependencies are not taken care of.
|
||||||
|
#
|
||||||
|
# $ ./scripts/make_release_tarball.sh
|
||||||
|
# (snip)
|
||||||
|
# ===============================================
|
||||||
|
# Release tarball has been generated at:
|
||||||
|
# /tmp/tmp.q8kme7m7/xrdp-0.9.22.1.tar.gz
|
||||||
|
#
|
||||||
|
# CHECKSUM:
|
||||||
|
# 3ca220d6941ca6dab6a8bd1b50fcffffcf386ce01fbbc350099fdc83684380e0 xrdp-0.9.22.1.tar.gz
|
||||||
|
#
|
||||||
|
# Copy tarball to /home/meta/github/metalefty/xrdp? [y/N] y
|
||||||
|
#
|
||||||
|
# If the script is executed with BATCH=yes, the full path of the release
|
||||||
|
# tarball will be printed on the last line. Clip it using tail command.
|
||||||
|
#
|
||||||
|
# $ BATCH=yes ./scripts/make_release_tarball.sh | tail -n1
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
: ${GH_ACCOUNT:=neutrinolabs}
|
||||||
|
: ${GH_PROJECT:=xrdp}
|
||||||
|
: ${GH_BRANCH:=v0.10}
|
||||||
|
: ${BATCH:=""}
|
||||||
|
|
||||||
|
WRKDIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# clean checkout
|
||||||
|
git clone --recursive --branch "${GH_BRANCH}" "https://github.com/${GH_ACCOUNT}/${GH_PROJECT}.git" "${WRKDIR}"
|
||||||
|
|
||||||
|
cd "${WRKDIR}"
|
||||||
|
git diff --no-ext-diff --quiet --exit-code # check if there's no changes on working tree
|
||||||
|
RELVER=$(git describe --tags --exact-match HEAD) # check if working HEAD refs a release tag
|
||||||
|
./bootstrap
|
||||||
|
./configure
|
||||||
|
make distcheck
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo ===============================================
|
||||||
|
echo Release tarball has been generated at:
|
||||||
|
echo ${WRKDIR}/xrdp-${RELVER#v}.tar.gz
|
||||||
|
echo
|
||||||
|
echo CHECKSUM:
|
||||||
|
sha256sum xrdp-${RELVER#v}.tar.gz
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ -z "${BATCH}" ]; then
|
||||||
|
echo -n "Copy tarball to ${OLDPWD}? [y/N] "
|
||||||
|
read -t 60 copy_tarball
|
||||||
|
case "${copy_tarball}" in
|
||||||
|
[Yy]*) cp -i xrdp-${RELVER#v}.tar.gz "${OLDPWD}"; exit ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo ${WRKDIR}/xrdp-${RELVER#v}.tar.gz
|
||||||
|
fi
|
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
# Script to run astyle on the code
|
# Script to run astyle on the code
|
||||||
#
|
#
|
||||||
# Usage: /path/to/run_astyle.sh
|
# Usage: /path/to/run_astyle.sh [ -v ASTYLE_VER]
|
||||||
#
|
#
|
||||||
|
# - If -v ASTYLE_VER is specified, that version of astyle is run from
|
||||||
|
# ~/astyle.local (whether or not it's there!). Use install_astyle.sh
|
||||||
|
# to install a new version.
|
||||||
|
|
||||||
# Note: the script must be run from the root directory of the xrdp repository
|
# Note: the script must be run from the root directory of the xrdp repository
|
||||||
|
|
||||||
INSTALL_ROOT=~/astyle.local
|
INSTALL_ROOT=~/astyle.local
|
||||||
ASTYLE_FROM_XRDP=$INSTALL_ROOT/3.4.12/usr/bin/astyle
|
|
||||||
MIN_ASTYLE_VER="3.1"
|
MIN_ASTYLE_VER="3.1"
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
@ -15,53 +18,66 @@ MIN_ASTYLE_VER="3.1"
|
|||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
echo "** Usage: $0"
|
echo "** Usage: $0 [ -v version]"
|
||||||
echo " e.g. $0"
|
echo " e.g. $0 -v 3.4.12"
|
||||||
} >&2
|
} >&2
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# M A I N
|
# M A I N
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
# Figure out ASTYLE setting, if any. Currently '-v' must be the first
|
||||||
|
# argument on the command line.
|
||||||
|
case "$1" in
|
||||||
|
-v) # Version is separate parameter
|
||||||
|
if [ $# -ge 2 ]; then
|
||||||
|
ASTYLE="$INSTALL_ROOT/$2/usr/bin/astyle"
|
||||||
|
shift 2
|
||||||
|
else
|
||||||
|
echo "** ignoring '-v' with no arg" >&2
|
||||||
|
shift 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-v*) # Version is in same parameter
|
||||||
|
# ${parameter#word} is not supported by classic Bourne shell,
|
||||||
|
# but it is on bash, dash, etc. If it doesn't work on your shell,
|
||||||
|
# don't use this form!
|
||||||
|
ASTYLE="$INSTALL_ROOT/${1#-v}/usr/bin/astyle"
|
||||||
|
shift 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "$ASTYLE" ]; then
|
||||||
|
ASTYLE=astyle
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $# -ne 0 ]; then
|
if [ $# -ne 0 ]; then
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# check if the built-in astyle meets the minimum requrements
|
|
||||||
ASTYLE_FROM_OS_VER_OUTPUT=`astyle --version | grep "Artistic Style Version" | cut -d' ' -f4`
|
|
||||||
|
|
||||||
ASTYLE=""
|
# check if the selected astyle meets the minimum requrements
|
||||||
ERROR_MESSAGE=""
|
ASTYLE_VER_OUTPUT=`$ASTYLE --version 2>/dev/null | grep "Artistic Style Version" | cut -d' ' -f4`
|
||||||
if [ ! -z "$ASTYLE_FROM_OS_VER_OUTPUT" ]; then
|
|
||||||
# astyle is installed, so check if it's version meets the minimum requirements
|
if [ ! -z "$ASTYLE_VER_OUTPUT" ]; then
|
||||||
LOWEST_VERSION=`echo -e "$MIN_ASTYLE_VER\n$ASTYLE_FROM_OS_VER_OUTPUT" | sort -V | head -n1`
|
# Check the version meets the minimum requirements
|
||||||
if [ "$MIN_ASTYLE_VER" = "$LOWEST_VERSION" ]; then
|
LOWEST_VERSION=`{ echo "$MIN_ASTYLE_VER" ; echo "$ASTYLE_VER_OUTPUT"; } | sort -V | head -n1`
|
||||||
ASTYLE=astyle
|
if [ "$MIN_ASTYLE_VER" != "$LOWEST_VERSION" ]; then
|
||||||
else
|
|
||||||
ERROR_MESSAGE="The version of astyle installed does not meet the minimum version requirement: >= $MIN_ASTYLE_VER "
|
ERROR_MESSAGE="The version of astyle installed does not meet the minimum version requirement: >= $MIN_ASTYLE_VER "
|
||||||
fi
|
fi
|
||||||
else
|
elif [ "$ASTYLE" = astyle ]; then
|
||||||
ERROR_MESSAGE="astyle is not installed on the system path"
|
ERROR_MESSAGE="astyle is not installed on the system path"
|
||||||
fi
|
else
|
||||||
|
ERROR_MESSAGE="Can't find $ASTYLE"
|
||||||
if [ -z "$ASTYLE" ]; then
|
|
||||||
# astyle from the os is invlid, fallback to the xrdp version if it is installed
|
|
||||||
if [ -x "$ASTYLE_FROM_XRDP" ]; then
|
|
||||||
ASTYLE="$ASTYLE_FROM_XRDP"
|
|
||||||
ERROR_MESSAGE=""
|
|
||||||
else
|
|
||||||
ERROR_MESSAGE="${ERROR_MESSAGE}\nastyle $MIN_ASTYLE_VER is not installed at the expected path: $ASTYLE_FROM_XRDP"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -z "$ERROR_MESSAGE" ]; then
|
if [ ! -z "$ERROR_MESSAGE" ]; then
|
||||||
echo "$ERROR_MESSAGE"
|
echo "$ERROR_MESSAGE" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "astyle_config.as" ]; then
|
if [ ! -f "astyle_config.as" ]; then
|
||||||
echo "$0 must be run from the root xrdp repository directory which "
|
echo "$0 must be run from the root xrdp repository directory which " >&2
|
||||||
echo "contains the 'astyle_config.as' file."
|
echo "contains the 'astyle_config.as' file." >&2
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -72,3 +88,5 @@ ASTYLE_FLAGS="--options=astyle_config.as --exclude=third_party ./\*.c ./\*.h"
|
|||||||
echo "Command: $ASTYLE $ASTYLE_FLAGS"
|
echo "Command: $ASTYLE $ASTYLE_FLAGS"
|
||||||
"$ASTYLE" $ASTYLE_FLAGS
|
"$ASTYLE" $ASTYLE_FLAGS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit $?
|
||||||
|
5
scripts/update_news.sh
Executable file
5
scripts/update_news.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
curl -s -H 'Cache-Control: no-cache' \
|
||||||
|
https://raw.githubusercontent.com/wiki/neutrinolabs/xrdp/NEWS-v0.10.md > \
|
||||||
|
$(git rev-parse --show-superproject-working-tree --show-toplevel | head -1)/NEWS.md
|
@ -27,6 +27,7 @@ xrdp_sesman_SOURCES = \
|
|||||||
scp_process.h \
|
scp_process.h \
|
||||||
sesman.c \
|
sesman.c \
|
||||||
sesman.h \
|
sesman.h \
|
||||||
|
sesman.ini.in \
|
||||||
sesexec_control.c \
|
sesexec_control.c \
|
||||||
sesexec_control.h \
|
sesexec_control.h \
|
||||||
session_list.c \
|
session_list.c \
|
||||||
@ -52,7 +53,7 @@ SUFFIXES = .in
|
|||||||
.in:
|
.in:
|
||||||
$(subst_verbose)$(SUBST_VARS) $< > $@
|
$(subst_verbose)$(SUBST_VARS) $< > $@
|
||||||
|
|
||||||
dist_sesmansysconf_DATA = \
|
nodist_sesmansysconf_DATA = \
|
||||||
sesman.ini
|
sesman.ini
|
||||||
|
|
||||||
dist_sesmansysconf_SCRIPTS = \
|
dist_sesmansysconf_SCRIPTS = \
|
||||||
@ -64,3 +65,5 @@ SUBDIRS = \
|
|||||||
sesexec \
|
sesexec \
|
||||||
tools \
|
tools \
|
||||||
chansrv
|
chansrv
|
||||||
|
|
||||||
|
CLEANFILES = $(nodist_sesmansysconf_DATA)
|
||||||
|
@ -202,7 +202,7 @@ struct state_lookup
|
|||||||
{
|
{
|
||||||
fuse_req_t req; /* Original FUSE request from lookup */
|
fuse_req_t req; /* Original FUSE request from lookup */
|
||||||
fuse_ino_t pinum; /* inum of parent directory */
|
fuse_ino_t pinum; /* inum of parent directory */
|
||||||
char name[XFS_MAXFILENAMELEN];
|
char name[XFS_MAXFILENAMELEN + 1];
|
||||||
/* Name to look up */
|
/* Name to look up */
|
||||||
fuse_ino_t existing_inum;
|
fuse_ino_t existing_inum;
|
||||||
/* inum of an existing entry */
|
/* inum of an existing entry */
|
||||||
@ -241,7 +241,7 @@ struct state_create
|
|||||||
fuse_req_t req; /* Original FUSE request from lookup */
|
fuse_req_t req; /* Original FUSE request from lookup */
|
||||||
struct fuse_file_info fi; /* File info struct passed to open */
|
struct fuse_file_info fi; /* File info struct passed to open */
|
||||||
fuse_ino_t pinum; /* inum of parent directory */
|
fuse_ino_t pinum; /* inum of parent directory */
|
||||||
char name[XFS_MAXFILENAMELEN];
|
char name[XFS_MAXFILENAMELEN + 1];
|
||||||
/* Name of file in parent directory */
|
/* Name of file in parent directory */
|
||||||
mode_t mode; /* Mode of file to create */
|
mode_t mode; /* Mode of file to create */
|
||||||
};
|
};
|
||||||
@ -280,7 +280,7 @@ struct state_rename
|
|||||||
fuse_req_t req; /* Original FUSE request from lookup */
|
fuse_req_t req; /* Original FUSE request from lookup */
|
||||||
fuse_ino_t pinum; /* inum of parent of file */
|
fuse_ino_t pinum; /* inum of parent of file */
|
||||||
fuse_ino_t new_pinum; /* inum of new parent of file */
|
fuse_ino_t new_pinum; /* inum of new parent of file */
|
||||||
char name[XFS_MAXFILENAMELEN];
|
char name[XFS_MAXFILENAMELEN + 1];
|
||||||
/* New name of file in new parent dir */
|
/* New name of file in new parent dir */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -540,10 +540,25 @@ xfuse_init(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_snprintf(g_fuse_clipboard_path, 255, "%s/.clipboard", g_fuse_root_path);
|
g_snprintf(g_fuse_clipboard_path, sizeof(g_fuse_clipboard_path),
|
||||||
|
"%s/.clipboard", g_fuse_root_path);
|
||||||
|
|
||||||
|
/* if FUSE mount point does not exist, create it */
|
||||||
|
if (!g_directory_exist(g_fuse_root_path))
|
||||||
|
{
|
||||||
|
(void)g_create_path(g_fuse_root_path);
|
||||||
|
if (!g_create_dir(g_fuse_root_path))
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "mkdir %s failed (%s)",
|
||||||
|
g_fuse_root_path, g_get_strerror());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the characteristics of the parent directory of the FUSE mount
|
/* Get the characteristics of the parent directory of the FUSE mount
|
||||||
* point. Used by xfuse_path_in_xfuse_fs() */
|
* point. Used by xfuse_path_in_xfuse_fs() */
|
||||||
|
g_fuse_root_parent_dev = -1;
|
||||||
|
g_fuse_root_parent_ino = -1;
|
||||||
p = (char *)g_strrchr(g_fuse_root_path, '/');
|
p = (char *)g_strrchr(g_fuse_root_path, '/');
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
{
|
{
|
||||||
@ -554,11 +569,6 @@ xfuse_init(void)
|
|||||||
g_fuse_root_parent_ino = g_file_get_inode_num(g_fuse_root_path);
|
g_fuse_root_parent_ino = g_file_get_inode_num(g_fuse_root_path);
|
||||||
*p = '/';
|
*p = '/';
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
g_fuse_root_parent_dev = -1;
|
|
||||||
g_fuse_root_parent_ino = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_fuse_root_parent_dev == -1 || g_fuse_root_parent_ino == -1)
|
if (g_fuse_root_parent_dev == -1 || g_fuse_root_parent_ino == -1)
|
||||||
{
|
{
|
||||||
@ -568,18 +578,6 @@ xfuse_init(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if FUSE mount point does not exist, create it */
|
|
||||||
if (!g_directory_exist(g_fuse_root_path))
|
|
||||||
{
|
|
||||||
(void)g_create_path(g_fuse_root_path);
|
|
||||||
if (!g_create_dir(g_fuse_root_path))
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "mkdir %s failed. If %s is already mounted, you must "
|
|
||||||
"first unmount it", g_fuse_root_path, g_fuse_root_path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* setup xrdp file system */
|
/* setup xrdp file system */
|
||||||
if (xfuse_init_xrdp_fs())
|
if (xfuse_init_xrdp_fs())
|
||||||
{
|
{
|
||||||
@ -906,14 +904,16 @@ static int xfuse_init_lib(struct fuse_args *args)
|
|||||||
{
|
{
|
||||||
if (fuse_parse_cmdline(args, &g_mount_point, 0, 0) < 0)
|
if (fuse_parse_cmdline(args, &g_mount_point, 0, 0) < 0)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_parse_cmdline() failed");
|
LOG(LOG_LEVEL_ERROR, "fuse_parse_cmdline() failed");
|
||||||
fuse_opt_free_args(args);
|
fuse_opt_free_args(args);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((g_ch = fuse_mount(g_mount_point, args)) == 0)
|
if ((g_ch = fuse_mount(g_mount_point, args)) == 0)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_mount() failed");
|
LOG(LOG_LEVEL_ERROR, "FUSE mount on %s failed."
|
||||||
|
" If %s is already mounted, you must first unmount it",
|
||||||
|
g_mount_point, g_mount_point);
|
||||||
fuse_opt_free_args(args);
|
fuse_opt_free_args(args);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -921,7 +921,7 @@ static int xfuse_init_lib(struct fuse_args *args)
|
|||||||
g_se = fuse_lowlevel_new(args, &g_xfuse_ops, sizeof(g_xfuse_ops), 0);
|
g_se = fuse_lowlevel_new(args, &g_xfuse_ops, sizeof(g_xfuse_ops), 0);
|
||||||
if (g_se == 0)
|
if (g_se == 0)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_lowlevel_new() failed");
|
LOG(LOG_LEVEL_ERROR, "fuse_lowlevel_new() failed");
|
||||||
fuse_unmount(g_mount_point, g_ch);
|
fuse_unmount(g_mount_point, g_ch);
|
||||||
g_ch = 0;
|
g_ch = 0;
|
||||||
fuse_opt_free_args(args);
|
fuse_opt_free_args(args);
|
||||||
|
@ -264,6 +264,8 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
|||||||
struct xfs_fs *xfs = g_new0(struct xfs_fs, 1);
|
struct xfs_fs *xfs = g_new0(struct xfs_fs, 1);
|
||||||
XFS_INODE_ALL *xino1 = NULL;
|
XFS_INODE_ALL *xino1 = NULL;
|
||||||
XFS_INODE_ALL *xino2 = NULL;
|
XFS_INODE_ALL *xino2 = NULL;
|
||||||
|
char *xino1_name = NULL;
|
||||||
|
char *xino2_name = NULL;
|
||||||
|
|
||||||
if (xfs != NULL)
|
if (xfs != NULL)
|
||||||
{
|
{
|
||||||
@ -279,10 +281,14 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
|||||||
if (!grow_xfs(xfs, INODE_TABLE_ALLOCATION_INITIAL) ||
|
if (!grow_xfs(xfs, INODE_TABLE_ALLOCATION_INITIAL) ||
|
||||||
xfs->inode_table == NULL ||
|
xfs->inode_table == NULL ||
|
||||||
(xino1 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
|
(xino1 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
|
||||||
(xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL)
|
(xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
|
||||||
|
(xino1_name = strdup(".")) == NULL ||
|
||||||
|
(xino2_name = strdup(".delete-pending")) == NULL)
|
||||||
{
|
{
|
||||||
free(xino1);
|
free(xino1);
|
||||||
free(xino2);
|
free(xino2);
|
||||||
|
free(xino1_name);
|
||||||
|
free(xino2_name);
|
||||||
xfs_delete_xfs_fs(xfs);
|
xfs_delete_xfs_fs(xfs);
|
||||||
xfs = NULL;
|
xfs = NULL;
|
||||||
}
|
}
|
||||||
@ -306,7 +312,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
|||||||
xino1->pub.atime = time(0);
|
xino1->pub.atime = time(0);
|
||||||
xino1->pub.mtime = xino1->pub.atime;
|
xino1->pub.mtime = xino1->pub.atime;
|
||||||
xino1->pub.ctime = xino1->pub.atime;
|
xino1->pub.ctime = xino1->pub.atime;
|
||||||
strcpy(xino1->pub.name, ".");
|
xino1->pub.name = xino1_name;
|
||||||
xino1->pub.generation = xfs->generation;
|
xino1->pub.generation = xfs->generation;
|
||||||
xino1->pub.is_redirected = 0;
|
xino1->pub.is_redirected = 0;
|
||||||
xino1->pub.device_id = 0;
|
xino1->pub.device_id = 0;
|
||||||
@ -328,7 +334,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
|||||||
xino2->pub.atime = time(0);
|
xino2->pub.atime = time(0);
|
||||||
xino2->pub.mtime = xino2->pub.atime;
|
xino2->pub.mtime = xino2->pub.atime;
|
||||||
xino2->pub.ctime = xino2->pub.atime;
|
xino2->pub.ctime = xino2->pub.atime;
|
||||||
strcpy(xino2->pub.name, ".delete-pending");
|
xino2->pub.name = xino2_name;
|
||||||
xino2->pub.generation = xfs->generation;
|
xino2->pub.generation = xfs->generation;
|
||||||
xino2->pub.is_redirected = 0;
|
xino2->pub.is_redirected = 0;
|
||||||
xino2->pub.device_id = 0;
|
xino2->pub.device_id = 0;
|
||||||
@ -349,6 +355,17 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
|||||||
return xfs;
|
return xfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
static void
|
||||||
|
xfs_free_inode(XFS_INODE_ALL *xino)
|
||||||
|
{
|
||||||
|
if (xino != NULL)
|
||||||
|
{
|
||||||
|
free(xino->pub.name);
|
||||||
|
free(xino);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
void
|
void
|
||||||
xfs_delete_xfs_fs(struct xfs_fs *xfs)
|
xfs_delete_xfs_fs(struct xfs_fs *xfs)
|
||||||
@ -363,7 +380,7 @@ xfs_delete_xfs_fs(struct xfs_fs *xfs)
|
|||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0 ; i < xfs->inode_count; ++i)
|
for (i = 0 ; i < xfs->inode_count; ++i)
|
||||||
{
|
{
|
||||||
free(xfs->inode_table[i]);
|
xfs_free_inode(xfs->inode_table[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(xfs->inode_table);
|
free(xfs->inode_table);
|
||||||
@ -407,9 +424,14 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
|
|||||||
if (xfs->free_count > 0 ||
|
if (xfs->free_count > 0 ||
|
||||||
grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY))
|
grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY))
|
||||||
{
|
{
|
||||||
XFS_INODE_ALL *xino = NULL;
|
XFS_INODE_ALL *xino = g_new0(XFS_INODE_ALL, 1);
|
||||||
|
char *cpyname = strdup(name);
|
||||||
if ((xino = g_new0(XFS_INODE_ALL, 1)) != NULL)
|
if (xino == NULL || cpyname == NULL)
|
||||||
|
{
|
||||||
|
free(xino);
|
||||||
|
free(cpyname);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
fuse_ino_t inum = xfs->free_list[--xfs->free_count];
|
fuse_ino_t inum = xfs->free_list[--xfs->free_count];
|
||||||
if (xfs->inode_table[inum] != NULL)
|
if (xfs->inode_table[inum] != NULL)
|
||||||
@ -433,7 +455,7 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
|
|||||||
xino->pub.atime = time(0);
|
xino->pub.atime = time(0);
|
||||||
xino->pub.mtime = xino->pub.atime;
|
xino->pub.mtime = xino->pub.atime;
|
||||||
xino->pub.ctime = xino->pub.atime;
|
xino->pub.ctime = xino->pub.atime;
|
||||||
strcpy(xino->pub.name, name);
|
xino->pub.name = cpyname;
|
||||||
xino->pub.generation = xfs->generation;
|
xino->pub.generation = xfs->generation;
|
||||||
xino->pub.is_redirected = parent->pub.is_redirected;
|
xino->pub.is_redirected = parent->pub.is_redirected;
|
||||||
xino->pub.device_id = parent->pub.device_id;
|
xino->pub.device_id = parent->pub.device_id;
|
||||||
@ -498,7 +520,7 @@ xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum)
|
|||||||
* so that the caller can distinguish re-uses of the same inum.
|
* so that the caller can distinguish re-uses of the same inum.
|
||||||
*/
|
*/
|
||||||
++xfs->generation;
|
++xfs->generation;
|
||||||
free(xino);
|
xfs_free_inode(xino);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -844,8 +866,15 @@ xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
|
|||||||
XFS_INODE_ALL *xino;
|
XFS_INODE_ALL *xino;
|
||||||
XFS_INODE_ALL *parent;
|
XFS_INODE_ALL *parent;
|
||||||
XFS_INODE *dest;
|
XFS_INODE *dest;
|
||||||
|
char *cpyname;
|
||||||
|
|
||||||
if (xfs_check_move_entry(xfs, inum, new_parent_inum, name))
|
/* Copy the new name. We'll either end up freeing it, or we'll
|
||||||
|
* use it to replace something else (which gets freed instead) */
|
||||||
|
if ((cpyname = strdup(name)) == NULL)
|
||||||
|
{
|
||||||
|
result = ENOMEM;
|
||||||
|
}
|
||||||
|
else if (xfs_check_move_entry(xfs, inum, new_parent_inum, name))
|
||||||
{
|
{
|
||||||
xino = xfs->inode_table[inum];
|
xino = xfs->inode_table[inum];
|
||||||
parent = xfs->inode_table[new_parent_inum];
|
parent = xfs->inode_table[new_parent_inum];
|
||||||
@ -862,19 +891,31 @@ xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
|
|||||||
|
|
||||||
unlink_inode_from_parent(xino);
|
unlink_inode_from_parent(xino);
|
||||||
link_inode_into_directory_node(parent, xino);
|
link_inode_into_directory_node(parent, xino);
|
||||||
strcpy(xino->pub.name, name);
|
|
||||||
|
/* Swap the copy name and the inode name so we end up with the
|
||||||
|
* right name, and the old one gets freed */
|
||||||
|
char *t = xino->pub.name;
|
||||||
|
xino->pub.name = cpyname;
|
||||||
|
cpyname = t;
|
||||||
}
|
}
|
||||||
else if (strcmp(xino->pub.name, name) != 0)
|
else if (strcmp(xino->pub.name, name) != 0)
|
||||||
{
|
{
|
||||||
/* Same directory, but name has changed */
|
/* Same directory, but name has changed */
|
||||||
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
|
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
|
||||||
{
|
{
|
||||||
|
/* Name collision - remove destination entry */
|
||||||
xfs_remove_entry(xfs, dest->inum);
|
xfs_remove_entry(xfs, dest->inum);
|
||||||
}
|
}
|
||||||
strcpy(xino->pub.name, name);
|
|
||||||
|
/* Swap the copy name and the inode name so we end up with the
|
||||||
|
* right name, and the old one gets freed */
|
||||||
|
char *t = xino->pub.name;
|
||||||
|
xino->pub.name = cpyname;
|
||||||
|
cpyname = t;
|
||||||
}
|
}
|
||||||
result = 0;
|
result = 0;
|
||||||
}
|
}
|
||||||
|
free (cpyname);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,11 @@
|
|||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
|
||||||
#define XFS_MAXFILENAMELEN 255
|
/* Maximum length of filename supported (in bytes).
|
||||||
|
* This is a sensible limit to a filename length. It is not used by
|
||||||
|
* this module to allocate long-lived storage, so it can be increased
|
||||||
|
* if necessary */
|
||||||
|
#define XFS_MAXFILENAMELEN 1023
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Incomplete types for the public interface
|
* Incomplete types for the public interface
|
||||||
@ -37,6 +41,9 @@
|
|||||||
struct xfs_fs;
|
struct xfs_fs;
|
||||||
struct xfs_dir_handle;
|
struct xfs_dir_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe an inode in the XFS filesystem
|
||||||
|
*/
|
||||||
typedef struct xfs_inode
|
typedef struct xfs_inode
|
||||||
{
|
{
|
||||||
fuse_ino_t inum; /* File serial number. */
|
fuse_ino_t inum; /* File serial number. */
|
||||||
@ -47,7 +54,7 @@ typedef struct xfs_inode
|
|||||||
time_t atime; /* Time of last access. */
|
time_t atime; /* Time of last access. */
|
||||||
time_t mtime; /* Time of last modification. */
|
time_t mtime; /* Time of last modification. */
|
||||||
time_t ctime; /* Time of last status change. */
|
time_t ctime; /* Time of last status change. */
|
||||||
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
|
char *name; /* Short name (dynamically allocated) */
|
||||||
tui32 generation; /* Changes if inode is reused */
|
tui32 generation; /* Changes if inode is reused */
|
||||||
char is_redirected; /* file is on redirected device */
|
char is_redirected; /* file is on redirected device */
|
||||||
tui32 device_id; /* device ID of redirected device */
|
tui32 device_id; /* device ID of redirected device */
|
||||||
|
@ -181,14 +181,8 @@ x-special/gnome-copied-files
|
|||||||
#include "ms-rdpeclip.h"
|
#include "ms-rdpeclip.h"
|
||||||
#include "xrdp_constants.h"
|
#include "xrdp_constants.h"
|
||||||
|
|
||||||
static char g_bmp_image_header[] =
|
#define BMPFILEHEADER_LEN 14
|
||||||
{
|
#define BMPINFOHEADER_LEN 40
|
||||||
/* this is known to work */
|
|
||||||
//0x42, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
||||||
|
|
||||||
/* THIS IS BEING SENT BY WIN2008 */
|
|
||||||
0x42, 0x4d, 0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int g_cliprdr_chan_id; /* in chansrv.c */
|
extern int g_cliprdr_chan_id; /* in chansrv.c */
|
||||||
|
|
||||||
@ -1135,6 +1129,7 @@ clipboard_process_data_response_for_image(struct stream *s,
|
|||||||
{
|
{
|
||||||
XSelectionRequestEvent *lxev;
|
XSelectionRequestEvent *lxev;
|
||||||
int len;
|
int len;
|
||||||
|
struct stream *bmp_hs;
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: "
|
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: "
|
||||||
"CLIPRDR_DATA_RESPONSE_FOR_IMAGE");
|
"CLIPRDR_DATA_RESPONSE_FOR_IMAGE");
|
||||||
@ -1148,20 +1143,45 @@ clipboard_process_data_response_for_image(struct stream *s,
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(g_clip_c2s.data);
|
g_free(g_clip_c2s.data);
|
||||||
g_clip_c2s.data = (char *) g_malloc(len + 14, 0);
|
g_clip_c2s.data = (char *) g_malloc(len + BMPFILEHEADER_LEN, 0);
|
||||||
if (g_clip_c2s.data == 0)
|
if (g_clip_c2s.data == 0)
|
||||||
{
|
{
|
||||||
g_clip_c2s.total_bytes = 0;
|
g_clip_c2s.total_bytes = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
g_clip_c2s.total_bytes = len;
|
g_clip_c2s.total_bytes = len + BMPFILEHEADER_LEN;
|
||||||
g_clip_c2s.read_bytes_done = g_clip_c2s.total_bytes;
|
g_clip_c2s.read_bytes_done = g_clip_c2s.total_bytes;
|
||||||
g_memcpy(g_clip_c2s.data, g_bmp_image_header, 14);
|
|
||||||
in_uint8a(s, g_clip_c2s.data + 14, len);
|
/*
|
||||||
|
* Assemble bitmap file header
|
||||||
|
* https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
|
||||||
|
*/
|
||||||
|
make_stream(bmp_hs);
|
||||||
|
if (bmp_hs == 0)
|
||||||
|
{
|
||||||
|
g_free(g_clip_c2s.data);
|
||||||
|
g_clip_c2s.total_bytes = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
init_stream(bmp_hs, BMPFILEHEADER_LEN);
|
||||||
|
out_uint8(bmp_hs, 'B');
|
||||||
|
out_uint8(bmp_hs, 'M');
|
||||||
|
out_uint32_le(bmp_hs, g_clip_c2s.total_bytes);
|
||||||
|
out_uint16_le(bmp_hs, 0);
|
||||||
|
out_uint16_le(bmp_hs, 0);
|
||||||
|
out_uint32_le(bmp_hs, BMPFILEHEADER_LEN + BMPINFOHEADER_LEN);
|
||||||
|
|
||||||
|
/* Copy header and data to output stream */
|
||||||
|
g_memcpy(g_clip_c2s.data, bmp_hs->data, BMPFILEHEADER_LEN);
|
||||||
|
in_uint8a(s, g_clip_c2s.data + BMPFILEHEADER_LEN, len);
|
||||||
|
|
||||||
|
free_stream(bmp_hs);
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: calling "
|
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: calling "
|
||||||
"clipboard_provide_selection_c2s");
|
"clipboard_provide_selection_c2s");
|
||||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <config_ac.h>
|
#include <config_ac.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
@ -52,8 +53,8 @@ extern char g_fuse_clipboard_path[];
|
|||||||
|
|
||||||
struct cb_file_info
|
struct cb_file_info
|
||||||
{
|
{
|
||||||
char pathname[256];
|
char *pathname;
|
||||||
char filename[256];
|
char *filename;
|
||||||
int flags;
|
int flags;
|
||||||
int size;
|
int size;
|
||||||
tui64 time;
|
tui64 time;
|
||||||
@ -82,6 +83,103 @@ timeval2wintime(struct timeval *tv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a useable filename from a file specification passed to us
|
||||||
|
*
|
||||||
|
* The passed-in specification may contain instances of RFC3986 encoded
|
||||||
|
* octets '%xx' where 'x' is a hex digit (e.g. %20 == ASCII SPACE). For
|
||||||
|
* UTF-8, there may be many of these (e.g. %E6%97%A5 maps to the U+65E5
|
||||||
|
* Unicode character)
|
||||||
|
*
|
||||||
|
* The result must be free'd by the caller.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
decode_rfc3986(const char *rfc3986, int len)
|
||||||
|
{
|
||||||
|
char *result = (char *)malloc(len + 1);
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
/* Copy the passed-in filename so we can modify it */
|
||||||
|
while (i < len)
|
||||||
|
{
|
||||||
|
/* Check for %xx for a character (e.g. %20 == ASCII 32 == SPACE) */
|
||||||
|
if (rfc3986[i] == '%' && (len - i) > 2 &&
|
||||||
|
isxdigit(rfc3986[i + 1]) && isxdigit(rfc3986[i + 2]))
|
||||||
|
{
|
||||||
|
char jchr[] = { rfc3986[i + 1], rfc3986[i + 2], '\0' };
|
||||||
|
result[j++] = g_htoi(jchr);
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result[j++] = rfc3986[i++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a alloc_cb_file_info struct
|
||||||
|
*
|
||||||
|
* The memory for the struct is allocated in such a way that a single
|
||||||
|
* free() call can be used to de-allocate it
|
||||||
|
*
|
||||||
|
* Filename elements are copied into the struct
|
||||||
|
*/
|
||||||
|
static struct cb_file_info *
|
||||||
|
alloc_cb_file_info(const char *full_name)
|
||||||
|
{
|
||||||
|
struct cb_file_info *result = NULL;
|
||||||
|
|
||||||
|
/* Find the last path separator in the string */
|
||||||
|
const char *psep = strrchr(full_name, '/');
|
||||||
|
|
||||||
|
/* Separate the name into a path and an unqualified name */
|
||||||
|
const char *path_ptr = "/";
|
||||||
|
unsigned int path_len = 1;
|
||||||
|
const char *name_ptr;
|
||||||
|
|
||||||
|
if (psep == NULL)
|
||||||
|
{
|
||||||
|
name_ptr = full_name;
|
||||||
|
}
|
||||||
|
else if (psep == full_name)
|
||||||
|
{
|
||||||
|
name_ptr = full_name + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path_ptr = full_name;
|
||||||
|
path_len = psep - full_name;
|
||||||
|
name_ptr = psep + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a block big enough for the struct, and
|
||||||
|
* for both the strings */
|
||||||
|
unsigned int name_len = strlen(name_ptr);
|
||||||
|
unsigned int alloc_size = sizeof(struct cb_file_info) +
|
||||||
|
(path_len + 1) + (name_len + 1);
|
||||||
|
|
||||||
|
result = (struct cb_file_info *)malloc(alloc_size);
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
/* Get a pointer to the first byte past the struct */
|
||||||
|
result->pathname = (char *)(result + 1);
|
||||||
|
result->filename = result->pathname + path_len + 1;
|
||||||
|
memcpy(result->pathname, path_ptr, path_len);
|
||||||
|
result->pathname[path_len] = '\0';
|
||||||
|
memcpy(result->filename, name_ptr, name_len);
|
||||||
|
result->filename[name_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* See MS-RDPECLIP 3.1.5.4.7
|
* See MS-RDPECLIP 3.1.5.4.7
|
||||||
*
|
*
|
||||||
@ -113,54 +211,13 @@ clipboard_send_filecontents_response_fail(int streamId)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* this will replace %20 or any hex with the space or correct char
|
|
||||||
* returns error */
|
|
||||||
static int
|
|
||||||
clipboard_check_file(char *filename)
|
|
||||||
{
|
|
||||||
char lfilename[256];
|
|
||||||
char jchr[8];
|
|
||||||
int lindex;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
g_memset(lfilename, 0, 256);
|
|
||||||
lindex = 0;
|
|
||||||
index = 0;
|
|
||||||
while (filename[index] != 0)
|
|
||||||
{
|
|
||||||
if (filename[index] == '%')
|
|
||||||
{
|
|
||||||
jchr[0] = filename[index + 1];
|
|
||||||
jchr[1] = filename[index + 2];
|
|
||||||
jchr[2] = 0;
|
|
||||||
index += 3;
|
|
||||||
lfilename[lindex] = g_htoi(jchr);
|
|
||||||
lindex++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lfilename[lindex] = filename[index];
|
|
||||||
lindex++;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "[%s] [%s]", filename, lfilename);
|
|
||||||
g_strcpy(filename, lfilename);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
static int
|
static int
|
||||||
clipboard_get_file(const char *file, int bytes)
|
clipboard_get_file(const char *file, int bytes)
|
||||||
{
|
{
|
||||||
int sindex;
|
char *full_fn;
|
||||||
int pindex;
|
|
||||||
int flags;
|
|
||||||
char full_fn[256]; /* /etc/xrdp/xrdp.ini */
|
|
||||||
char filename[256]; /* xrdp.ini */
|
|
||||||
char pathname[256]; /* /etc/xrdp */
|
|
||||||
struct cb_file_info *cfi;
|
struct cb_file_info *cfi;
|
||||||
|
int result = 1;
|
||||||
|
|
||||||
/* x-special/gnome-copied-files */
|
/* x-special/gnome-copied-files */
|
||||||
if ((g_strncmp(file, "copy", 4) == 0) && (bytes == 4))
|
if ((g_strncmp(file, "copy", 4) == 0) && (bytes == 4))
|
||||||
@ -171,35 +228,23 @@ clipboard_get_file(const char *file, int bytes)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
sindex = 0;
|
|
||||||
flags = CB_FILE_ATTRIBUTE_ARCHIVE;
|
|
||||||
/* text/uri-list */
|
/* text/uri-list */
|
||||||
/* x-special/gnome-copied-files */
|
/* x-special/gnome-copied-files */
|
||||||
if (g_strncmp(file, "file://", 7) == 0)
|
if (bytes > 7 && g_strncmp(file, "file://", 7) == 0)
|
||||||
{
|
{
|
||||||
sindex = 7;
|
full_fn = decode_rfc3986(file + 7, bytes - 7);
|
||||||
}
|
}
|
||||||
pindex = bytes;
|
else
|
||||||
while (pindex > sindex)
|
|
||||||
{
|
{
|
||||||
if (file[pindex] == '/')
|
full_fn = decode_rfc3986(file, bytes);
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pindex--;
|
|
||||||
}
|
}
|
||||||
g_memset(pathname, 0, 256);
|
|
||||||
g_memset(filename, 0, 256);
|
if (full_fn == NULL)
|
||||||
g_memcpy(pathname, file + sindex, pindex - sindex);
|
|
||||||
if (pathname[0] == 0)
|
|
||||||
{
|
{
|
||||||
pathname[0] = '/';
|
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Out of memory");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
g_memcpy(filename, file + pindex + 1, (bytes - 1) - pindex);
|
|
||||||
/* this should replace %20 with space */
|
|
||||||
clipboard_check_file(pathname);
|
|
||||||
clipboard_check_file(filename);
|
|
||||||
g_snprintf(full_fn, 255, "%s/%s", pathname, filename);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before we look at the file, see if it's in the FUSE filesystem. If it is,
|
* Before we look at the file, see if it's in the FUSE filesystem. If it is,
|
||||||
@ -209,68 +254,69 @@ clipboard_get_file(const char *file, int bytes)
|
|||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Can't add client-side file "
|
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Can't add client-side file "
|
||||||
"%s to clipboard", full_fn);
|
"%s to clipboard", full_fn);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
if (g_directory_exist(full_fn))
|
else if (g_directory_exist(full_fn))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: file [%s] is a directory, "
|
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: file [%s] is a directory, "
|
||||||
"not supported", full_fn);
|
"not supported", full_fn);
|
||||||
flags |= CB_FILE_ATTRIBUTE_DIRECTORY;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
if (!g_file_exist(full_fn))
|
else if (!g_file_exist(full_fn))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: file [%s] does not exist",
|
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: file [%s] does not exist",
|
||||||
full_fn);
|
full_fn);
|
||||||
return 1;
|
}
|
||||||
|
else if ((cfi = alloc_cb_file_info(full_fn)) == NULL)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Out of memory");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cfi = (struct cb_file_info *)g_malloc(sizeof(struct cb_file_info), 1);
|
|
||||||
list_add_item(g_files_list, (tintptr)cfi);
|
list_add_item(g_files_list, (tintptr)cfi);
|
||||||
g_strcpy(cfi->filename, filename);
|
|
||||||
g_strcpy(cfi->pathname, pathname);
|
|
||||||
cfi->size = g_file_get_size(full_fn);
|
cfi->size = g_file_get_size(full_fn);
|
||||||
cfi->flags = flags;
|
cfi->flags = CB_FILE_ATTRIBUTE_ARCHIVE;
|
||||||
cfi->time = (g_time1() + CB_EPOCH_DIFF) * 10000000LL;
|
cfi->time = (g_time1() + CB_EPOCH_DIFF) * 10000000LL;
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "ok filename [%s] pathname [%s] size [%d]",
|
LOG_DEVEL(LOG_LEVEL_DEBUG, "ok filename [%s] pathname [%s] size [%d]",
|
||||||
cfi->filename, cfi->pathname, cfi->size);
|
cfi->filename, cfi->pathname, cfi->size);
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
free(full_fn);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
/*
|
||||||
|
* Calls clipboard_get_file() for each filename in a list.
|
||||||
|
*
|
||||||
|
* List items are separated by line terminators. Blank items are ignored */
|
||||||
static int
|
static int
|
||||||
clipboard_get_files(const char *files, int bytes)
|
clipboard_get_files(const char *files, int bytes)
|
||||||
{
|
{
|
||||||
int index;
|
const char *start = files;
|
||||||
int file_index;
|
const char *end = files + bytes;
|
||||||
char file[512];
|
const char *p;
|
||||||
|
|
||||||
file_index = 0;
|
for (p = start ; p < end ; ++p)
|
||||||
for (index = 0; index < bytes; index++)
|
|
||||||
{
|
{
|
||||||
if (files[index] == '\n' || files[index] == '\r')
|
if (*p == '\n' || *p == '\r')
|
||||||
{
|
{
|
||||||
if (file_index > 0)
|
/* Skip zero-length files (which might be caused by
|
||||||
|
* multiple line terminators */
|
||||||
|
if (p > start)
|
||||||
{
|
{
|
||||||
if (clipboard_get_file(file, file_index) == 0)
|
/* Get file. Errors are logged */
|
||||||
{
|
(void)clipboard_get_file(start, p - start);
|
||||||
}
|
|
||||||
file_index = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
/* Move the start of filename pointer to either 'end', or
|
||||||
{
|
* the next character which will either be a filename or
|
||||||
file[file_index] = files[index];
|
* another terminator */
|
||||||
file_index++;
|
start = p + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (file_index > 0)
|
if (end > start)
|
||||||
{
|
{
|
||||||
if (clipboard_get_file(file, file_index) == 0)
|
(void)clipboard_get_file(start, end - start);
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (g_files_list->count < 1)
|
if (g_files_list->count < 1)
|
||||||
{
|
{
|
||||||
@ -492,10 +538,12 @@ clipboard_send_file_data(int streamId, int lindex,
|
|||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, cbRequested + 64);
|
init_stream(s, cbRequested + 64);
|
||||||
size = g_file_read(fd, s->data + 12, cbRequested);
|
size = g_file_read(fd, s->data + 12, cbRequested);
|
||||||
if (size < 1)
|
// If we're at end-of-file, 0 is a valid response
|
||||||
|
if (size < 0)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_send_file_data: read error, want %d got %d",
|
LOG_DEVEL(LOG_LEVEL_ERROR,
|
||||||
cbRequested, size);
|
"clipboard_send_file_data: read error, want %d got [%s]",
|
||||||
|
cbRequested, g_get_strerror());
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
g_file_close(fd);
|
g_file_close(fd);
|
||||||
clipboard_send_filecontents_response_fail(streamId);
|
clipboard_send_filecontents_response_fail(streamId);
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "chansrv.h"
|
#include "chansrv.h"
|
||||||
#include "chansrv_fuse.h"
|
#include "chansrv_fuse.h"
|
||||||
|
#include "chansrv_xfs.h"
|
||||||
#include "devredir.h"
|
#include "devredir.h"
|
||||||
#include "smartcard.h"
|
#include "smartcard.h"
|
||||||
#include "ms-rdpefs.h"
|
#include "ms-rdpefs.h"
|
||||||
@ -1249,7 +1250,13 @@ devredir_proc_query_dir_response(IRP *irp,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Size the filename buffer so it's big enough for
|
||||||
|
// storing the file in our filesystem if we need to.
|
||||||
|
#ifdef XFS_MAXFILENAMELEN
|
||||||
|
char filename[XFS_MAXFILENAMELEN + 1];
|
||||||
|
#else
|
||||||
char filename[256];
|
char filename[256];
|
||||||
|
#endif
|
||||||
tui64 LastAccessTime;
|
tui64 LastAccessTime;
|
||||||
tui64 LastWriteTime;
|
tui64 LastWriteTime;
|
||||||
tui64 EndOfFile;
|
tui64 EndOfFile;
|
||||||
|
@ -102,6 +102,14 @@ process_sys_login_request(struct pre_session_item *psi)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Copy the IP address of the requesting user, anticipating a
|
||||||
|
* successful login. We need this so we can search for a session
|
||||||
|
* with a matching IP address if required.
|
||||||
|
*/
|
||||||
|
g_snprintf(psi->start_ip_addr, sizeof(psi->start_ip_addr),
|
||||||
|
"%s", ip_addr);
|
||||||
|
|
||||||
/* Create a sesexec process to handle the login
|
/* Create a sesexec process to handle the login
|
||||||
*
|
*
|
||||||
* We won't check for the user being valid here, as this might
|
* We won't check for the user being valid here, as this might
|
||||||
@ -323,6 +331,9 @@ process_logout_request(struct pre_session_item *psi)
|
|||||||
static int
|
static int
|
||||||
create_xrdp_socket_path(uid_t uid)
|
create_xrdp_socket_path(uid_t uid)
|
||||||
{
|
{
|
||||||
|
// Owner all permissions, group read+execute
|
||||||
|
#define RWX_PERMS 0x750
|
||||||
|
|
||||||
int rv = 1;
|
int rv = 1;
|
||||||
const char *sockdir_group = g_cfg->sec.session_sockdir_group;
|
const char *sockdir_group = g_cfg->sec.session_sockdir_group;
|
||||||
int gid = 0; // Default if no group specified
|
int gid = 0; // Default if no group specified
|
||||||
@ -330,14 +341,21 @@ create_xrdp_socket_path(uid_t uid)
|
|||||||
char sockdir[XRDP_SOCKETS_MAXPATH];
|
char sockdir[XRDP_SOCKETS_MAXPATH];
|
||||||
g_snprintf(sockdir, sizeof(sockdir), XRDP_SOCKET_PATH, (int)uid);
|
g_snprintf(sockdir, sizeof(sockdir), XRDP_SOCKET_PATH, (int)uid);
|
||||||
|
|
||||||
// Create directory permissions 0x750, if it doesn't exist already.
|
// Create directory permissions RWX_PERMS, if it doesn't exist already
|
||||||
int old_umask = g_umask_hex(0x750 ^ 0x777);
|
// (our os_calls layer doesn't allow us to set the SGID bit here)
|
||||||
|
int old_umask = g_umask_hex(RWX_PERMS ^ 0x777);
|
||||||
if (!g_directory_exist(sockdir) && !g_create_dir(sockdir))
|
if (!g_directory_exist(sockdir) && !g_create_dir(sockdir))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_ERROR,
|
||||||
"create_xrdp_socket_path: Can't create %s [%s]",
|
"create_xrdp_socket_path: Can't create %s [%s]",
|
||||||
sockdir, g_get_strerror());
|
sockdir, g_get_strerror());
|
||||||
}
|
}
|
||||||
|
else if (g_chmod_hex(sockdir, RWX_PERMS | 0x2000) != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR,
|
||||||
|
"create_xrdp_socket_path: Can't set SGID bit on %s [%s]",
|
||||||
|
sockdir, g_get_strerror());
|
||||||
|
}
|
||||||
else if (sockdir_group != NULL && sockdir_group[0] != '\0' &&
|
else if (sockdir_group != NULL && sockdir_group[0] != '\0' &&
|
||||||
g_getgroup_info(sockdir_group, &gid) != 0)
|
g_getgroup_info(sockdir_group, &gid) != 0)
|
||||||
{
|
{
|
||||||
@ -358,6 +376,7 @@ create_xrdp_socket_path(uid_t uid)
|
|||||||
(void)g_umask_hex(old_umask);
|
(void)g_umask_hex(old_umask);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
#undef RWX_PERMS
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -579,8 +579,9 @@ print_version(void)
|
|||||||
{
|
{
|
||||||
g_writeln("xrdp-sesman %s", PACKAGE_VERSION);
|
g_writeln("xrdp-sesman %s", PACKAGE_VERSION);
|
||||||
g_writeln(" The xrdp session manager");
|
g_writeln(" The xrdp session manager");
|
||||||
g_writeln(" Copyright (C) 2004-2023 Jay Sorg, "
|
g_writeln(" Copyright (C) 2004-%d Jay Sorg, "
|
||||||
"Neutrino Labs, and all contributors.");
|
"Neutrino Labs, and all contributors.",
|
||||||
|
VERSION_YEAR);
|
||||||
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
||||||
g_writeln("%s", "");
|
g_writeln("%s", "");
|
||||||
|
|
||||||
|
@ -209,9 +209,12 @@ x_server_running_check_ports(int display)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Helper function for get_sorted_display_list():qsort() */
|
/* Helper function for get_sorted_display_list():qsort() */
|
||||||
static int
|
static int
|
||||||
icmp(const void *i1, const void *i2)
|
icmp(const void *v1, const void *v2)
|
||||||
{
|
{
|
||||||
return *(const unsigned int *)i2 - *(const unsigned int *)i1;
|
// Pointers point to unsigned ints
|
||||||
|
unsigned int i1 = *(unsigned int *)v1;
|
||||||
|
unsigned int i2 = *(unsigned int *)v2;
|
||||||
|
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -108,6 +108,9 @@ START_TEST(test_g_signal_child_stop_1)
|
|||||||
pid = g_fork();
|
pid = g_fork();
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
{
|
{
|
||||||
|
// Before raising the signal, change directory to a non-writeable
|
||||||
|
// one to avoid generating a corefile.
|
||||||
|
g_set_current_dir("/");
|
||||||
raise(SIGSEGV);
|
raise(SIGSEGV);
|
||||||
}
|
}
|
||||||
ck_assert_int_ne(pid, 0);
|
ck_assert_int_ne(pid, 0);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
|
-DXRDP_TOP_SRCDIR=\"$(top_srcdir)\" \
|
||||||
-I$(top_builddir) \
|
-I$(top_builddir) \
|
||||||
-I$(top_srcdir)/xrdp \
|
-I$(top_srcdir)/xrdp \
|
||||||
-I$(top_srcdir)/libxrdp \
|
-I$(top_srcdir)/libxrdp \
|
||||||
@ -18,7 +19,14 @@ EXTRA_DIST = \
|
|||||||
test_not4_8bit.bmp \
|
test_not4_8bit.bmp \
|
||||||
test_not4_24bit.bmp \
|
test_not4_24bit.bmp \
|
||||||
test1.jpg \
|
test1.jpg \
|
||||||
test_alpha_blend.png
|
test_alpha_blend.png \
|
||||||
|
gfx/gfx.toml\
|
||||||
|
gfx/gfx_codec_order_undefined.toml \
|
||||||
|
gfx/gfx_codec_h264_preferred.toml \
|
||||||
|
gfx/gfx_codec_h264_only.toml \
|
||||||
|
gfx/gfx_codec_rfx_preferred.toml \
|
||||||
|
gfx/gfx_codec_rfx_preferred_odd.toml \
|
||||||
|
gfx/gfx_codec_rfx_only.toml
|
||||||
|
|
||||||
TESTS = test_xrdp
|
TESTS = test_xrdp
|
||||||
check_PROGRAMS = test_xrdp
|
check_PROGRAMS = test_xrdp
|
||||||
@ -28,6 +36,7 @@ test_xrdp_SOURCES = \
|
|||||||
test_xrdp_main.c \
|
test_xrdp_main.c \
|
||||||
test_xrdp_egfx.c \
|
test_xrdp_egfx.c \
|
||||||
test_xrdp_region.c \
|
test_xrdp_region.c \
|
||||||
|
test_tconfig.c \
|
||||||
test_bitmap_load.c
|
test_bitmap_load.c
|
||||||
|
|
||||||
test_xrdp_CFLAGS = \
|
test_xrdp_CFLAGS = \
|
||||||
@ -47,6 +56,7 @@ test_xrdp_LDADD = \
|
|||||||
$(top_builddir)/libxrdp/libxrdp.la \
|
$(top_builddir)/libxrdp/libxrdp.la \
|
||||||
$(top_builddir)/libpainter/src/libpainter.la \
|
$(top_builddir)/libpainter/src/libpainter.la \
|
||||||
$(top_builddir)/librfxcodec/src/librfxencode.la \
|
$(top_builddir)/librfxcodec/src/librfxencode.la \
|
||||||
|
$(top_builddir)/third_party/tomlc99/libtoml.la \
|
||||||
$(top_builddir)/xrdp/lang.o \
|
$(top_builddir)/xrdp/lang.o \
|
||||||
$(top_builddir)/xrdp/xrdp_mm.o \
|
$(top_builddir)/xrdp/xrdp_mm.o \
|
||||||
$(top_builddir)/xrdp/xrdp_wm.o \
|
$(top_builddir)/xrdp/xrdp_wm.o \
|
||||||
@ -60,8 +70,16 @@ test_xrdp_LDADD = \
|
|||||||
$(top_builddir)/xrdp/xrdp_encoder.o \
|
$(top_builddir)/xrdp/xrdp_encoder.o \
|
||||||
$(top_builddir)/xrdp/xrdp_process.o \
|
$(top_builddir)/xrdp/xrdp_process.o \
|
||||||
$(top_builddir)/xrdp/xrdp_login_wnd.o \
|
$(top_builddir)/xrdp/xrdp_login_wnd.o \
|
||||||
|
$(top_builddir)/xrdp/xrdp_tconfig.o \
|
||||||
$(top_builddir)/xrdp/xrdp_main_utils.o \
|
$(top_builddir)/xrdp/xrdp_main_utils.o \
|
||||||
$(PIXMAN_LIBS) \
|
$(PIXMAN_LIBS) \
|
||||||
$(IMLIB2_LIBS) \
|
$(IMLIB2_LIBS) \
|
||||||
@CHECK_LIBS@ \
|
@CHECK_LIBS@ \
|
||||||
@CMOCKA_LIBS@
|
@CMOCKA_LIBS@
|
||||||
|
|
||||||
|
if XRDP_X264
|
||||||
|
AM_CPPFLAGS += -DXRDP_X264 $(XRDP_X264_CFLAGS)
|
||||||
|
test_xrdp_LDADD += \
|
||||||
|
$(top_builddir)/xrdp/xrdp_encoder_x264.o \
|
||||||
|
$(XRDP_X264_LIBS)
|
||||||
|
endif
|
||||||
|
40
tests/xrdp/gfx/gfx.toml
Normal file
40
tests/xrdp/gfx/gfx.toml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "H.264", "RFX" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
# inherits default
|
||||||
|
|
||||||
|
[x264.wan]
|
||||||
|
vbv_max_bitrate = 15000
|
||||||
|
vbv_buffer_size = 1500
|
||||||
|
|
||||||
|
[x264.broadband_high]
|
||||||
|
preset = "superfast"
|
||||||
|
vbv_max_bitrate = 8000
|
||||||
|
vbv_buffer_Size = 800
|
||||||
|
|
||||||
|
[x264.satellite]
|
||||||
|
preset = "superfast"
|
||||||
|
vbv_max_bitrate = 5000
|
||||||
|
vbv_buffer_size = 500
|
||||||
|
|
||||||
|
[x264.broadband_low]
|
||||||
|
preset = "veryfast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
vbv_max_bitrate = 1600
|
||||||
|
vbv_buffer_size = 66
|
||||||
|
|
||||||
|
[x264.modem]
|
||||||
|
preset = "fast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
vbv_max_bitrate = 1200
|
||||||
|
vbv_buffer_size = 50
|
18
tests/xrdp/gfx/gfx_codec_h264_only.toml
Normal file
18
tests/xrdp/gfx/gfx_codec_h264_only.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "H.264" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
18
tests/xrdp/gfx/gfx_codec_h264_preferred.toml
Normal file
18
tests/xrdp/gfx/gfx_codec_h264_preferred.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "H.264", "RFX" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
18
tests/xrdp/gfx/gfx_codec_order_undefined.toml
Normal file
18
tests/xrdp/gfx/gfx_codec_order_undefined.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
18
tests/xrdp/gfx/gfx_codec_rfx_only.toml
Normal file
18
tests/xrdp/gfx/gfx_codec_rfx_only.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "RFX" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
18
tests/xrdp/gfx/gfx_codec_rfx_preferred.toml
Normal file
18
tests/xrdp/gfx/gfx_codec_rfx_preferred.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "RFX", "H.264" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
18
tests/xrdp/gfx/gfx_codec_rfx_preferred_odd.toml
Normal file
18
tests/xrdp/gfx/gfx_codec_rfx_preferred_odd.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "RFX", "H.264", "RFX" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
9
tests/xrdp/gfx/gfx_missing_h264.toml
Normal file
9
tests/xrdp/gfx/gfx_missing_h264.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "H.264", "RFX" ]
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
[x264.wan]
|
||||||
|
[x264.broadband_high]
|
||||||
|
[x264.satellite]
|
||||||
|
[x264.broadband_low]
|
||||||
|
[x264.modem]
|
117
tests/xrdp/test_tconfig.c
Normal file
117
tests/xrdp/test_tconfig.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#if defined(HAVE_CONFIG_H)
|
||||||
|
#include "config_ac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xrdp_tconfig.h"
|
||||||
|
#include "test_xrdp.h"
|
||||||
|
#include "xrdp.h"
|
||||||
|
|
||||||
|
#define GFXCONF_STUBDIR XRDP_TOP_SRCDIR "/tests/xrdp/gfx/"
|
||||||
|
|
||||||
|
START_TEST(test_tconfig_gfx_always_success)
|
||||||
|
{
|
||||||
|
ck_assert_int_eq(1, 1);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_tconfig_gfx_x264_load_basic)
|
||||||
|
{
|
||||||
|
struct xrdp_tconfig_gfx gfxconfig;
|
||||||
|
int rv = tconfig_load_gfx(GFXCONF_STUBDIR "/gfx.toml", &gfxconfig);
|
||||||
|
|
||||||
|
ck_assert_int_eq(rv, 0);
|
||||||
|
|
||||||
|
/* default */
|
||||||
|
ck_assert_str_eq(gfxconfig.x264_param[0].preset, "ultrafast");
|
||||||
|
ck_assert_str_eq(gfxconfig.x264_param[0].tune, "zerolatency");
|
||||||
|
ck_assert_str_eq(gfxconfig.x264_param[0].profile, "main");
|
||||||
|
ck_assert_int_eq(gfxconfig.x264_param[0].vbv_max_bitrate, 0);
|
||||||
|
ck_assert_int_eq(gfxconfig.x264_param[0].vbv_buffer_size, 0);
|
||||||
|
ck_assert_int_eq(gfxconfig.x264_param[0].fps_num, 24);
|
||||||
|
ck_assert_int_eq(gfxconfig.x264_param[0].fps_den, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_tconfig_gfx_codec_order)
|
||||||
|
{
|
||||||
|
struct xrdp_tconfig_gfx gfxconfig;
|
||||||
|
|
||||||
|
/* H264 earlier */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_h264_preferred.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_H264);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_RFX);
|
||||||
|
|
||||||
|
/* H264 only */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_h264_only.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_H264);
|
||||||
|
|
||||||
|
/* RFX earlier */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_rfx_preferred.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_H264);
|
||||||
|
|
||||||
|
/* RFX appears twice like: RFX, H264, RFX */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_rfx_preferred_odd.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_H264);
|
||||||
|
|
||||||
|
/* RFX only */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_rfx_only.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
|
||||||
|
|
||||||
|
/* H264 is preferred if order undefined */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_order_undefined.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_H264);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_RFX);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_tconfig_gfx_missing_file)
|
||||||
|
{
|
||||||
|
struct xrdp_tconfig_gfx gfxconfig;
|
||||||
|
|
||||||
|
/* Check RFX config is returned if the file doesn't exist */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/no_such_file.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_tconfig_gfx_missing_h264)
|
||||||
|
{
|
||||||
|
struct xrdp_tconfig_gfx gfxconfig;
|
||||||
|
|
||||||
|
/* Check RFX config only is returned if H.264 parameters are missing */
|
||||||
|
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_missing_h264.toml", &gfxconfig);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
|
||||||
|
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
Suite *
|
||||||
|
make_suite_tconfig_load_gfx(void)
|
||||||
|
{
|
||||||
|
Suite *s;
|
||||||
|
TCase *tc_tconfig_load_gfx;
|
||||||
|
|
||||||
|
s = suite_create("GfxLoad");
|
||||||
|
|
||||||
|
tc_tconfig_load_gfx = tcase_create("xrdp_tconfig_load_gfx");
|
||||||
|
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_always_success);
|
||||||
|
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_x264_load_basic);
|
||||||
|
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_codec_order);
|
||||||
|
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_missing_file);
|
||||||
|
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_missing_h264);
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc_tconfig_load_gfx);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
@ -6,5 +6,6 @@
|
|||||||
Suite *make_suite_test_bitmap_load(void);
|
Suite *make_suite_test_bitmap_load(void);
|
||||||
Suite *make_suite_egfx_base_functions(void);
|
Suite *make_suite_egfx_base_functions(void);
|
||||||
Suite *make_suite_region(void);
|
Suite *make_suite_region(void);
|
||||||
|
Suite *make_suite_tconfig_load_gfx(void);
|
||||||
|
|
||||||
#endif /* TEST_XRDP_H */
|
#endif /* TEST_XRDP_H */
|
||||||
|
@ -57,6 +57,7 @@ int main (void)
|
|||||||
sr = srunner_create (make_suite_test_bitmap_load());
|
sr = srunner_create (make_suite_test_bitmap_load());
|
||||||
srunner_add_suite(sr, make_suite_egfx_base_functions());
|
srunner_add_suite(sr, make_suite_egfx_base_functions());
|
||||||
srunner_add_suite(sr, make_suite_region());
|
srunner_add_suite(sr, make_suite_region());
|
||||||
|
srunner_add_suite(sr, make_suite_tconfig_load_gfx());
|
||||||
|
|
||||||
srunner_set_tap(sr, "-");
|
srunner_set_tap(sr, "-");
|
||||||
srunner_run_all (sr, CK_ENV);
|
srunner_run_all (sr, CK_ENV);
|
||||||
|
431
vnc/vnc.c
431
vnc/vnc.c
@ -149,17 +149,13 @@ log_screen_layout(const enum logLevels lvl, const char *source,
|
|||||||
* @param a First structure
|
* @param a First structure
|
||||||
* @param b Second structure
|
* @param b Second structure
|
||||||
*
|
*
|
||||||
* @return Suitable for sorting structures with ID as the primary key
|
* @return Suitable for sorting structures on (x, y, width, height)
|
||||||
*/
|
*/
|
||||||
static int cmp_vnc_screen(const struct vnc_screen *a,
|
static int cmp_vnc_screen(const struct vnc_screen *a,
|
||||||
const struct vnc_screen *b)
|
const struct vnc_screen *b)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (a->id != b->id)
|
if (a->x != b->x)
|
||||||
{
|
|
||||||
result = a->id - b->id;
|
|
||||||
}
|
|
||||||
else if (a->x != b->x)
|
|
||||||
{
|
{
|
||||||
result = a->x - b->x;
|
result = a->x - b->x;
|
||||||
}
|
}
|
||||||
@ -211,9 +207,7 @@ static int vnc_screen_layouts_equal(const struct vnc_screen_layout *a,
|
|||||||
* @return != 0 for error
|
* @return != 0 for error
|
||||||
*
|
*
|
||||||
* @pre The next octet read from v->trans is the number of screens
|
* @pre The next octet read from v->trans is the number of screens
|
||||||
* @pre layout is not already allocated
|
|
||||||
*
|
*
|
||||||
* @post if call is successful, layout->s must be freed after use.
|
|
||||||
* @post Returned structure is in increasing ID order
|
* @post Returned structure is in increasing ID order
|
||||||
* @post layout->total_width is untouched
|
* @post layout->total_width is untouched
|
||||||
* @post layout->total_height is untouched
|
* @post layout->total_height is untouched
|
||||||
@ -225,10 +219,8 @@ read_extended_desktop_size_rect(struct vnc *v,
|
|||||||
struct stream *s;
|
struct stream *s;
|
||||||
int error;
|
int error;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
struct vnc_screen *screens;
|
|
||||||
|
|
||||||
layout->count = 0;
|
layout->count = 0;
|
||||||
layout->s = NULL;
|
|
||||||
|
|
||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
@ -239,46 +231,41 @@ read_extended_desktop_size_rect(struct vnc *v,
|
|||||||
{
|
{
|
||||||
/* Get the number of screens */
|
/* Get the number of screens */
|
||||||
in_uint8(s, count);
|
in_uint8(s, count);
|
||||||
in_uint8s(s, 3);
|
if (count <= 0 || count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
|
||||||
|
|
||||||
error = trans_force_read_s(v->trans, s, 16 * count);
|
|
||||||
if (error == 0)
|
|
||||||
{
|
{
|
||||||
screens = g_new(struct vnc_screen, count);
|
LOG(LOG_LEVEL_ERROR,
|
||||||
if (screens == NULL)
|
"Bad monitor count %d in ExtendedDesktopSize rectangle",
|
||||||
{
|
count);
|
||||||
LOG(LOG_LEVEL_ERROR,
|
error = 1;
|
||||||
"VNC : Can't alloc for %d screens", count);
|
}
|
||||||
error = 1;
|
else
|
||||||
}
|
{
|
||||||
else
|
in_uint8s(s, 3);
|
||||||
|
|
||||||
|
error = trans_force_read_s(v->trans, s, 16 * count);
|
||||||
|
if (error == 0)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0 ; i < count ; ++i)
|
for (i = 0 ; i < count ; ++i)
|
||||||
{
|
{
|
||||||
in_uint32_be(s, screens[i].id);
|
in_uint32_be(s, layout->s[i].id);
|
||||||
in_uint16_be(s, screens[i].x);
|
in_uint16_be(s, layout->s[i].x);
|
||||||
in_uint16_be(s, screens[i].y);
|
in_uint16_be(s, layout->s[i].y);
|
||||||
in_uint16_be(s, screens[i].width);
|
in_uint16_be(s, layout->s[i].width);
|
||||||
in_uint16_be(s, screens[i].height);
|
in_uint16_be(s, layout->s[i].height);
|
||||||
in_uint32_be(s, screens[i].flags);
|
in_uint32_be(s, layout->s[i].flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sort monitors in increasing ID order */
|
/* sort monitors in increasing (x,y) order */
|
||||||
qsort(screens, count, sizeof(screens[0]),
|
qsort(layout->s, count, sizeof(layout->s[0]),
|
||||||
(int (*)(const void *, const void *))cmp_vnc_screen);
|
(int (*)(const void *, const void *))cmp_vnc_screen);
|
||||||
|
layout->count = count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
|
|
||||||
if (error == 0)
|
|
||||||
{
|
|
||||||
layout->count = count;
|
|
||||||
layout->s = screens;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,88 +313,76 @@ send_set_desktop_size(struct vnc *v, const struct vnc_screen_layout *layout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* Sets up a single-screen vnc_screen_layout structure
|
* Initialises a vnc_screen_layout as a single screen
|
||||||
*
|
* @param[in] width Screen Width
|
||||||
* @param layout Structure to set up
|
* @param[in] height Screen Height
|
||||||
* @param width New client width
|
* @param[out] layout Layout to initialise
|
||||||
* @param height New client height
|
|
||||||
*
|
|
||||||
* @pre layout->count must be valid
|
|
||||||
* @pre layout->s must be valid
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
set_single_screen_layout(struct vnc_screen_layout *layout,
|
init_single_screen_layout(int width, int height,
|
||||||
int width, int height)
|
struct vnc_screen_layout *layout)
|
||||||
{
|
{
|
||||||
int id = 0;
|
|
||||||
int flags = 0;
|
|
||||||
|
|
||||||
layout->total_width = width;
|
layout->total_width = width;
|
||||||
layout->total_height = height;
|
layout->total_height = height;
|
||||||
|
|
||||||
if (layout->count == 0)
|
|
||||||
{
|
|
||||||
/* No previous layout */
|
|
||||||
layout->s = g_new(struct vnc_screen, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Keep the ID and flags from the previous first screen */
|
|
||||||
id = layout->s[0].id;
|
|
||||||
flags = layout->s[0].flags;
|
|
||||||
|
|
||||||
if (layout->count > 1)
|
|
||||||
{
|
|
||||||
g_free(layout->s);
|
|
||||||
layout->s = g_new(struct vnc_screen, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layout->count = 1;
|
layout->count = 1;
|
||||||
layout->s[0].id = id;
|
layout->s[0].id = 0;
|
||||||
layout->s[0].x = 0;
|
layout->s[0].x = 0;
|
||||||
layout->s[0].y = 0;
|
layout->s[0].y = 0;
|
||||||
layout->s[0].width = width;
|
layout->s[0].width = width;
|
||||||
layout->s[0].height = height;
|
layout->s[0].height = height;
|
||||||
layout->s[0].flags = flags;
|
layout->s[0].flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* Resize the client as a single screen
|
* Resize the client to match the server_layout
|
||||||
*
|
*
|
||||||
* @param v VNC object
|
* @param v VNC object
|
||||||
* @param update_in_progress True if there's a painter update in progress
|
* @param update_in_progress True if there's a painter update in progress
|
||||||
* @param width New client width
|
|
||||||
* @param height New client height
|
|
||||||
* @return != 0 for error
|
* @return != 0 for error
|
||||||
*
|
*
|
||||||
* The new client layout is recorded in v->client_layout. If the client was
|
* The new client layout is recorded in v->client_layout.
|
||||||
* multi-screen before this call, it won't be afterwards.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
resize_client(struct vnc *v, int update_in_progress, int width, int height)
|
resize_client_to_server(struct vnc *v, int update_in_progress)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
unsigned int i;
|
||||||
|
const struct vnc_screen_layout *sl = &v->server_layout;
|
||||||
|
struct monitor_info client_mons[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS] = {0};
|
||||||
|
|
||||||
if (v->client_layout.count != 1 ||
|
if (sl->count <= 0 ||
|
||||||
v->client_layout.total_width != width ||
|
sl->count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
|
||||||
v->client_layout.total_height != height)
|
|
||||||
{
|
{
|
||||||
if (update_in_progress)
|
LOG(LOG_LEVEL_ERROR, "%s: Programming error. Bad monitors %d",
|
||||||
{
|
__func__, sl->count);
|
||||||
error = v->server_end_update(v);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the server monitors into client monitors
|
||||||
|
for (i = 0; i < sl->count; ++i)
|
||||||
|
{
|
||||||
|
client_mons[i].left = sl->s[i].x;
|
||||||
|
client_mons[i].top = sl->s[i].y;
|
||||||
|
client_mons[i].right = sl->s[i].x + sl->s[i].width - 1;
|
||||||
|
client_mons[i].bottom = sl->s[i].y + sl->s[i].height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_in_progress && v->server_end_update(v) != 0)
|
||||||
|
{
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error = v->client_monitor_resize(v, sl->total_width, sl->total_height,
|
||||||
|
sl->count, client_mons);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
error = v->server_reset(v, width, height, v->server_bpp);
|
v->client_layout = *sl;
|
||||||
if (error == 0)
|
}
|
||||||
{
|
|
||||||
set_single_screen_layout(&v->client_layout, width, height);
|
if (update_in_progress && v->server_begin_update(v) != 0)
|
||||||
if (update_in_progress)
|
{
|
||||||
{
|
error = 1;
|
||||||
error = v->server_begin_update(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,50 +391,53 @@ resize_client(struct vnc *v, int update_in_progress, int width, int height)
|
|||||||
|
|
||||||
|
|
||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* Resize the attached client from a layout
|
* Resize the server to the client layout
|
||||||
*
|
*
|
||||||
* @param v VNC object
|
* @param v VNC object
|
||||||
* @param update_in_progress True if there's a painter update in progress
|
|
||||||
* @param layout Desired layout from server
|
|
||||||
* @return != 0 for error
|
* @return != 0 for error
|
||||||
*
|
*
|
||||||
* This has some limitations. We have no way to move multiple screens about
|
* The new client layout is recorded in v->client_layout.
|
||||||
* on a connected client, and so we are not able to change the client unless
|
|
||||||
* we're changing to a single screen layout.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
resize_client_from_layout(struct vnc *v,
|
resize_server_to_client_layout(struct vnc *v)
|
||||||
int update_in_progress,
|
|
||||||
const struct vnc_screen_layout *layout)
|
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if (!vnc_screen_layouts_equal(&v->client_layout, layout))
|
if (v->resize_supported != VRSS_SUPPORTED)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "%s: Asked to resize server, but not possible",
|
||||||
|
__func__);
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
else if (vnc_screen_layouts_equal(&v->server_layout, &v->client_layout))
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_DEBUG, "Server layout is the same "
|
||||||
|
"as the client layout");
|
||||||
|
v->resize_status = VRS_DONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* we don't have the capability to resize to anything other
|
* If we've only got one screen, and the other side has
|
||||||
* than a single screen.
|
* only got one screen, we will preserve their screen ID
|
||||||
|
* and any flags. This may prevent us sending an unwanted
|
||||||
|
* SetDesktopSize message if the screen dimensions are
|
||||||
|
* a match. We can't do this with more than one screen,
|
||||||
|
* as we have no way to map different IDs
|
||||||
*/
|
*/
|
||||||
if (layout->count != 1)
|
if (v->server_layout.count == 1 && v->client_layout.count == 1)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_DEBUG, "VNC "
|
||||||
"VNC Resize to %d screen(s) from %d screen(s) "
|
"setting screen id to %d from server",
|
||||||
"not implemented",
|
v->server_layout.s[0].id);
|
||||||
v->client_layout.count, layout->count);
|
|
||||||
|
|
||||||
/* Dump some useful info, in case we get here when we don't
|
v->client_layout.s[0].id = v->server_layout.s[0].id;
|
||||||
* need to */
|
v->client_layout.s[0].flags = v->server_layout.s[0].flags;
|
||||||
log_screen_layout(LOG_LEVEL_ERROR, "OldLayout", &v->client_layout);
|
|
||||||
log_screen_layout(LOG_LEVEL_ERROR, "NewLayout", layout);
|
|
||||||
error = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error = resize_client(v,
|
|
||||||
update_in_progress,
|
|
||||||
layout->total_width,
|
|
||||||
layout->total_height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG(LOG_LEVEL_DEBUG, "Changing server layout");
|
||||||
|
error = send_set_desktop_size(v, &v->client_layout);
|
||||||
|
v->resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -927,7 +905,6 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
|
|||||||
"x=%d, y=%d geom=%dx%d",
|
"x=%d, y=%d geom=%dx%d",
|
||||||
x, y, cx, cy);
|
x, y, cx, cy);
|
||||||
error = read_extended_desktop_size_rect(v, &layout);
|
error = read_extended_desktop_size_rect(v, &layout);
|
||||||
g_free(layout.s);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -944,7 +921,7 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
|
|||||||
* Parses an entire framebuffer update message from the wire, and returns the
|
* Parses an entire framebuffer update message from the wire, and returns the
|
||||||
* first matching ExtendedDesktopSize encoding if found.
|
* first matching ExtendedDesktopSize encoding if found.
|
||||||
*
|
*
|
||||||
* Caller can check for a match by examining match_layout.s after the call
|
* Caller can check for a match by examining match_layout.count after the call
|
||||||
*
|
*
|
||||||
* @param v VNC object
|
* @param v VNC object
|
||||||
* @param match Function to call to check for a match
|
* @param match Function to call to check for a match
|
||||||
@ -952,8 +929,6 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
|
|||||||
* @param [out] match_y Matching y parameter for an encoding (if needed)
|
* @param [out] match_y Matching y parameter for an encoding (if needed)
|
||||||
* @param [out] match_layout Returned layout for the encoding
|
* @param [out] match_layout Returned layout for the encoding
|
||||||
* @return != 0 for error
|
* @return != 0 for error
|
||||||
*
|
|
||||||
* @post After a successful call, match_layout.s must be free'd
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
find_matching_extended_rect(struct vnc *v,
|
find_matching_extended_rect(struct vnc *v,
|
||||||
@ -971,8 +946,7 @@ find_matching_extended_rect(struct vnc *v,
|
|||||||
int cx;
|
int cx;
|
||||||
int cy;
|
int cy;
|
||||||
encoding_type encoding;
|
encoding_type encoding;
|
||||||
|
int found = 0;
|
||||||
match_layout->s = NULL;
|
|
||||||
|
|
||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
@ -1002,14 +976,14 @@ find_matching_extended_rect(struct vnc *v,
|
|||||||
in_uint32_be(s, encoding);
|
in_uint32_be(s, encoding);
|
||||||
|
|
||||||
if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE &&
|
if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE &&
|
||||||
match_layout->s == NULL &&
|
!found &&
|
||||||
match(x, y, cx, cy))
|
match(x, y, cx, cy))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_DEBUG,
|
LOG(LOG_LEVEL_DEBUG,
|
||||||
"VNC matched ExtendedDesktopSize rectangle "
|
"VNC matched ExtendedDesktopSize rectangle "
|
||||||
"x=%d, y=%d geom=%dx%d",
|
"x=%d, y=%d geom=%dx%d",
|
||||||
x, y, cx, cy);
|
x, y, cx, cy);
|
||||||
|
found = 1;
|
||||||
error = read_extended_desktop_size_rect(v, match_layout);
|
error = read_extended_desktop_size_rect(v, match_layout);
|
||||||
if (match_x)
|
if (match_x)
|
||||||
{
|
{
|
||||||
@ -1065,6 +1039,7 @@ send_update_request_for_resize_status(struct vnc *v)
|
|||||||
switch (v->resize_status)
|
switch (v->resize_status)
|
||||||
{
|
{
|
||||||
case VRS_WAITING_FOR_FIRST_UPDATE:
|
case VRS_WAITING_FOR_FIRST_UPDATE:
|
||||||
|
case VRS_WAITING_FOR_RESIZE_CONFIRM:
|
||||||
/*
|
/*
|
||||||
* Ask for an immediate, minimal update.
|
* Ask for an immediate, minimal update.
|
||||||
*/
|
*/
|
||||||
@ -1078,20 +1053,6 @@ send_update_request_for_resize_status(struct vnc *v)
|
|||||||
error = lib_send_copy(v, s);
|
error = lib_send_copy(v, s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VRS_WAITING_FOR_RESIZE_CONFIRM:
|
|
||||||
/*
|
|
||||||
* Ask for a deferred minimal update.
|
|
||||||
*/
|
|
||||||
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
|
|
||||||
out_uint8(s, 1); /* incremental == 1 : Changes only */
|
|
||||||
out_uint16_be(s, 0);
|
|
||||||
out_uint16_be(s, 0);
|
|
||||||
out_uint16_be(s, 1);
|
|
||||||
out_uint16_be(s, 1);
|
|
||||||
s_mark_end(s);
|
|
||||||
error = lib_send_copy(v, s);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
* Ask for a full update from the server
|
* Ask for a full update from the server
|
||||||
@ -1102,8 +1063,8 @@ send_update_request_for_resize_status(struct vnc *v)
|
|||||||
out_uint8(s, 0); /* incremental == 0 : Full update */
|
out_uint8(s, 0); /* incremental == 0 : Full update */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->server_width);
|
out_uint16_be(s, v->server_layout.total_width);
|
||||||
out_uint16_be(s, v->server_height);
|
out_uint16_be(s, v->server_layout.total_height);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
error = lib_send_copy(v, s);
|
error = lib_send_copy(v, s);
|
||||||
}
|
}
|
||||||
@ -1159,12 +1120,15 @@ lib_framebuffer_first_update(struct vnc *v)
|
|||||||
&layout);
|
&layout);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
if (layout.s != NULL)
|
if (layout.count > 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_DEBUG, "VNC server supports resizing");
|
LOG(LOG_LEVEL_DEBUG, "VNC server supports resizing");
|
||||||
|
v->resize_supported = VRSS_SUPPORTED;
|
||||||
|
v->server_layout = layout;
|
||||||
|
|
||||||
/* Force the client geometry over to the server */
|
/* Force the client geometry over to the server */
|
||||||
log_screen_layout(LOG_LEVEL_INFO, "OldLayout", &layout);
|
log_screen_layout(LOG_LEVEL_INFO, "ClientLayout", &v->client_layout);
|
||||||
|
log_screen_layout(LOG_LEVEL_INFO, "OldServerLayout", &layout);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've only got one screen, and the other side has
|
* If we've only got one screen, and the other side has
|
||||||
@ -1184,32 +1148,19 @@ lib_framebuffer_first_update(struct vnc *v)
|
|||||||
v->client_layout.s[0].flags = layout.s[0].flags;
|
v->client_layout.s[0].flags = layout.s[0].flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vnc_screen_layouts_equal(&layout, &v->client_layout))
|
resize_server_to_client_layout(v);
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_DEBUG, "Server layout is the same "
|
|
||||||
"as the client layout");
|
|
||||||
v->resize_status = VRS_DONE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_DEBUG, "Server layout differs from "
|
|
||||||
"the client layout. Changing server layout");
|
|
||||||
error = send_set_desktop_size(v, &v->client_layout);
|
|
||||||
v->resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_DEBUG, "VNC server does not support resizing");
|
LOG(LOG_LEVEL_DEBUG, "VNC server does not support resizing");
|
||||||
|
v->resize_supported = VRSS_NOT_SUPPORTED;
|
||||||
|
|
||||||
/* Force client to same size as server */
|
/* Force client to same size as server */
|
||||||
LOG(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d",
|
LOG(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d",
|
||||||
v->server_width, v->server_height);
|
v->server_layout.total_width, v->server_layout.total_height);
|
||||||
error = resize_client(v, 0, v->server_width, v->server_height);
|
error = resize_client_to_server(v, 0);
|
||||||
v->resize_status = VRS_DONE;
|
v->resize_status = VRS_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(layout.s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
@ -1224,7 +1175,7 @@ lib_framebuffer_first_update(struct vnc *v)
|
|||||||
* Looks for a resize confirm in a framebuffer update request
|
* Looks for a resize confirm in a framebuffer update request
|
||||||
*
|
*
|
||||||
* If the server supports resizes from us, this is used to find the
|
* If the server supports resizes from us, this is used to find the
|
||||||
* reply to our initial resize request. See The RFB community wiki for details.
|
* reply to our resize request. See The RFB community wiki for details.
|
||||||
*
|
*
|
||||||
* @param v VNC object
|
* @param v VNC object
|
||||||
* @return != 0 for error
|
* @return != 0 for error
|
||||||
@ -1243,18 +1194,17 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
|
|||||||
&layout);
|
&layout);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
if (layout.s != NULL)
|
if (layout.count > 0)
|
||||||
{
|
{
|
||||||
if (response_code == 0)
|
if (response_code == 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized");
|
LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized");
|
||||||
log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout);
|
log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout);
|
||||||
|
v->server_layout = layout;
|
||||||
// If this resize was requested by the client mid-session
|
// If this resize was requested by the client mid-session
|
||||||
// (dynamic resize), we need to tell xrdp_mm that
|
// (dynamic resize), we need to tell xrdp_mm that
|
||||||
// it's OK to continue with the resize state machine.
|
// it's OK to continue with the resize state machine.
|
||||||
// We do this by sending a reset with bpp == 0
|
error = v->server_monitor_resize_done(v);
|
||||||
error = v->server_reset(v, v->server_width,
|
|
||||||
v->server_height, 0);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1263,14 +1213,11 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
|
|||||||
response_code,
|
response_code,
|
||||||
rfb_get_eds_status_msg(response_code));
|
rfb_get_eds_status_msg(response_code));
|
||||||
/* Force client to same size as server */
|
/* Force client to same size as server */
|
||||||
LOG(LOG_LEVEL_WARNING, "Resizing client to server %dx%d",
|
LOG(LOG_LEVEL_WARNING, "Resizing client to server");
|
||||||
v->server_width, v->server_height);
|
error = resize_client_to_server(v, 0);
|
||||||
error = resize_client(v, 0, v->server_width, v->server_height);
|
|
||||||
}
|
}
|
||||||
v->resize_status = VRS_DONE;
|
v->resize_status = VRS_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(layout.s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
@ -1415,9 +1362,8 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
else if (encoding == RFB_ENC_DESKTOP_SIZE)
|
else if (encoding == RFB_ENC_DESKTOP_SIZE)
|
||||||
{
|
{
|
||||||
/* Server end has resized */
|
/* Server end has resized */
|
||||||
v->server_width = cx;
|
init_single_screen_layout(cx, cy, &v->server_layout);
|
||||||
v->server_height = cy;
|
error = resize_client_to_server(v, 1);
|
||||||
error = resize_client(v, 1, cx, cy);
|
|
||||||
}
|
}
|
||||||
else if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE)
|
else if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE)
|
||||||
{
|
{
|
||||||
@ -1427,11 +1373,14 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
/* If this is a reply to a request from us, x == 1 */
|
/* If this is a reply to a request from us, x == 1 */
|
||||||
if (error == 0 && x != 1)
|
if (error == 0 && x != 1)
|
||||||
{
|
{
|
||||||
v->server_width = layout.total_width;
|
if (!vnc_screen_layouts_equal(&v->server_layout, &layout))
|
||||||
v->server_height = layout.total_height;
|
{
|
||||||
error = resize_client_from_layout(v, 1, &layout);
|
v->server_layout = layout;
|
||||||
|
log_screen_layout(LOG_LEVEL_INFO, "NewServerLayout",
|
||||||
|
&v->server_layout);
|
||||||
|
error = resize_client_to_server(v, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_free(layout.s);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1456,8 +1405,8 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
out_uint8(s, 1); /* incremental == 1 : Changes only */
|
out_uint8(s, 1); /* incremental == 1 : Changes only */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->server_width);
|
out_uint16_be(s, v->server_layout.total_width);
|
||||||
out_uint16_be(s, v->server_height);
|
out_uint16_be(s, v->server_layout.total_height);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
error = lib_send_copy(v, s);
|
error = lib_send_copy(v, s);
|
||||||
}
|
}
|
||||||
@ -1831,8 +1780,11 @@ lib_mod_connect(struct vnc *v)
|
|||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
in_uint16_be(s, v->server_width);
|
int width;
|
||||||
in_uint16_be(s, v->server_height);
|
int height;
|
||||||
|
in_uint16_be(s, width);
|
||||||
|
in_uint16_be(s, height);
|
||||||
|
init_single_screen_layout(width, height, &v->server_layout);
|
||||||
|
|
||||||
init_stream(pixel_format, 8192);
|
init_stream(pixel_format, 8192);
|
||||||
v->server_msg(v, "VNC receiving pixel format", 0);
|
v->server_msg(v, "VNC receiving pixel format", 0);
|
||||||
@ -2000,6 +1952,7 @@ lib_mod_connect(struct vnc *v)
|
|||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
|
v->resize_supported = VRSS_UNKNOWN;
|
||||||
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
|
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
|
||||||
error = send_update_request_for_resize_status(v);
|
error = send_update_request_for_resize_status(v);
|
||||||
}
|
}
|
||||||
@ -2061,33 +2014,40 @@ lib_mod_end(struct vnc *v)
|
|||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* Initialises the client layout from the Windows monitor definition.
|
* Initialises the client layout from the Windows monitor definition.
|
||||||
*
|
*
|
||||||
* @param [out] layout Our layout
|
* @param v VNC module
|
||||||
* @param [in] client_info WM info
|
* @param [in] width session width
|
||||||
|
* @param [in] height session height
|
||||||
|
* @param [in] num_monitors (can be 0, meaning one monitor)
|
||||||
|
* @param [in] monitors Monitor definitions for num_monitors > 0
|
||||||
|
* @param [in] multimon_configured Whether multimon is configured
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
init_client_layout(struct vnc_screen_layout *layout,
|
init_client_layout(struct vnc *v,
|
||||||
const struct xrdp_client_info *client_info)
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
struct vnc_screen_layout *layout = &v->client_layout;
|
||||||
|
if (!v->multimon_configured || num_monitors < 1)
|
||||||
layout->total_width = client_info->display_sizes.session_width;
|
|
||||||
layout->total_height = client_info->display_sizes.session_height;
|
|
||||||
|
|
||||||
layout->count = client_info->display_sizes.monitorCount;
|
|
||||||
layout->s = g_new(struct vnc_screen, layout->count);
|
|
||||||
|
|
||||||
for (i = 0 ; i < client_info->display_sizes.monitorCount ; ++i)
|
|
||||||
{
|
{
|
||||||
/* Use minfo_wm, as this is normalised for a top-left of (0,0)
|
init_single_screen_layout(width, height, layout);
|
||||||
* as required by RFC6143 */
|
}
|
||||||
layout->s[i].id = i;
|
else
|
||||||
layout->s[i].x = client_info->display_sizes.minfo_wm[i].left;
|
{
|
||||||
layout->s[i].y = client_info->display_sizes.minfo_wm[i].top;
|
layout->total_width = width;
|
||||||
layout->s[i].width = client_info->display_sizes.minfo_wm[i].right -
|
layout->total_height = height;
|
||||||
client_info->display_sizes.minfo_wm[i].left + 1;
|
layout->count = num_monitors;
|
||||||
layout->s[i].height = client_info->display_sizes.minfo_wm[i].bottom -
|
|
||||||
client_info->display_sizes.minfo_wm[i].top + 1;
|
unsigned int i;
|
||||||
layout->s[i].flags = 0;
|
for (i = 0 ; i < layout->count; ++i)
|
||||||
|
{
|
||||||
|
layout->s[i].id = i;
|
||||||
|
layout->s[i].x = monitors[i].left;
|
||||||
|
layout->s[i].y = monitors[i].top;
|
||||||
|
layout->s[i].width = monitors[i].right - monitors[i].left + 1;
|
||||||
|
layout->s[i].height = monitors[i].bottom - monitors[i].top + 1;
|
||||||
|
layout->s[i].flags = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2132,19 +2092,16 @@ lib_mod_set_param(struct vnc *v, const char *name, const char *value)
|
|||||||
const struct xrdp_client_info *client_info =
|
const struct xrdp_client_info *client_info =
|
||||||
(const struct xrdp_client_info *) value;
|
(const struct xrdp_client_info *) value;
|
||||||
|
|
||||||
g_free(v->client_layout.s);
|
v->multimon_configured = client_info->multimon;
|
||||||
|
|
||||||
/* Save monitor information from the client */
|
/* Save monitor information from the client
|
||||||
if (!client_info->multimon || client_info->display_sizes.monitorCount < 1)
|
* Use minfo_wm, as this is normalised for a top-left of (0,0)
|
||||||
{
|
* as required by RFC6143 */
|
||||||
set_single_screen_layout(&v->client_layout,
|
init_client_layout(v,
|
||||||
client_info->display_sizes.session_width,
|
client_info->display_sizes.session_width,
|
||||||
client_info->display_sizes.session_height);
|
client_info->display_sizes.session_height,
|
||||||
}
|
client_info->display_sizes.monitorCount,
|
||||||
else
|
client_info->display_sizes.minfo_wm);
|
||||||
{
|
|
||||||
init_client_layout(&v->client_layout, client_info);
|
|
||||||
}
|
|
||||||
log_screen_layout(LOG_LEVEL_DEBUG, "client_info", &v->client_layout);
|
log_screen_layout(LOG_LEVEL_DEBUG, "client_info", &v->client_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2185,6 +2142,10 @@ lib_mod_check_wait_objs(struct vnc *v)
|
|||||||
if (v->trans != 0)
|
if (v->trans != 0)
|
||||||
{
|
{
|
||||||
rv = trans_check_wait_objs(v->trans);
|
rv = trans_check_wait_objs(v->trans);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "VNC server closed connection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
@ -2217,8 +2178,8 @@ lib_mod_suppress_output(struct vnc *v, int suppress,
|
|||||||
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->server_width);
|
out_uint16_be(s, v->server_layout.total_width);
|
||||||
out_uint16_be(s, v->server_height);
|
out_uint16_be(s, v->server_layout.total_height);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
error = lib_send_copy(v, s);
|
error = lib_send_copy(v, s);
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
@ -2237,12 +2198,29 @@ lib_mod_server_version_message(struct vnc *v)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* return error */
|
/* return error */
|
||||||
int
|
int
|
||||||
lib_mod_server_monitor_resize(struct vnc *v, int width, int height)
|
lib_mod_server_monitor_resize(struct vnc *v, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error;
|
||||||
set_single_screen_layout(&v->client_layout, width, height);
|
*in_progress = 0;
|
||||||
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
|
init_client_layout(v, width, height, num_monitors, monitors);
|
||||||
error = send_update_request_for_resize_status(v);
|
|
||||||
|
if ((error = resize_server_to_client_layout(v)) == 0)
|
||||||
|
{
|
||||||
|
// If we're waiting for a confirmation, send an update request.
|
||||||
|
// According to the spec this should not be needed, but
|
||||||
|
// it works around a buggy VNC server not sending an
|
||||||
|
// ExtendedDesktopSize rectangle if the desktop change is
|
||||||
|
// small (eg. same dimensions, but 2 monitors -> 1 monitor)
|
||||||
|
if (v->resize_status == VRS_WAITING_FOR_RESIZE_CONFIRM &&
|
||||||
|
(error = send_update_request_for_resize_status(v)) == 0)
|
||||||
|
{
|
||||||
|
*in_progress = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2298,7 +2276,6 @@ mod_exit(tintptr handle)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
trans_delete(v->trans);
|
trans_delete(v->trans);
|
||||||
g_free(v->client_layout.s);
|
|
||||||
vnc_clip_exit(v);
|
vnc_clip_exit(v);
|
||||||
g_free(v);
|
g_free(v);
|
||||||
return 0;
|
return 0;
|
||||||
|
32
vnc/vnc.h
32
vnc/vnc.h
@ -27,6 +27,7 @@
|
|||||||
#include "os_calls.h"
|
#include "os_calls.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "guid.h"
|
#include "guid.h"
|
||||||
|
#include "ms-rdpbcgr.h"
|
||||||
|
|
||||||
#define CURRENT_MOD_VER 4
|
#define CURRENT_MOD_VER 4
|
||||||
|
|
||||||
@ -46,8 +47,8 @@ struct vnc_screen_layout
|
|||||||
int total_width;
|
int total_width;
|
||||||
int total_height;
|
int total_height;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
/* For comparison, screens are sorted in increasing order of ID */
|
/* For comparison, screens are sorted in x, y, width, height) order */
|
||||||
struct vnc_screen *s;
|
struct vnc_screen s[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,11 +61,21 @@ enum vnc_resize_status
|
|||||||
VRS_DONE
|
VRS_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum vnc_resize_support_status
|
||||||
|
{
|
||||||
|
VRSS_NOT_SUPPORTED,
|
||||||
|
VRSS_SUPPORTED,
|
||||||
|
VRSS_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
struct source_info;
|
struct source_info;
|
||||||
|
|
||||||
/* Defined in vnc_clip.c */
|
/* Defined in vnc_clip.c */
|
||||||
struct vnc_clipboard_data;
|
struct vnc_clipboard_data;
|
||||||
|
|
||||||
|
/* Defined in xrdp_client_info.h */
|
||||||
|
struct monitor_info;
|
||||||
|
|
||||||
struct vnc
|
struct vnc
|
||||||
{
|
{
|
||||||
int size; /* size of this struct */
|
int size; /* size of this struct */
|
||||||
@ -85,7 +96,10 @@ struct vnc
|
|||||||
int (*mod_suppress_output)(struct vnc *v, int suppress,
|
int (*mod_suppress_output)(struct vnc *v, int suppress,
|
||||||
int left, int top, int right, int bottom);
|
int left, int top, int right, int bottom);
|
||||||
int (*mod_server_monitor_resize)(struct vnc *v,
|
int (*mod_server_monitor_resize)(struct vnc *v,
|
||||||
int width, int height);
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress);
|
||||||
int (*mod_server_monitor_full_invalidate)(struct vnc *v,
|
int (*mod_server_monitor_full_invalidate)(struct vnc *v,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
int (*mod_server_version_message)(struct vnc *v);
|
int (*mod_server_version_message)(struct vnc *v);
|
||||||
@ -123,7 +137,10 @@ struct vnc
|
|||||||
int box_left, int box_top,
|
int box_left, int box_top,
|
||||||
int box_right, int box_bottom,
|
int box_right, int box_bottom,
|
||||||
int x, int y, char *data, int data_len);
|
int x, int y, char *data, int data_len);
|
||||||
int (*server_reset)(struct vnc *v, int width, int height, int bpp);
|
int (*client_monitor_resize)(struct vnc *v, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors);
|
||||||
|
int (*server_monitor_resize_done)(struct vnc *v);
|
||||||
int (*server_get_channel_count)(struct vnc *v);
|
int (*server_get_channel_count)(struct vnc *v);
|
||||||
int (*server_query_channel)(struct vnc *v, int index,
|
int (*server_query_channel)(struct vnc *v, int index,
|
||||||
char *channel_name,
|
char *channel_name,
|
||||||
@ -134,7 +151,7 @@ struct vnc
|
|||||||
int total_data_len, int flags);
|
int total_data_len, int flags);
|
||||||
int (*server_bell_trigger)(struct vnc *v);
|
int (*server_bell_trigger)(struct vnc *v);
|
||||||
int (*server_chansrv_in_use)(struct vnc *v);
|
int (*server_chansrv_in_use)(struct vnc *v);
|
||||||
tintptr server_dumby[100 - 27]; /* align, 100 minus the number of server
|
tintptr server_dumby[100 - 28]; /* align, 100 minus the number of server
|
||||||
functions above */
|
functions above */
|
||||||
/* common */
|
/* common */
|
||||||
tintptr handle; /* pointer to self as long */
|
tintptr handle; /* pointer to self as long */
|
||||||
@ -142,8 +159,6 @@ struct vnc
|
|||||||
tintptr painter;
|
tintptr painter;
|
||||||
struct source_info *si;
|
struct source_info *si;
|
||||||
/* mod data */
|
/* mod data */
|
||||||
int server_width;
|
|
||||||
int server_height;
|
|
||||||
int server_bpp;
|
int server_bpp;
|
||||||
char mod_name[256];
|
char mod_name[256];
|
||||||
int mod_mouse_state;
|
int mod_mouse_state;
|
||||||
@ -164,8 +179,11 @@ struct vnc
|
|||||||
int suppress_output;
|
int suppress_output;
|
||||||
unsigned int enabled_encodings_mask;
|
unsigned int enabled_encodings_mask;
|
||||||
/* Resizeable support */
|
/* Resizeable support */
|
||||||
|
int multimon_configured;
|
||||||
struct vnc_screen_layout client_layout;
|
struct vnc_screen_layout client_layout;
|
||||||
|
struct vnc_screen_layout server_layout;
|
||||||
enum vnc_resize_status resize_status;
|
enum vnc_resize_status resize_status;
|
||||||
|
enum vnc_resize_support_status resize_supported;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -19,6 +19,7 @@ AM_CPPFLAGS = \
|
|||||||
$(IMLIB2_CFLAGS)
|
$(IMLIB2_CFLAGS)
|
||||||
|
|
||||||
XRDP_EXTRA_LIBS =
|
XRDP_EXTRA_LIBS =
|
||||||
|
XRDP_EXTRA_SOURCES =
|
||||||
|
|
||||||
if XRDP_RFXCODEC
|
if XRDP_RFXCODEC
|
||||||
AM_CPPFLAGS += -DXRDP_RFXCODEC
|
AM_CPPFLAGS += -DXRDP_RFXCODEC
|
||||||
@ -26,6 +27,13 @@ AM_CPPFLAGS += -I$(top_srcdir)/librfxcodec/include
|
|||||||
XRDP_EXTRA_LIBS += $(top_builddir)/librfxcodec/src/.libs/librfxencode.a
|
XRDP_EXTRA_LIBS += $(top_builddir)/librfxcodec/src/.libs/librfxencode.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if XRDP_X264
|
||||||
|
AM_CPPFLAGS += -DXRDP_X264
|
||||||
|
AM_CPPFLAGS += $(XRDP_X264_CFLAGS)
|
||||||
|
XRDP_EXTRA_LIBS += $(XRDP_X264_LIBS)
|
||||||
|
XRDP_EXTRA_SOURCES += xrdp_encoder_x264.c xrdp_encoder_x264.h
|
||||||
|
endif
|
||||||
|
|
||||||
if XRDP_PIXMAN
|
if XRDP_PIXMAN
|
||||||
AM_CPPFLAGS += -DXRDP_PIXMAN
|
AM_CPPFLAGS += -DXRDP_PIXMAN
|
||||||
AM_CPPFLAGS += $(PIXMAN_CFLAGS)
|
AM_CPPFLAGS += $(PIXMAN_CFLAGS)
|
||||||
@ -46,6 +54,7 @@ xrdp_SOURCES = \
|
|||||||
lang.c \
|
lang.c \
|
||||||
xrdp.c \
|
xrdp.c \
|
||||||
xrdp.h \
|
xrdp.h \
|
||||||
|
xrdp.ini.in \
|
||||||
xrdp_bitmap.c \
|
xrdp_bitmap.c \
|
||||||
xrdp_bitmap_load.c \
|
xrdp_bitmap_load.c \
|
||||||
xrdp_bitmap_common.c \
|
xrdp_bitmap_common.c \
|
||||||
@ -63,7 +72,10 @@ xrdp_SOURCES = \
|
|||||||
xrdp_egfx.c \
|
xrdp_egfx.c \
|
||||||
xrdp_egfx.h \
|
xrdp_egfx.h \
|
||||||
xrdp_wm.c \
|
xrdp_wm.c \
|
||||||
xrdp_main_utils.c
|
xrdp_main_utils.c \
|
||||||
|
xrdp_tconfig.c \
|
||||||
|
xrdp_tconfig.h \
|
||||||
|
$(XRDP_EXTRA_SOURCES)
|
||||||
|
|
||||||
xrdp_LDADD = \
|
xrdp_LDADD = \
|
||||||
$(top_builddir)/common/libcommon.la \
|
$(top_builddir)/common/libcommon.la \
|
||||||
@ -93,9 +105,12 @@ SUFFIXES = .in
|
|||||||
$(subst_verbose)$(SUBST_VARS) $< > $@
|
$(subst_verbose)$(SUBST_VARS) $< > $@
|
||||||
|
|
||||||
dist_xrdpsysconf_DATA = \
|
dist_xrdpsysconf_DATA = \
|
||||||
xrdp.ini \
|
gfx.toml \
|
||||||
xrdp_keyboard.ini
|
xrdp_keyboard.ini
|
||||||
|
|
||||||
|
nodist_xrdpsysconf_DATA = \
|
||||||
|
xrdp.ini
|
||||||
|
|
||||||
xrdppkgdatadir=$(datadir)/xrdp
|
xrdppkgdatadir=$(datadir)/xrdp
|
||||||
|
|
||||||
dist_xrdppkgdata_DATA = \
|
dist_xrdppkgdata_DATA = \
|
||||||
@ -110,3 +125,5 @@ dist_xrdppkgdata_DATA = \
|
|||||||
sans-18.fv1 \
|
sans-18.fv1 \
|
||||||
cursor0.cur \
|
cursor0.cur \
|
||||||
cursor1.cur
|
cursor1.cur
|
||||||
|
|
||||||
|
CLEANFILES = $(nodist_xrdpsysconf_DATA)
|
||||||
|
40
xrdp/gfx.toml
Normal file
40
xrdp/gfx.toml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[codec]
|
||||||
|
order = [ "H.264", "RFX" ]
|
||||||
|
|
||||||
|
[x264.default]
|
||||||
|
preset = "ultrafast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
profile = "main" # profile is forced to baseline if preset == ultrafast
|
||||||
|
vbv_max_bitrate = 0
|
||||||
|
vbv_buffer_size = 0
|
||||||
|
fps_num = 24
|
||||||
|
fps_den = 1
|
||||||
|
|
||||||
|
[x264.lan]
|
||||||
|
# inherits default
|
||||||
|
|
||||||
|
[x264.wan]
|
||||||
|
vbv_max_bitrate = 15000
|
||||||
|
vbv_buffer_size = 1500
|
||||||
|
|
||||||
|
[x264.broadband_high]
|
||||||
|
preset = "superfast"
|
||||||
|
vbv_max_bitrate = 8000
|
||||||
|
vbv_buffer_Size = 800
|
||||||
|
|
||||||
|
[x264.satellite]
|
||||||
|
preset = "superfast"
|
||||||
|
vbv_max_bitrate = 5000
|
||||||
|
vbv_buffer_size = 500
|
||||||
|
|
||||||
|
[x264.broadband_low]
|
||||||
|
preset = "veryfast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
vbv_max_bitrate = 1600
|
||||||
|
vbv_buffer_size = 66
|
||||||
|
|
||||||
|
[x264.modem]
|
||||||
|
preset = "fast"
|
||||||
|
tune = "zerolatency"
|
||||||
|
vbv_max_bitrate = 1200
|
||||||
|
vbv_buffer_size = 50
|
@ -53,8 +53,9 @@ print_version(void)
|
|||||||
{
|
{
|
||||||
g_writeln("xrdp %s", PACKAGE_VERSION);
|
g_writeln("xrdp %s", PACKAGE_VERSION);
|
||||||
g_writeln(" A Remote Desktop Protocol Server.");
|
g_writeln(" A Remote Desktop Protocol Server.");
|
||||||
g_writeln(" Copyright (C) 2004-2020 Jay Sorg, "
|
g_writeln(" Copyright (C) 2004-%d Jay Sorg, "
|
||||||
"Neutrino Labs, and all contributors.");
|
"Neutrino Labs, and all contributors.",
|
||||||
|
VERSION_YEAR);
|
||||||
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
||||||
g_writeln("%s", "");
|
g_writeln("%s", "");
|
||||||
|
|
||||||
|
16
xrdp/xrdp.h
16
xrdp/xrdp.h
@ -38,6 +38,14 @@
|
|||||||
#include "xrdp_client_info.h"
|
#include "xrdp_client_info.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#if defined(XRDP_X264) || defined(XRDP_OPENH264) || defined(XRDP_NVENC)
|
||||||
|
#if !defined(XRDP_H264)
|
||||||
|
#define XRDP_H264 1
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#undef XRDP_H264
|
||||||
|
#endif
|
||||||
|
|
||||||
/* xrdp.c */
|
/* xrdp.c */
|
||||||
long
|
long
|
||||||
g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
|
g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
|
||||||
@ -502,6 +510,9 @@ int
|
|||||||
xrdp_mm_check_wait_objs(struct xrdp_mm *self);
|
xrdp_mm_check_wait_objs(struct xrdp_mm *self);
|
||||||
int
|
int
|
||||||
xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id);
|
xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id);
|
||||||
|
void
|
||||||
|
xrdp_mm_efgx_add_dirty_region_to_planar_list(struct xrdp_mm *self,
|
||||||
|
struct xrdp_region *dirty_region);
|
||||||
int
|
int
|
||||||
xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,
|
xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,
|
||||||
struct xrdp_bitmap *bitmap,
|
struct xrdp_bitmap *bitmap,
|
||||||
@ -591,7 +602,10 @@ server_draw_text(struct xrdp_mod *mod, int font,
|
|||||||
int box_right, int box_bottom,
|
int box_right, int box_bottom,
|
||||||
int x, int y, char *data, int data_len);
|
int x, int y, char *data, int data_len);
|
||||||
int
|
int
|
||||||
server_reset(struct xrdp_mod *mod, int width, int height, int bpp);
|
client_monitor_resize(struct xrdp_mod *mod, int width, int height,
|
||||||
|
int num_monitors, const struct monitor_info *monitors);
|
||||||
|
int
|
||||||
|
server_monitor_resize_done(struct xrdp_mod *mod);
|
||||||
int
|
int
|
||||||
is_channel_allowed(struct xrdp_wm *wm, int channel_id);
|
is_channel_allowed(struct xrdp_wm *wm, int channel_id);
|
||||||
int
|
int
|
||||||
|
@ -35,7 +35,10 @@ tcp_nodelay=true
|
|||||||
; if the network connection disappear without close messages the connection will be closed
|
; if the network connection disappear without close messages the connection will be closed
|
||||||
tcp_keepalive=true
|
tcp_keepalive=true
|
||||||
|
|
||||||
; set tcp send/recv buffer (for experts)
|
; set tcp send/recv buffer
|
||||||
|
; These parameters are largely historic. On systems with dynamic TCP
|
||||||
|
; buffer sizes, setting them manually will either impact performance or
|
||||||
|
; waste memory
|
||||||
#tcp_send_buffer_bytes=32768
|
#tcp_send_buffer_bytes=32768
|
||||||
#tcp_recv_buffer_bytes=32768
|
#tcp_recv_buffer_bytes=32768
|
||||||
|
|
||||||
@ -85,7 +88,8 @@ max_bpp=32
|
|||||||
new_cursors=true
|
new_cursors=true
|
||||||
; fastpath - can be 'input', 'output', 'both', 'none'
|
; fastpath - can be 'input', 'output', 'both', 'none'
|
||||||
use_fastpath=both
|
use_fastpath=both
|
||||||
; when true, userid/password *must* be passed on cmd line
|
; when true, userid/password *must* be passed on cmd line. If the password
|
||||||
|
; is incorrect, the login will fail
|
||||||
#require_credentials=true
|
#require_credentials=true
|
||||||
; when true, the userid will be used to try to authenticate
|
; when true, the userid will be used to try to authenticate
|
||||||
#enable_token_login=true
|
#enable_token_login=true
|
||||||
@ -219,7 +223,6 @@ drdynvc=true
|
|||||||
cliprdr=true
|
cliprdr=true
|
||||||
rail=true
|
rail=true
|
||||||
xrdpvr=true
|
xrdpvr=true
|
||||||
tcutils=true
|
|
||||||
|
|
||||||
; for debugging xrdp, in section xrdp1, change port=-1 to this:
|
; for debugging xrdp, in section xrdp1, change port=-1 to this:
|
||||||
#port=/tmp/.xrdp/xrdp_display_10
|
#port=/tmp/.xrdp/xrdp_display_10
|
||||||
|
@ -301,8 +301,6 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->width = width;
|
|
||||||
self->height = height;
|
|
||||||
Bpp = 4;
|
Bpp = 4;
|
||||||
|
|
||||||
switch (self->bpp)
|
switch (self->bpp)
|
||||||
@ -318,8 +316,28 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(self->data);
|
/* To prevent valgrind errors (particularly on a screen resize),
|
||||||
self->data = (char *)g_malloc(width * height * Bpp, 0);
|
clear extra memory */
|
||||||
|
unsigned long old_size = self->width * self->height * Bpp;
|
||||||
|
unsigned long new_size = width * height * Bpp;
|
||||||
|
|
||||||
|
char *new_data = (char *)realloc(self->data, new_size);
|
||||||
|
if (new_data == NULL)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->width = width;
|
||||||
|
self->height = height;
|
||||||
|
if (new_data != self->data)
|
||||||
|
{
|
||||||
|
self->data = new_data;
|
||||||
|
memset(self->data, 0, new_size);
|
||||||
|
}
|
||||||
|
else if (new_size > old_size)
|
||||||
|
{
|
||||||
|
memset(self->data + old_size, 0, new_size - old_size);
|
||||||
|
}
|
||||||
self->line_size = width * Bpp;
|
self->line_size = width * Bpp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -392,8 +392,11 @@ xrdp_egfx_send_frame_start(struct xrdp_egfx *egfx, int frame_id, int timestamp)
|
|||||||
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_start:");
|
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_start:");
|
||||||
s = xrdp_egfx_frame_start(egfx->bulk, frame_id, timestamp);
|
s = xrdp_egfx_frame_start(egfx->bulk, frame_id, timestamp);
|
||||||
error = xrdp_egfx_send_s(egfx, s);
|
error = xrdp_egfx_send_s(egfx, s);
|
||||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s "
|
if (error != 0)
|
||||||
"error %d", error);
|
{
|
||||||
|
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s "
|
||||||
|
"error %d", error);
|
||||||
|
}
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -434,8 +437,11 @@ xrdp_egfx_send_frame_end(struct xrdp_egfx *egfx, int frame_id)
|
|||||||
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_end:");
|
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_end:");
|
||||||
s = xrdp_egfx_frame_end(egfx->bulk, frame_id);
|
s = xrdp_egfx_frame_end(egfx->bulk, frame_id);
|
||||||
error = xrdp_egfx_send_s(egfx, s);
|
error = xrdp_egfx_send_s(egfx, s);
|
||||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s "
|
if (error != 0)
|
||||||
"error %d", error);
|
{
|
||||||
|
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s "
|
||||||
|
"error %d", error);
|
||||||
|
}
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -769,7 +775,7 @@ xrdp_egfx_process_frame_ack(struct xrdp_egfx *egfx, struct stream *s)
|
|||||||
in_uint32_le(s, queueDepth);
|
in_uint32_le(s, queueDepth);
|
||||||
in_uint32_le(s, intframeId);
|
in_uint32_le(s, intframeId);
|
||||||
in_uint32_le(s, totalFramesDecoded);
|
in_uint32_le(s, totalFramesDecoded);
|
||||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process_frame_ack: queueDepth %d"
|
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process_frame_ack: queueDepth %d"
|
||||||
" intframeId %d totalFramesDecoded %d",
|
" intframeId %d totalFramesDecoded %d",
|
||||||
queueDepth, intframeId, totalFramesDecoded);
|
queueDepth, intframeId, totalFramesDecoded);
|
||||||
if (egfx->frame_ack != NULL)
|
if (egfx->frame_ack != NULL)
|
||||||
@ -869,7 +875,7 @@ xrdp_egfx_process(struct xrdp_egfx *egfx, struct stream *s)
|
|||||||
in_uint16_le(s, flags);
|
in_uint16_le(s, flags);
|
||||||
in_uint32_le(s, pduLength);
|
in_uint32_le(s, pduLength);
|
||||||
s->end = holdp + pduLength;
|
s->end = holdp + pduLength;
|
||||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process: cmdId 0x%x flags %d"
|
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process: cmdId 0x%x flags %d"
|
||||||
" pduLength %d", cmdId, flags, pduLength);
|
" pduLength %d", cmdId, flags, pduLength);
|
||||||
if (pduLength < 8)
|
if (pduLength < 8)
|
||||||
{
|
{
|
||||||
@ -1121,6 +1127,10 @@ xrdp_egfx_shutdown_close_connection(struct xrdp_egfx *egfx)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore any messages we haven't processed yet
|
||||||
|
egfx->caps_advertise = NULL;
|
||||||
|
egfx->frame_ack = NULL;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +222,10 @@ xrdp_egfx_send_wire_to_surface2(struct xrdp_egfx *egfx, int surface_id,
|
|||||||
int codec_id, int codec_context_id,
|
int codec_id, int codec_context_id,
|
||||||
int pixel_format,
|
int pixel_format,
|
||||||
void *bitmap_data, int bitmap_data_length);
|
void *bitmap_data, int bitmap_data_length);
|
||||||
|
/*
|
||||||
|
* NB: mi below must be such that the (top,left) co-ordinate of
|
||||||
|
* the primary monitor is (0.0)
|
||||||
|
*/
|
||||||
struct stream *
|
struct stream *
|
||||||
xrdp_egfx_reset_graphics(struct xrdp_egfx_bulk *bulk, int width, int height,
|
xrdp_egfx_reset_graphics(struct xrdp_egfx_bulk *bulk, int width, int height,
|
||||||
int monitor_count, struct monitor_info *mi);
|
int monitor_count, struct monitor_info *mi);
|
||||||
|
@ -28,21 +28,55 @@
|
|||||||
#include "thread_calls.h"
|
#include "thread_calls.h"
|
||||||
#include "fifo.h"
|
#include "fifo.h"
|
||||||
#include "xrdp_egfx.h"
|
#include "xrdp_egfx.h"
|
||||||
|
#include "string_calls.h"
|
||||||
|
|
||||||
#ifdef XRDP_RFXCODEC
|
#ifdef XRDP_RFXCODEC
|
||||||
#include "rfxcodec_encode.h"
|
#include "rfxcodec_encode.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef XRDP_X264
|
||||||
|
#include "xrdp_encoder_x264.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT 2
|
||||||
|
/* limits used for validate env var XRDP_GFX_FRAMES_IN_FLIGHT */
|
||||||
|
#define MIN_XRDP_GFX_FRAMES_IN_FLIGHT 1
|
||||||
|
#define MAX_XRDP_GFX_FRAMES_IN_FLIGHT 16
|
||||||
|
|
||||||
|
#define DEFAULT_XRDP_GFX_MAX_COMPRESSED_BYTES (3 * 1024 * 1024)
|
||||||
|
/* limits used for validate env var XRDP_GFX_MAX_COMPRESSED_BYTES */
|
||||||
|
#define MIN_XRDP_GFX_MAX_COMPRESSED_BYTES (64 * 1024)
|
||||||
|
#define MAX_XRDP_GFX_MAX_COMPRESSED_BYTES (256 * 1024 * 1024)
|
||||||
|
|
||||||
#define XRDP_SURCMD_PREFIX_BYTES 256
|
#define XRDP_SURCMD_PREFIX_BYTES 256
|
||||||
#define OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024)
|
#define OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024)
|
||||||
|
|
||||||
#ifdef XRDP_RFXCODEC
|
#ifdef XRDP_RFXCODEC
|
||||||
/* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1 todo check this */
|
/*
|
||||||
static const unsigned char g_rfx_quantization_values[] =
|
* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1
|
||||||
|
* https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdprfx/3e9c8af4-7539-4c9d-95de-14b1558b902c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* standard quality */
|
||||||
|
static const unsigned char g_rfx_quantization_values_std[] =
|
||||||
{
|
{
|
||||||
0x66, 0x66, 0x77, 0x87, 0x98,
|
0x66, 0x66, 0x77, 0x87, 0x98,
|
||||||
0x76, 0x77, 0x88, 0x98, 0x99
|
0x76, 0x77, 0x88, 0x98, 0x99
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* low quality */
|
||||||
|
static const unsigned char g_rfx_quantization_values_lq[] =
|
||||||
|
{
|
||||||
|
0x66, 0x66, 0x77, 0x87, 0x98,
|
||||||
|
0xAA, 0xAA, 0xAA, 0xAA, 0xAA /* TODO: tentative value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ultra low quality */
|
||||||
|
static const unsigned char g_rfx_quantization_values_ulq[] =
|
||||||
|
{
|
||||||
|
0x66, 0x66, 0x77, 0x87, 0x98,
|
||||||
|
0xBB, 0xBB, 0xBB, 0xBB, 0xBB /* TODO: tentative value */
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct enc_rect
|
struct enc_rect
|
||||||
@ -59,11 +93,13 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
|||||||
#ifdef XRDP_RFXCODEC
|
#ifdef XRDP_RFXCODEC
|
||||||
static int
|
static int
|
||||||
process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
||||||
static int
|
|
||||||
process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef XRDP_X264
|
||||||
static int
|
static int
|
||||||
process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
||||||
|
#endif
|
||||||
|
static int
|
||||||
|
process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Item destructor for self->fifo_to_proc */
|
/* Item destructor for self->fifo_to_proc */
|
||||||
@ -71,8 +107,15 @@ static void
|
|||||||
xrdp_enc_data_destructor(void *item, void *closure)
|
xrdp_enc_data_destructor(void *item, void *closure)
|
||||||
{
|
{
|
||||||
XRDP_ENC_DATA *enc = (XRDP_ENC_DATA *)item;
|
XRDP_ENC_DATA *enc = (XRDP_ENC_DATA *)item;
|
||||||
g_free(enc->u.sc.drects);
|
if (ENC_IS_BIT_SET(enc->flags, ENC_FLAGS_GFX_BIT))
|
||||||
g_free(enc->u.sc.crects);
|
{
|
||||||
|
g_free(enc->u.gfx.cmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free(enc->u.sc.drects);
|
||||||
|
g_free(enc->u.sc.crects);
|
||||||
|
}
|
||||||
g_free(enc);
|
g_free(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,53 +160,80 @@ xrdp_encoder_create(struct xrdp_mm *mm)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
self->mm = mm;
|
self->mm = mm;
|
||||||
|
self->process_enc = process_enc_egfx;
|
||||||
if (client_info->jpeg_codec_id != 0)
|
if (client_info->jpeg_codec_id != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session");
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session");
|
||||||
self->codec_id = client_info->jpeg_codec_id;
|
self->codec_id = client_info->jpeg_codec_id;
|
||||||
self->in_codec_mode = 1;
|
self->in_codec_mode = 1;
|
||||||
self->codec_quality = client_info->jpeg_prop[0];
|
self->codec_quality = client_info->jpeg_prop[0];
|
||||||
client_info->capture_code = 0;
|
client_info->capture_code = CC_SIMPLE;
|
||||||
client_info->capture_format = XRDP_a8b8g8r8;
|
client_info->capture_format = XRDP_a8b8g8r8;
|
||||||
self->process_enc = process_enc_jpg;
|
self->process_enc = process_enc_jpg;
|
||||||
}
|
}
|
||||||
|
#ifdef XRDP_X264
|
||||||
|
else if (mm->egfx_flags & XRDP_EGFX_H264)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO,
|
||||||
|
"xrdp_encoder_create: starting h264 codec session gfx");
|
||||||
|
self->in_codec_mode = 1;
|
||||||
|
client_info->capture_code = CC_GFX_A2;
|
||||||
|
client_info->capture_format = XRDP_nv12_709fr;
|
||||||
|
self->gfx = 1;
|
||||||
|
}
|
||||||
|
else if (client_info->h264_codec_id != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session");
|
||||||
|
self->codec_id = client_info->h264_codec_id;
|
||||||
|
self->in_codec_mode = 1;
|
||||||
|
client_info->capture_code = CC_SUF_A2;
|
||||||
|
client_info->capture_format = XRDP_nv12;
|
||||||
|
self->process_enc = process_enc_h264;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef XRDP_RFXCODEC
|
#ifdef XRDP_RFXCODEC
|
||||||
else if (mm->egfx_flags & XRDP_EGFX_RFX_PRO)
|
else if (mm->egfx_flags & XRDP_EGFX_RFX_PRO)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_INFO,
|
LOG(LOG_LEVEL_INFO,
|
||||||
"xrdp_encoder_create: starting gfx rfx pro codec session");
|
"xrdp_encoder_create: starting gfx rfx pro codec session");
|
||||||
self->in_codec_mode = 1;
|
self->in_codec_mode = 1;
|
||||||
client_info->capture_code = 4;
|
client_info->capture_code = CC_GFX_PRO;
|
||||||
self->process_enc = process_enc_egfx;
|
|
||||||
self->gfx = 1;
|
self->gfx = 1;
|
||||||
self->quants = (const char *) g_rfx_quantization_values;
|
|
||||||
self->num_quants = 2;
|
self->num_quants = 2;
|
||||||
self->quant_idx_y = 0;
|
self->quant_idx_y = 0;
|
||||||
self->quant_idx_u = 1;
|
self->quant_idx_u = 1;
|
||||||
self->quant_idx_v = 1;
|
self->quant_idx_v = 1;
|
||||||
|
|
||||||
|
switch (client_info->mcs_connection_type)
|
||||||
|
{
|
||||||
|
case CONNECTION_TYPE_MODEM:
|
||||||
|
case CONNECTION_TYPE_BROADBAND_LOW:
|
||||||
|
case CONNECTION_TYPE_SATELLITE:
|
||||||
|
self->quants = (const char *) g_rfx_quantization_values_ulq;
|
||||||
|
break;
|
||||||
|
case CONNECTION_TYPE_BROADBAND_HIGH:
|
||||||
|
case CONNECTION_TYPE_WAN:
|
||||||
|
self->quants = (const char *) g_rfx_quantization_values_lq;
|
||||||
|
break;
|
||||||
|
case CONNECTION_TYPE_LAN:
|
||||||
|
case CONNECTION_TYPE_AUTODETECT: /* not implemented yet */
|
||||||
|
default:
|
||||||
|
self->quants = (const char *) g_rfx_quantization_values_std;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (client_info->rfx_codec_id != 0)
|
else if (client_info->rfx_codec_id != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session");
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session");
|
||||||
self->codec_id = client_info->rfx_codec_id;
|
self->codec_id = client_info->rfx_codec_id;
|
||||||
self->in_codec_mode = 1;
|
self->in_codec_mode = 1;
|
||||||
client_info->capture_code = 2;
|
client_info->capture_code = CC_SUF_RFX;
|
||||||
self->process_enc = process_enc_rfx;
|
self->process_enc = process_enc_rfx;
|
||||||
self->codec_handle_rfx = rfxcodec_encode_create(mm->wm->screen->width,
|
self->codec_handle_rfx = rfxcodec_encode_create(mm->wm->screen->width,
|
||||||
mm->wm->screen->height,
|
mm->wm->screen->height,
|
||||||
RFX_FORMAT_YUV, 0);
|
RFX_FORMAT_YUV, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (client_info->h264_codec_id != 0)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session");
|
|
||||||
self->codec_id = client_info->h264_codec_id;
|
|
||||||
self->in_codec_mode = 1;
|
|
||||||
client_info->capture_code = 3;
|
|
||||||
client_info->capture_format = XRDP_nv12;
|
|
||||||
self->process_enc = process_enc_h264;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_free(self);
|
g_free(self);
|
||||||
@ -186,12 +256,50 @@ xrdp_encoder_create(struct xrdp_mm *mm)
|
|||||||
g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_event_processed", pid);
|
g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_event_processed", pid);
|
||||||
self->xrdp_encoder_event_processed = g_create_wait_obj(buf);
|
self->xrdp_encoder_event_processed = g_create_wait_obj(buf);
|
||||||
g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_term", pid);
|
g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_term", pid);
|
||||||
self->xrdp_encoder_term = g_create_wait_obj(buf);
|
self->xrdp_encoder_term_request = g_create_wait_obj(buf);
|
||||||
|
self->xrdp_encoder_term_done = g_create_wait_obj(buf);
|
||||||
if (client_info->gfx)
|
if (client_info->gfx)
|
||||||
{
|
{
|
||||||
// Magic numbers... Why?
|
const char *env_var = g_getenv("XRDP_GFX_FRAMES_IN_FLIGHT");
|
||||||
self->frames_in_flight = 2;
|
self->frames_in_flight = DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT;
|
||||||
self->max_compressed_bytes = 3145728;
|
if (env_var != NULL)
|
||||||
|
{
|
||||||
|
int fif = g_atoix(env_var);
|
||||||
|
if (fif >= MIN_XRDP_GFX_FRAMES_IN_FLIGHT &&
|
||||||
|
fif <= MAX_XRDP_GFX_FRAMES_IN_FLIGHT)
|
||||||
|
{
|
||||||
|
self->frames_in_flight = fif;
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||||
|
"XRDP_GFX_FRAMES_IN_FLIGHT set to %d", fif);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||||
|
"XRDP_GFX_FRAMES_IN_FLIGHT set but invalid %s",
|
||||||
|
env_var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env_var = g_getenv("XRDP_GFX_MAX_COMPRESSED_BYTES");
|
||||||
|
self->max_compressed_bytes = DEFAULT_XRDP_GFX_MAX_COMPRESSED_BYTES;
|
||||||
|
if (env_var != NULL)
|
||||||
|
{
|
||||||
|
int mcb = g_atoix(env_var);
|
||||||
|
if (mcb >= MIN_XRDP_GFX_MAX_COMPRESSED_BYTES &&
|
||||||
|
mcb <= MAX_XRDP_GFX_MAX_COMPRESSED_BYTES)
|
||||||
|
{
|
||||||
|
self->max_compressed_bytes = mcb;
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||||
|
"XRDP_GFX_MAX_COMPRESSED_BYTES set to %d", mcb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
|
||||||
|
"XRDP_GFX_MAX_COMPRESSED_BYTES set but invalid %s",
|
||||||
|
env_var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_DEVEL(LOG_LEVEL_INFO, "Using %d max_compressed_bytes for encoder",
|
||||||
|
self->max_compressed_bytes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -225,8 +333,12 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* tell worker thread to shut down */
|
/* tell worker thread to shut down */
|
||||||
g_set_wait_obj(self->xrdp_encoder_term);
|
g_set_wait_obj(self->xrdp_encoder_term_request);
|
||||||
g_sleep(1000);
|
g_obj_wait(&self->xrdp_encoder_term_done, 1, NULL, 0, 5000);
|
||||||
|
if (!g_is_wait_obj_set(self->xrdp_encoder_term_done))
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Encoder failed to shut down cleanly");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef XRDP_RFXCODEC
|
#ifdef XRDP_RFXCODEC
|
||||||
for (index = 0; index < 16; index++)
|
for (index = 0; index < 16; index++)
|
||||||
@ -247,7 +359,7 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
|
|||||||
{
|
{
|
||||||
if (self->codec_handle_h264_gfx[index] != NULL)
|
if (self->codec_handle_h264_gfx[index] != NULL)
|
||||||
{
|
{
|
||||||
rfxcodec_encode_destroy(self->codec_handle_h264_gfx[index]);
|
xrdp_encoder_x264_delete(self->codec_handle_h264_gfx[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self->codec_handle_h264 != NULL)
|
if (self->codec_handle_h264 != NULL)
|
||||||
@ -259,7 +371,8 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
|
|||||||
/* destroy wait objects used for signalling */
|
/* destroy wait objects used for signalling */
|
||||||
g_delete_wait_obj(self->xrdp_encoder_event_to_proc);
|
g_delete_wait_obj(self->xrdp_encoder_event_to_proc);
|
||||||
g_delete_wait_obj(self->xrdp_encoder_event_processed);
|
g_delete_wait_obj(self->xrdp_encoder_event_processed);
|
||||||
g_delete_wait_obj(self->xrdp_encoder_term);
|
g_delete_wait_obj(self->xrdp_encoder_term_request);
|
||||||
|
g_delete_wait_obj(self->xrdp_encoder_term_done);
|
||||||
|
|
||||||
/* cleanup fifos */
|
/* cleanup fifos */
|
||||||
fifo_delete(self->fifo_to_proc, NULL);
|
fifo_delete(self->fifo_to_proc, NULL);
|
||||||
@ -515,6 +628,61 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(XRDP_X264)
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static int
|
||||||
|
out_RFX_AVC420_METABLOCK(struct xrdp_egfx_rect *dst_rect,
|
||||||
|
struct stream *s,
|
||||||
|
struct xrdp_egfx_rect *rects,
|
||||||
|
int num_rects)
|
||||||
|
{
|
||||||
|
struct xrdp_region *reg;
|
||||||
|
struct xrdp_rect rect;
|
||||||
|
int index;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/* RFX_AVC420_METABLOCK */
|
||||||
|
s_push_layer(s, iso_hdr, 4); /* numRegionRects, set later */
|
||||||
|
reg = xrdp_region_create(NULL);
|
||||||
|
if (reg == NULL)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (index = 0; index < num_rects; index++)
|
||||||
|
{
|
||||||
|
rect.left = MAX(0, rects[index].x1 - dst_rect->x1 - 1);
|
||||||
|
rect.top = MAX(0, rects[index].y1 - dst_rect->y1 - 1);
|
||||||
|
rect.right = MIN(dst_rect->x2 - dst_rect->x1,
|
||||||
|
rects[index].x2 - dst_rect->x1 + 1);
|
||||||
|
rect.bottom = MIN(dst_rect->y2 - dst_rect->y1,
|
||||||
|
rects[index].y2 - dst_rect->y1 + 1);
|
||||||
|
xrdp_region_add_rect(reg, &rect);
|
||||||
|
}
|
||||||
|
index = 0;
|
||||||
|
while (xrdp_region_get_rect(reg, index, &rect) == 0)
|
||||||
|
{
|
||||||
|
out_uint16_le(s, rect.left);
|
||||||
|
out_uint16_le(s, rect.top);
|
||||||
|
out_uint16_le(s, rect.right);
|
||||||
|
out_uint16_le(s, rect.bottom);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
xrdp_region_delete(reg);
|
||||||
|
count = index;
|
||||||
|
while (index > 0)
|
||||||
|
{
|
||||||
|
out_uint8(s, 23); /* qp */
|
||||||
|
out_uint8(s, 100); /* quality level 0..100 */
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
s_push_layer(s, mcs_hdr, 0);
|
||||||
|
s_pop_layer(s, iso_hdr);
|
||||||
|
out_uint32_le(s, count); /* numRegionRects */
|
||||||
|
s_pop_layer(s, mcs_hdr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* called from encoder thread */
|
/* called from encoder thread */
|
||||||
static int
|
static int
|
||||||
@ -524,27 +692,267 @@ process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XRDP_RFXCODEC
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static int
|
||||||
|
gfx_send_done(struct xrdp_encoder *self, XRDP_ENC_DATA *enc,
|
||||||
|
int comp_bytes, int pad_bytes, char *comp_pad_data,
|
||||||
|
int got_frame_id, int frame_id, int is_last)
|
||||||
|
|
||||||
|
{
|
||||||
|
XRDP_ENC_DATA_DONE *enc_done;
|
||||||
|
|
||||||
|
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
|
||||||
|
if (enc_done == NULL)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT);
|
||||||
|
enc_done->enc = enc;
|
||||||
|
enc_done->last = is_last;
|
||||||
|
enc_done->pad_bytes = pad_bytes;
|
||||||
|
enc_done->comp_bytes = comp_bytes;
|
||||||
|
enc_done->comp_pad_data = comp_pad_data;
|
||||||
|
if (got_frame_id)
|
||||||
|
{
|
||||||
|
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
|
||||||
|
enc_done->frame_id = frame_id;
|
||||||
|
}
|
||||||
|
/* inform main thread done */
|
||||||
|
tc_mutex_lock(self->mutex);
|
||||||
|
fifo_add_item(self->fifo_processed, enc_done);
|
||||||
|
tc_mutex_unlock(self->mutex);
|
||||||
|
/* signal completion for main thread */
|
||||||
|
g_set_wait_obj(self->xrdp_encoder_event_processed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
static struct stream *
|
static struct stream *
|
||||||
gfx_wiretosurface1(struct xrdp_encoder *self,
|
gfx_wiretosurface1(struct xrdp_encoder *self,
|
||||||
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
|
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
|
||||||
struct xrdp_enc_gfx_cmd *enc_gfx_cmd)
|
XRDP_ENC_DATA *enc)
|
||||||
{
|
{
|
||||||
|
#ifdef XRDP_X264
|
||||||
|
int index;
|
||||||
|
int surface_id;
|
||||||
|
int codec_id;
|
||||||
|
int pixel_format;
|
||||||
|
int num_rects_d;
|
||||||
|
int num_rects_c;
|
||||||
|
struct stream *rv;
|
||||||
|
short left;
|
||||||
|
short top;
|
||||||
|
short width;
|
||||||
|
short height;
|
||||||
|
short twidth;
|
||||||
|
short theight;
|
||||||
|
int bitmap_data_length;
|
||||||
|
int flags;
|
||||||
|
struct xrdp_egfx_rect *d_rects;
|
||||||
|
struct xrdp_egfx_rect *c_rects;
|
||||||
|
struct xrdp_egfx_rect dst_rect;
|
||||||
|
int error;
|
||||||
|
struct stream ls;
|
||||||
|
struct stream *s;
|
||||||
|
short *crects;
|
||||||
|
struct xrdp_enc_gfx_cmd *enc_gfx_cmd = &(enc->u.gfx);
|
||||||
|
int mon_index;
|
||||||
|
int connection_type;
|
||||||
|
|
||||||
|
connection_type = self->mm->wm->client_info->mcs_connection_type;
|
||||||
|
|
||||||
|
s = &ls;
|
||||||
|
g_memset(s, 0, sizeof(struct stream));
|
||||||
|
s->size = self->max_compressed_bytes;
|
||||||
|
s->data = g_new(char, s->size);
|
||||||
|
if (s->data == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
s->p = s->data;
|
||||||
|
if (!s_check_rem(in_s, 11))
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
in_uint16_le(in_s, surface_id);
|
||||||
|
in_uint16_le(in_s, codec_id);
|
||||||
|
in_uint8(in_s, pixel_format);
|
||||||
|
in_uint32_le(in_s, flags);
|
||||||
|
mon_index = (flags >> 28) & 0xF;
|
||||||
|
in_uint16_le(in_s, num_rects_d);
|
||||||
|
if ((num_rects_d < 1) || (num_rects_d > 16 * 1024) ||
|
||||||
|
(!s_check_rem(in_s, num_rects_d * 8)))
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
d_rects = g_new0(struct xrdp_egfx_rect, num_rects_d);
|
||||||
|
if (d_rects == NULL)
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (index = 0; index < num_rects_d; index++)
|
||||||
|
{
|
||||||
|
in_uint16_le(in_s, left);
|
||||||
|
in_uint16_le(in_s, top);
|
||||||
|
in_uint16_le(in_s, width);
|
||||||
|
in_uint16_le(in_s, height);
|
||||||
|
d_rects[index].x1 = left;
|
||||||
|
d_rects[index].y1 = top;
|
||||||
|
d_rects[index].x2 = left + width;
|
||||||
|
d_rects[index].y2 = top + height;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!s_check_rem(in_s, 2))
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(d_rects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
in_uint16_le(in_s, num_rects_c);
|
||||||
|
if ((num_rects_c < 1) || (num_rects_c > 16 * 1024) ||
|
||||||
|
(!s_check_rem(in_s, num_rects_c * 8)))
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(d_rects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
c_rects = g_new0(struct xrdp_egfx_rect, num_rects_c);
|
||||||
|
if (c_rects == NULL)
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(d_rects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
crects = g_new(short, num_rects_c * 4);
|
||||||
|
if (crects == NULL)
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(c_rects);
|
||||||
|
g_free(d_rects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
g_memcpy(crects, in_s->p, num_rects_c * 2 * 4);
|
||||||
|
for (index = 0; index < num_rects_c; index++)
|
||||||
|
{
|
||||||
|
in_uint16_le(in_s, left);
|
||||||
|
in_uint16_le(in_s, top);
|
||||||
|
in_uint16_le(in_s, width);
|
||||||
|
in_uint16_le(in_s, height);
|
||||||
|
c_rects[index].x1 = left;
|
||||||
|
c_rects[index].y1 = top;
|
||||||
|
c_rects[index].x2 = left + width;
|
||||||
|
c_rects[index].y2 = top + height;
|
||||||
|
}
|
||||||
|
if (!s_check_rem(in_s, 8))
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(c_rects);
|
||||||
|
g_free(d_rects);
|
||||||
|
g_free(crects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
in_uint16_le(in_s, left);
|
||||||
|
in_uint16_le(in_s, top);
|
||||||
|
in_uint16_le(in_s, width);
|
||||||
|
in_uint16_le(in_s, height);
|
||||||
|
twidth = width;
|
||||||
|
theight = height;
|
||||||
|
dst_rect.x1 = 0;
|
||||||
|
dst_rect.y1 = 0;
|
||||||
|
dst_rect.x2 = width;
|
||||||
|
dst_rect.y2 = height;
|
||||||
|
LOG_DEVEL(LOG_LEVEL_INFO, "gfx_wiretosurface1: left %d top "
|
||||||
|
"%d width %d height %d mon_index %d",
|
||||||
|
left, top, width, height, mon_index);
|
||||||
|
/* RFX_AVC420_METABLOCK */
|
||||||
|
if (out_RFX_AVC420_METABLOCK(&dst_rect, s, d_rects, num_rects_d) != 0)
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(c_rects);
|
||||||
|
g_free(d_rects);
|
||||||
|
g_free(crects);
|
||||||
|
LOG(LOG_LEVEL_INFO, "10");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(c_rects);
|
||||||
|
g_free(d_rects);
|
||||||
|
|
||||||
|
if (ENC_IS_BIT_SET(flags, 0))
|
||||||
|
{
|
||||||
|
/* already compressed */
|
||||||
|
out_uint8a(s, enc_gfx_cmd->data, enc_gfx_cmd->data_bytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* assume NV12 format */
|
||||||
|
if (twidth * theight * 3 / 2 > enc_gfx_cmd->data_bytes)
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(crects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
bitmap_data_length = s_rem_out(s);
|
||||||
|
if (self->codec_handle_h264_gfx[mon_index] == NULL)
|
||||||
|
{
|
||||||
|
self->codec_handle_h264_gfx[mon_index] =
|
||||||
|
xrdp_encoder_x264_create();
|
||||||
|
if (self->codec_handle_h264_gfx[mon_index] == NULL)
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(crects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error = xrdp_encoder_x264_encode(
|
||||||
|
self->codec_handle_h264_gfx[mon_index], 0,
|
||||||
|
0, 0,
|
||||||
|
width, height, twidth, theight, 0,
|
||||||
|
enc_gfx_cmd->data,
|
||||||
|
crects, num_rects_c,
|
||||||
|
s->p, &bitmap_data_length,
|
||||||
|
connection_type, NULL);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
xstream_seek(s, bitmap_data_length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(crects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s_mark_end(s);
|
||||||
|
bitmap_data_length = (int) (s->end - s->data);
|
||||||
|
rv = xrdp_egfx_wire_to_surface1(bulk, surface_id,
|
||||||
|
codec_id,
|
||||||
|
pixel_format, &dst_rect,
|
||||||
|
s->data, bitmap_data_length);
|
||||||
|
g_free(s->data);
|
||||||
|
g_free(crects);
|
||||||
|
return rv;
|
||||||
|
#else
|
||||||
(void)self;
|
(void)self;
|
||||||
(void)bulk;
|
(void)bulk;
|
||||||
(void)in_s;
|
(void)in_s;
|
||||||
(void)enc_gfx_cmd;
|
(void)enc;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
static struct stream *
|
static struct stream *
|
||||||
gfx_wiretosurface2(struct xrdp_encoder *self,
|
gfx_wiretosurface2(struct xrdp_encoder *self,
|
||||||
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
|
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
|
||||||
struct xrdp_enc_gfx_cmd *enc_gfx_cmd)
|
XRDP_ENC_DATA *enc)
|
||||||
{
|
{
|
||||||
|
#ifdef XRDP_RFXCODEC
|
||||||
int index;
|
int index;
|
||||||
int surface_id;
|
int surface_id;
|
||||||
int codec_id;
|
int codec_id;
|
||||||
@ -561,10 +969,10 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
|||||||
int bitmap_data_length;
|
int bitmap_data_length;
|
||||||
struct rfx_tile *tiles;
|
struct rfx_tile *tiles;
|
||||||
struct rfx_rect *rfxrects;
|
struct rfx_rect *rfxrects;
|
||||||
|
int tiles_compressed;
|
||||||
int flags;
|
int flags;
|
||||||
|
int total_tiles;
|
||||||
int tiles_written;
|
int tiles_written;
|
||||||
int do_free;
|
|
||||||
int do_send;
|
|
||||||
int mon_index;
|
int mon_index;
|
||||||
|
|
||||||
if (!s_check_rem(in_s, 15))
|
if (!s_check_rem(in_s, 15))
|
||||||
@ -641,6 +1049,9 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
|||||||
in_uint16_le(in_s, top);
|
in_uint16_le(in_s, top);
|
||||||
in_uint16_le(in_s, width);
|
in_uint16_le(in_s, width);
|
||||||
in_uint16_le(in_s, height);
|
in_uint16_le(in_s, height);
|
||||||
|
LOG_DEVEL(LOG_LEVEL_INFO, "gfx_wiretosurface2: left %d top "
|
||||||
|
"%d width %d height %d mon_index %d",
|
||||||
|
left, top, width, height, mon_index);
|
||||||
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
|
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
|
||||||
{
|
{
|
||||||
self->codec_handle_prfx_gfx[mon_index] = rfxcodec_encode_create(
|
self->codec_handle_prfx_gfx[mon_index] = rfxcodec_encode_create(
|
||||||
@ -649,60 +1060,80 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
|||||||
RFX_FORMAT_YUV,
|
RFX_FORMAT_YUV,
|
||||||
RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1);
|
RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1);
|
||||||
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
|
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
do_free = 0;
|
|
||||||
do_send = 0;
|
|
||||||
if (ENC_IS_BIT_SET(flags, 0))
|
|
||||||
{
|
|
||||||
/* already compressed */
|
|
||||||
bitmap_data_length = enc_gfx_cmd->data_bytes;
|
|
||||||
bitmap_data = enc_gfx_cmd->data;
|
|
||||||
do_send = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bitmap_data_length = self->max_compressed_bytes;
|
|
||||||
bitmap_data = g_new(char, bitmap_data_length);
|
|
||||||
if (bitmap_data == NULL)
|
|
||||||
{
|
{
|
||||||
g_free(tiles);
|
g_free(tiles);
|
||||||
g_free(rfxrects);
|
g_free(rfxrects);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
do_free = 1;
|
|
||||||
tiles_written = rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index],
|
|
||||||
bitmap_data,
|
|
||||||
&bitmap_data_length,
|
|
||||||
enc_gfx_cmd->data,
|
|
||||||
width, height,
|
|
||||||
((width + 63) & ~63) * 4,
|
|
||||||
rfxrects, num_rects_d,
|
|
||||||
tiles, num_rects_c,
|
|
||||||
self->quants, self->num_quants);
|
|
||||||
if (tiles_written > 0)
|
|
||||||
{
|
|
||||||
do_send = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g_free(tiles);
|
bitmap_data_length = self->max_compressed_bytes;
|
||||||
g_free(rfxrects);
|
bitmap_data = g_new(char, bitmap_data_length);
|
||||||
rv = NULL;
|
if (bitmap_data == NULL)
|
||||||
if (do_send)
|
|
||||||
{
|
{
|
||||||
|
g_free(tiles);
|
||||||
|
g_free(rfxrects);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rv = NULL;
|
||||||
|
tiles_written = 0;
|
||||||
|
total_tiles = num_rects_c;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
tiles_compressed =
|
||||||
|
rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index],
|
||||||
|
bitmap_data,
|
||||||
|
&bitmap_data_length,
|
||||||
|
enc->u.gfx.data,
|
||||||
|
width, height,
|
||||||
|
((width + 63) & ~63) * 4,
|
||||||
|
rfxrects, num_rects_d,
|
||||||
|
tiles + tiles_written, total_tiles - tiles_written,
|
||||||
|
self->quants, self->num_quants);
|
||||||
|
if (tiles_compressed < 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tiles_written += tiles_compressed;
|
||||||
rv = xrdp_egfx_wire_to_surface2(bulk, surface_id,
|
rv = xrdp_egfx_wire_to_surface2(bulk, surface_id,
|
||||||
codec_id, codec_context_id,
|
codec_id, codec_context_id,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
bitmap_data, bitmap_data_length);
|
bitmap_data, bitmap_data_length);
|
||||||
|
if (rv == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LOG_DEVEL(LOG_LEVEL_ERROR, "gfx_wiretosurface2: "
|
||||||
|
"tiles_compressed %d total_tiles %d tiles_written %d",
|
||||||
|
tiles_compressed, total_tiles,
|
||||||
|
tiles_written);
|
||||||
|
if (tiles_written >= total_tiles)
|
||||||
|
{
|
||||||
|
/* ok, done with last tile set */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* we have another tile set, send this one to main thread */
|
||||||
|
if (gfx_send_done(self, enc, (int)(rv->end - rv->data), 0,
|
||||||
|
rv->data, 0, 0, 0) != 0)
|
||||||
|
{
|
||||||
|
free_stream(rv);
|
||||||
|
rv = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_free(rv); /* don't call free_stream() here so s->data is valid */
|
||||||
|
rv = NULL;
|
||||||
|
bitmap_data_length = self->max_compressed_bytes;
|
||||||
}
|
}
|
||||||
if (do_free)
|
g_free(tiles);
|
||||||
{
|
g_free(rfxrects);
|
||||||
g_free(bitmap_data);
|
g_free(bitmap_data);
|
||||||
}
|
|
||||||
return rv;
|
return rv;
|
||||||
|
#else
|
||||||
|
(void)self;
|
||||||
|
(void)bulk;
|
||||||
|
(void)in_s;
|
||||||
|
(void)enc;
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -902,20 +1333,14 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||||||
struct stream *s;
|
struct stream *s;
|
||||||
struct stream in_s;
|
struct stream in_s;
|
||||||
struct xrdp_egfx_bulk *bulk;
|
struct xrdp_egfx_bulk *bulk;
|
||||||
XRDP_ENC_DATA_DONE *enc_done;
|
|
||||||
struct fifo *fifo_processed;
|
|
||||||
tbus mutex;
|
|
||||||
tbus event_processed;
|
|
||||||
int cmd_id;
|
int cmd_id;
|
||||||
int cmd_bytes;
|
int cmd_bytes;
|
||||||
int frame_id;
|
int frame_id;
|
||||||
int got_frame_id;
|
int got_frame_id;
|
||||||
|
int error;
|
||||||
char *holdp;
|
char *holdp;
|
||||||
char *holdend;
|
char *holdend;
|
||||||
|
|
||||||
fifo_processed = self->fifo_processed;
|
|
||||||
mutex = self->mutex;
|
|
||||||
event_processed = self->xrdp_encoder_event_processed;
|
|
||||||
bulk = self->mm->egfx->bulk;
|
bulk = self->mm->egfx->bulk;
|
||||||
g_memset(&in_s, 0, sizeof(in_s));
|
g_memset(&in_s, 0, sizeof(in_s));
|
||||||
in_s.data = enc->u.gfx.cmd;
|
in_s.data = enc->u.gfx.cmd;
|
||||||
@ -937,13 +1362,14 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||||||
}
|
}
|
||||||
holdend = in_s.end;
|
holdend = in_s.end;
|
||||||
in_s.end = holdp + cmd_bytes;
|
in_s.end = holdp + cmd_bytes;
|
||||||
|
LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_egfx: cmd_id %d", cmd_id);
|
||||||
switch (cmd_id)
|
switch (cmd_id)
|
||||||
{
|
{
|
||||||
case XR_RDPGFX_CMDID_WIRETOSURFACE_1: /* 0x0001 */
|
case XR_RDPGFX_CMDID_WIRETOSURFACE_1: /* 0x0001 */
|
||||||
s = gfx_wiretosurface1(self, bulk, &in_s, &(enc->u.gfx));
|
s = gfx_wiretosurface1(self, bulk, &in_s, enc);
|
||||||
break;
|
break;
|
||||||
case XR_RDPGFX_CMDID_WIRETOSURFACE_2: /* 0x0002 */
|
case XR_RDPGFX_CMDID_WIRETOSURFACE_2: /* 0x0002 */
|
||||||
s = gfx_wiretosurface2(self, bulk, &in_s, &(enc->u.gfx));
|
s = gfx_wiretosurface2(self, bulk, &in_s, enc);
|
||||||
break;
|
break;
|
||||||
case XR_RDPGFX_CMDID_SOLIDFILL: /* 0x0004 */
|
case XR_RDPGFX_CMDID_SOLIDFILL: /* 0x0004 */
|
||||||
s = gfx_solidfill(self, bulk, &in_s);
|
s = gfx_solidfill(self, bulk, &in_s);
|
||||||
@ -973,44 +1399,32 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (s == NULL)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: cmd_id %d s = nil", cmd_id);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* setup for next cmd */
|
/* setup for next cmd */
|
||||||
in_s.p = holdp + cmd_bytes;
|
in_s.p = holdp + cmd_bytes;
|
||||||
in_s.end = holdend;
|
in_s.end = holdend;
|
||||||
/* setup enc_done struct */
|
if (s != NULL)
|
||||||
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
|
|
||||||
if (enc_done == NULL)
|
|
||||||
{
|
{
|
||||||
free_stream(s);
|
/* send message to main thread */
|
||||||
return 1;
|
error = gfx_send_done(self, enc, (int) (s->end - s->data),
|
||||||
|
0, s->data, got_frame_id, frame_id,
|
||||||
|
!s_check_rem(&in_s, 8));
|
||||||
|
if (error != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: gfx_send_done failed "
|
||||||
|
"error %d", error);
|
||||||
|
free_stream(s);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
g_free(s); /* don't call free_stream() here so s->data is valid */
|
||||||
}
|
}
|
||||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT);
|
else
|
||||||
enc_done->enc = enc;
|
|
||||||
enc_done->last = !s_check_rem(&in_s, 8);
|
|
||||||
enc_done->comp_bytes = (int) (s->end - s->data);
|
|
||||||
enc_done->comp_pad_data = s->data;
|
|
||||||
if (got_frame_id)
|
|
||||||
{
|
{
|
||||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
|
LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_egfx: nil");
|
||||||
enc_done->frame_id = frame_id;
|
|
||||||
}
|
}
|
||||||
g_free(s); /* don't call free_stream() here so s->data is valid */
|
|
||||||
/* inform main thread done */
|
|
||||||
tc_mutex_lock(mutex);
|
|
||||||
fifo_add_item(fifo_processed, enc_done);
|
|
||||||
tc_mutex_unlock(mutex);
|
|
||||||
/* signal completion for main thread */
|
|
||||||
g_set_wait_obj(event_processed);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encoder thread main loop
|
* Encoder thread main loop
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@ -1045,7 +1459,7 @@ proc_enc_msg(void *arg)
|
|||||||
event_to_proc = self->xrdp_encoder_event_to_proc;
|
event_to_proc = self->xrdp_encoder_event_to_proc;
|
||||||
|
|
||||||
term_obj = g_get_term();
|
term_obj = g_get_term();
|
||||||
lterm_obj = self->xrdp_encoder_term;
|
lterm_obj = self->xrdp_encoder_term_request;
|
||||||
|
|
||||||
cont = 1;
|
cont = 1;
|
||||||
while (cont)
|
while (cont)
|
||||||
@ -1096,6 +1510,7 @@ proc_enc_msg(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} /* end while (cont) */
|
} /* end while (cont) */
|
||||||
|
g_set_wait_obj(self->xrdp_encoder_term_done);
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "proc_enc_msg: thread exit");
|
LOG_DEVEL(LOG_LEVEL_DEBUG, "proc_enc_msg: thread exit");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ struct xrdp_encoder
|
|||||||
int max_compressed_bytes;
|
int max_compressed_bytes;
|
||||||
tbus xrdp_encoder_event_to_proc;
|
tbus xrdp_encoder_event_to_proc;
|
||||||
tbus xrdp_encoder_event_processed;
|
tbus xrdp_encoder_event_processed;
|
||||||
tbus xrdp_encoder_term;
|
tbus xrdp_encoder_term_request;
|
||||||
|
tbus xrdp_encoder_term_done;
|
||||||
struct fifo *fifo_to_proc;
|
struct fifo *fifo_to_proc;
|
||||||
struct fifo *fifo_processed;
|
struct fifo *fifo_processed;
|
||||||
tbus mutex;
|
tbus mutex;
|
||||||
|
256
xrdp/xrdp_encoder_x264.c
Normal file
256
xrdp/xrdp_encoder_x264.c
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* Copyright (C) Jay Sorg 2016-2024
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* x264 Encoder
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(HAVE_CONFIG_H)
|
||||||
|
#include <config_ac.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <x264.h>
|
||||||
|
|
||||||
|
#include "xrdp.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "os_calls.h"
|
||||||
|
#include "xrdp_encoder_x264.h"
|
||||||
|
#include "xrdp_tconfig.h"
|
||||||
|
|
||||||
|
#define X264_MAX_ENCODERS 16
|
||||||
|
|
||||||
|
struct x264_encoder
|
||||||
|
{
|
||||||
|
x264_t *x264_enc_han;
|
||||||
|
char *yuvdata;
|
||||||
|
x264_param_t x264_params;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct x264_global
|
||||||
|
{
|
||||||
|
struct x264_encoder encoders[X264_MAX_ENCODERS];
|
||||||
|
struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void *
|
||||||
|
xrdp_encoder_x264_create(void)
|
||||||
|
{
|
||||||
|
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_encoder_x264_create:");
|
||||||
|
|
||||||
|
struct x264_global *xg;
|
||||||
|
struct xrdp_tconfig_gfx gfxconfig;
|
||||||
|
xg = g_new0(struct x264_global, 1);
|
||||||
|
tconfig_load_gfx(GFX_CONF, &gfxconfig);
|
||||||
|
|
||||||
|
memcpy(&xg->x264_param, &gfxconfig.x264_param,
|
||||||
|
sizeof(struct xrdp_tconfig_gfx_x264_param) * NUM_CONNECTION_TYPES);
|
||||||
|
|
||||||
|
return xg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
int
|
||||||
|
xrdp_encoder_x264_delete(void *handle)
|
||||||
|
{
|
||||||
|
struct x264_global *xg;
|
||||||
|
struct x264_encoder *xe;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (handle == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
xg = (struct x264_global *) handle;
|
||||||
|
for (index = 0; index < 16; index++)
|
||||||
|
{
|
||||||
|
xe = &(xg->encoders[index]);
|
||||||
|
if (xe->x264_enc_han != NULL)
|
||||||
|
{
|
||||||
|
x264_encoder_close(xe->x264_enc_han);
|
||||||
|
}
|
||||||
|
g_free(xe->yuvdata);
|
||||||
|
}
|
||||||
|
g_free(xg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
int
|
||||||
|
xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
|
||||||
|
int width, int height, int twidth, int theight,
|
||||||
|
int format, const char *data,
|
||||||
|
short *crects, int num_crects,
|
||||||
|
char *cdata, int *cdata_bytes, int connection_type,
|
||||||
|
int *flags_ptr)
|
||||||
|
{
|
||||||
|
struct x264_global *xg;
|
||||||
|
struct x264_encoder *xe;
|
||||||
|
const char *src8;
|
||||||
|
char *dst8;
|
||||||
|
int index;
|
||||||
|
x264_nal_t *nals;
|
||||||
|
int num_nals;
|
||||||
|
int frame_size;
|
||||||
|
int x264_width_height;
|
||||||
|
int flags;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int cx;
|
||||||
|
int cy;
|
||||||
|
int ct; /* connection_type */
|
||||||
|
|
||||||
|
x264_picture_t pic_in;
|
||||||
|
x264_picture_t pic_out;
|
||||||
|
|
||||||
|
LOG(LOG_LEVEL_TRACE, "xrdp_encoder_x264_encode:");
|
||||||
|
flags = 0;
|
||||||
|
xg = (struct x264_global *) handle;
|
||||||
|
xe = &(xg->encoders[session % X264_MAX_ENCODERS]);
|
||||||
|
|
||||||
|
/* validate connection type */
|
||||||
|
ct = connection_type;
|
||||||
|
if (ct > CONNECTION_TYPE_LAN || ct < CONNECTION_TYPE_MODEM)
|
||||||
|
{
|
||||||
|
ct = CONNECTION_TYPE_LAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xe->x264_enc_han == NULL) ||
|
||||||
|
(xe->width != width) || (xe->height != height))
|
||||||
|
{
|
||||||
|
if (xe->x264_enc_han != NULL)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: "
|
||||||
|
"x264_encoder_close %p", xe->x264_enc_han);
|
||||||
|
x264_encoder_close(xe->x264_enc_han);
|
||||||
|
xe->x264_enc_han = NULL;
|
||||||
|
g_free(xe->yuvdata);
|
||||||
|
xe->yuvdata = NULL;
|
||||||
|
flags |= 2;
|
||||||
|
}
|
||||||
|
if ((width > 0) && (height > 0))
|
||||||
|
{
|
||||||
|
x264_param_default_preset(&(xe->x264_params),
|
||||||
|
xg->x264_param[ct].preset,
|
||||||
|
xg->x264_param[ct].tune);
|
||||||
|
xe->x264_params.i_threads = 1;
|
||||||
|
xe->x264_params.i_width = (width + 15) & ~15;
|
||||||
|
xe->x264_params.i_height = (height + 15) & ~15;
|
||||||
|
xe->x264_params.i_fps_num = xg->x264_param[ct].fps_num;
|
||||||
|
xe->x264_params.i_fps_den = xg->x264_param[ct].fps_den;
|
||||||
|
xe->x264_params.rc.i_rc_method = X264_RC_CRF;
|
||||||
|
xe->x264_params.rc.i_vbv_max_bitrate = xg->x264_param[ct].vbv_max_bitrate;
|
||||||
|
xe->x264_params.rc.i_vbv_buffer_size = xg->x264_param[ct].vbv_buffer_size;
|
||||||
|
x264_param_apply_profile(&(xe->x264_params),
|
||||||
|
xg->x264_param[ct].profile);
|
||||||
|
xe->x264_enc_han = x264_encoder_open(&(xe->x264_params));
|
||||||
|
LOG(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: "
|
||||||
|
"x264_encoder_open rv %p for width %d height %d",
|
||||||
|
xe->x264_enc_han, width, height);
|
||||||
|
if (xe->x264_enc_han == NULL)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
xe->yuvdata = g_new(char, width * height * 2);
|
||||||
|
if (xe->yuvdata == NULL)
|
||||||
|
{
|
||||||
|
x264_encoder_close(xe->x264_enc_han);
|
||||||
|
xe->x264_enc_han = NULL;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
flags |= 1;
|
||||||
|
}
|
||||||
|
xe->width = width;
|
||||||
|
xe->height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data != NULL) && (xe->x264_enc_han != NULL))
|
||||||
|
{
|
||||||
|
x264_width_height = xe->x264_params.i_width * xe->x264_params.i_height;
|
||||||
|
for (index = 0; index < num_crects; index++)
|
||||||
|
{
|
||||||
|
src8 = data;
|
||||||
|
dst8 = xe->yuvdata;
|
||||||
|
x = crects[index * 4 + 0];
|
||||||
|
y = crects[index * 4 + 1];
|
||||||
|
cx = crects[index * 4 + 2];
|
||||||
|
cy = crects[index * 4 + 3];
|
||||||
|
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: x %d y %d "
|
||||||
|
"cx %d cy %d", x, y, cx, cy);
|
||||||
|
src8 += twidth * y + x;
|
||||||
|
dst8 += xe->x264_params.i_width * (y - top) + (x - left);
|
||||||
|
for (; cy > 0; cy -= 1)
|
||||||
|
{
|
||||||
|
g_memcpy(dst8, src8, cx);
|
||||||
|
src8 += twidth;
|
||||||
|
dst8 += xe->x264_params.i_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (index = 0; index < num_crects; index++)
|
||||||
|
{
|
||||||
|
src8 = data;
|
||||||
|
src8 += twidth * theight;
|
||||||
|
dst8 = xe->yuvdata;
|
||||||
|
dst8 += x264_width_height;
|
||||||
|
x = crects[index * 4 + 0];
|
||||||
|
y = crects[index * 4 + 1];
|
||||||
|
cx = crects[index * 4 + 2];
|
||||||
|
cy = crects[index * 4 + 3];
|
||||||
|
src8 += twidth * (y / 2) + x;
|
||||||
|
dst8 += xe->x264_params.i_width * ((y - top) / 2) + (x - left);
|
||||||
|
for (; cy > 0; cy -= 2)
|
||||||
|
{
|
||||||
|
g_memcpy(dst8, src8, cx);
|
||||||
|
src8 += twidth;
|
||||||
|
dst8 += xe->x264_params.i_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_memset(&pic_in, 0, sizeof(pic_in));
|
||||||
|
pic_in.img.i_csp = X264_CSP_NV12;
|
||||||
|
pic_in.img.i_plane = 2;
|
||||||
|
pic_in.img.plane[0] = (unsigned char *) (xe->yuvdata);
|
||||||
|
pic_in.img.plane[1] = (unsigned char *)
|
||||||
|
(xe->yuvdata + x264_width_height);
|
||||||
|
pic_in.img.i_stride[0] = xe->x264_params.i_width;
|
||||||
|
pic_in.img.i_stride[1] = xe->x264_params.i_width;
|
||||||
|
num_nals = 0;
|
||||||
|
frame_size = x264_encoder_encode(xe->x264_enc_han, &nals, &num_nals,
|
||||||
|
&pic_in, &pic_out);
|
||||||
|
LOG(LOG_LEVEL_TRACE, "i_type %d", pic_out.i_type);
|
||||||
|
if (frame_size < 1)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (*cdata_bytes < frame_size)
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
g_memcpy(cdata, nals[0].p_payload, frame_size);
|
||||||
|
*cdata_bytes = frame_size;
|
||||||
|
}
|
||||||
|
if (flags_ptr != NULL)
|
||||||
|
{
|
||||||
|
*flags_ptr = flags;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
39
xrdp/xrdp_encoder_x264.h
Normal file
39
xrdp/xrdp_encoder_x264.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* Copyright (C) Jay Sorg 2016-2024
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* libx264 Encoder
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _XRDP_ENCODER_X264_H
|
||||||
|
#define _XRDP_ENCODER_X264_H
|
||||||
|
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
xrdp_encoder_x264_create(void);
|
||||||
|
int
|
||||||
|
xrdp_encoder_x264_delete(void *handle);
|
||||||
|
int
|
||||||
|
xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
|
||||||
|
int width, int height, int twidth, int theight,
|
||||||
|
int format, const char *data,
|
||||||
|
short *crects, int num_crects,
|
||||||
|
char *cdata, int *cdata_bytes, int connection_type,
|
||||||
|
int *flags_ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -86,7 +86,7 @@ rdp_layout_pt=0x00000816
|
|||||||
; <rdp layout name> = <X11 keyboard layout value>
|
; <rdp layout name> = <X11 keyboard layout value>
|
||||||
[default_layouts_map]
|
[default_layouts_map]
|
||||||
rdp_layout_us=us
|
rdp_layout_us=us
|
||||||
rdp_layout_us_dvorak=dvorak
|
rdp_layout_us_dvorak=us(dvorak)
|
||||||
rdp_layout_us_dvp=us(dvp)
|
rdp_layout_us_dvp=us(dvp)
|
||||||
rdp_layout_dk=dk
|
rdp_layout_dk=dk
|
||||||
rdp_layout_de=de
|
rdp_layout_de=de
|
||||||
@ -125,7 +125,7 @@ layouts_map=default_layouts_map
|
|||||||
|
|
||||||
[rdp_layouts_map_mac]
|
[rdp_layouts_map_mac]
|
||||||
rdp_layout_us=us
|
rdp_layout_us=us
|
||||||
rdp_layout_us_dvorak=dvorak
|
rdp_layout_us_dvorak=us(dvorak)
|
||||||
rdp_layout_us_dvp=us(dvp)
|
rdp_layout_us_dvp=us(dvp)
|
||||||
rdp_layout_dk=dk
|
rdp_layout_dk=dk
|
||||||
rdp_layout_de=de
|
rdp_layout_de=de
|
||||||
|
@ -716,47 +716,45 @@ xrdp_listen_process_startup_params(struct xrdp_listen *self)
|
|||||||
if (startup_params->tcp_send_buffer_bytes > 0)
|
if (startup_params->tcp_send_buffer_bytes > 0)
|
||||||
{
|
{
|
||||||
bytes = startup_params->tcp_send_buffer_bytes;
|
bytes = startup_params->tcp_send_buffer_bytes;
|
||||||
LOG(LOG_LEVEL_INFO, "setting send buffer to %d bytes",
|
|
||||||
bytes);
|
|
||||||
if (g_sck_set_send_buffer_bytes(ltrans->sck, bytes) != 0)
|
if (g_sck_set_send_buffer_bytes(ltrans->sck, bytes) != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_WARNING, "error setting send buffer");
|
LOG(LOG_LEVEL_WARNING, "error setting send buffer");
|
||||||
}
|
}
|
||||||
|
else if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "error getting send buffer");
|
||||||
|
}
|
||||||
|
else if (bytes != startup_params->tcp_send_buffer_bytes)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "send buffer set to %d "
|
||||||
|
"bytes but %d bytes requested", bytes,
|
||||||
|
startup_params->tcp_send_buffer_bytes);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
|
LOG(LOG_LEVEL_INFO, "send buffer set to %d bytes", bytes);
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_WARNING, "error getting send "
|
|
||||||
"buffer");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_INFO, "send buffer set to %d "
|
|
||||||
"bytes", bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startup_params->tcp_recv_buffer_bytes > 0)
|
if (startup_params->tcp_recv_buffer_bytes > 0)
|
||||||
{
|
{
|
||||||
bytes = startup_params->tcp_recv_buffer_bytes;
|
bytes = startup_params->tcp_recv_buffer_bytes;
|
||||||
LOG(LOG_LEVEL_INFO, "setting recv buffer to %d bytes",
|
|
||||||
bytes);
|
|
||||||
if (g_sck_set_recv_buffer_bytes(ltrans->sck, bytes) != 0)
|
if (g_sck_set_recv_buffer_bytes(ltrans->sck, bytes) != 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_WARNING, "error setting recv buffer");
|
LOG(LOG_LEVEL_WARNING, "error setting recv buffer");
|
||||||
}
|
}
|
||||||
|
else if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "error getting recv buffer");
|
||||||
|
}
|
||||||
|
else if (bytes != startup_params->tcp_recv_buffer_bytes)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "recv buffer set to %d "
|
||||||
|
"bytes but %d bytes requested", bytes,
|
||||||
|
startup_params->tcp_recv_buffer_bytes);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
|
LOG(LOG_LEVEL_INFO, "recv buffer set to %d bytes", bytes);
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_WARNING, "error getting recv "
|
|
||||||
"buffer");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_INFO, "recv buffer set to %d "
|
|
||||||
"bytes", bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1458,8 +1458,6 @@ load_xrdp_config(struct xrdp_config *config, const char *xrdp_ini, int bpp)
|
|||||||
LOG(LOG_LEVEL_DEBUG, "tcp_keepalive: %d", globals->tcp_keepalive);
|
LOG(LOG_LEVEL_DEBUG, "tcp_keepalive: %d", globals->tcp_keepalive);
|
||||||
LOG(LOG_LEVEL_DEBUG, "tcp_send_buffer_bytes: %d", globals->tcp_send_buffer_bytes);
|
LOG(LOG_LEVEL_DEBUG, "tcp_send_buffer_bytes: %d", globals->tcp_send_buffer_bytes);
|
||||||
LOG(LOG_LEVEL_DEBUG, "tcp_recv_buffer_bytes: %d", globals->tcp_recv_buffer_bytes);
|
LOG(LOG_LEVEL_DEBUG, "tcp_recv_buffer_bytes: %d", globals->tcp_recv_buffer_bytes);
|
||||||
LOG(LOG_LEVEL_DEBUG, "new_cursors: %d", globals->new_cursors);
|
|
||||||
LOG(LOG_LEVEL_DEBUG, "allow_multimon: %d", globals->allow_multimon);
|
|
||||||
|
|
||||||
LOG(LOG_LEVEL_DEBUG, "grey: %d", globals->grey);
|
LOG(LOG_LEVEL_DEBUG, "grey: %d", globals->grey);
|
||||||
LOG(LOG_LEVEL_DEBUG, "black: %d", globals->black);
|
LOG(LOG_LEVEL_DEBUG, "black: %d", globals->black);
|
||||||
|
315
xrdp/xrdp_mm.c
315
xrdp/xrdp_mm.c
@ -396,7 +396,8 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self)
|
|||||||
self->mod->server_draw_line = server_draw_line;
|
self->mod->server_draw_line = server_draw_line;
|
||||||
self->mod->server_add_char = server_add_char;
|
self->mod->server_add_char = server_add_char;
|
||||||
self->mod->server_draw_text = server_draw_text;
|
self->mod->server_draw_text = server_draw_text;
|
||||||
self->mod->server_reset = server_reset;
|
self->mod->client_monitor_resize = client_monitor_resize;
|
||||||
|
self->mod->server_monitor_resize_done = server_monitor_resize_done;
|
||||||
self->mod->server_get_channel_count = server_get_channel_count;
|
self->mod->server_get_channel_count = server_get_channel_count;
|
||||||
self->mod->server_query_channel = server_query_channel;
|
self->mod->server_query_channel = server_query_channel;
|
||||||
self->mod->server_get_channel_id = server_get_channel_id;
|
self->mod->server_get_channel_id = server_get_channel_id;
|
||||||
@ -1094,25 +1095,32 @@ cleanup:
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
static int
|
static int
|
||||||
xrdp_mm_egfx_invalidate_all(struct xrdp_mm *self)
|
xrdp_mm_egfx_invalidate_wm_screen(struct xrdp_mm *self)
|
||||||
{
|
{
|
||||||
struct xrdp_rect xr_rect;
|
int error = 0;
|
||||||
struct xrdp_bitmap *screen;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:");
|
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_wm_screen:");
|
||||||
|
|
||||||
screen = self->wm->screen;
|
// Only invalidate the WM screen if the module is using the WM screen,
|
||||||
|
// or we haven't loaded the module yet.
|
||||||
xr_rect.left = 0;
|
//
|
||||||
xr_rect.top = 0;
|
// Otherwise we may send client updates which conflict with the
|
||||||
xr_rect.right = screen->width;
|
// updates sent directly from the module via the encoder.
|
||||||
xr_rect.bottom = screen->height;
|
if (self->mod_uses_wm_screen_for_gfx || self->mod_handle == 0)
|
||||||
if (self->wm->screen_dirty_region == NULL)
|
|
||||||
{
|
{
|
||||||
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
|
struct xrdp_bitmap *screen = self->wm->screen;
|
||||||
|
struct xrdp_rect xr_rect;
|
||||||
|
|
||||||
|
xr_rect.left = 0;
|
||||||
|
xr_rect.top = 0;
|
||||||
|
xr_rect.right = screen->width;
|
||||||
|
xr_rect.bottom = screen->height;
|
||||||
|
if (self->wm->screen_dirty_region == NULL)
|
||||||
|
{
|
||||||
|
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
|
||||||
|
}
|
||||||
|
error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect);
|
||||||
}
|
}
|
||||||
error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1262,7 +1270,6 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
|||||||
struct xrdp_mm *self;
|
struct xrdp_mm *self;
|
||||||
struct xrdp_bitmap *screen;
|
struct xrdp_bitmap *screen;
|
||||||
int index;
|
int index;
|
||||||
int best_index;
|
|
||||||
int best_h264_index;
|
int best_h264_index;
|
||||||
int best_pro_index;
|
int best_pro_index;
|
||||||
int error;
|
int error;
|
||||||
@ -1270,6 +1277,10 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
|||||||
int flags;
|
int flags;
|
||||||
struct ver_flags_t *ver_flags;
|
struct ver_flags_t *ver_flags;
|
||||||
|
|
||||||
|
#if !defined(XRDP_H264)
|
||||||
|
UNUSED_VAR(best_h264_index);
|
||||||
|
#endif
|
||||||
|
|
||||||
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:");
|
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:");
|
||||||
self = (struct xrdp_mm *) user;
|
self = (struct xrdp_mm *) user;
|
||||||
screen = self->wm->screen;
|
screen = self->wm->screen;
|
||||||
@ -1290,7 +1301,6 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
|||||||
}
|
}
|
||||||
/* sort by version */
|
/* sort by version */
|
||||||
g_qsort(ver_flags, caps_count, sizeof(struct ver_flags_t), cmpverfunc);
|
g_qsort(ver_flags, caps_count, sizeof(struct ver_flags_t), cmpverfunc);
|
||||||
best_index = -1;
|
|
||||||
best_h264_index = -1;
|
best_h264_index = -1;
|
||||||
best_pro_index = -1;
|
best_pro_index = -1;
|
||||||
for (index = 0; index < caps_count; index++)
|
for (index = 0; index < caps_count; index++)
|
||||||
@ -1337,19 +1347,34 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best_pro_index >= 0)
|
|
||||||
|
int best_index = -1;
|
||||||
|
struct xrdp_tconfig_gfx_codec_order *co = &self->wm->gfx_config->codec;
|
||||||
|
char cobuff[64];
|
||||||
|
|
||||||
|
LOG(LOG_LEVEL_INFO, "Codec search order is %s",
|
||||||
|
tconfig_codec_order_to_str(co, cobuff, sizeof(cobuff)));
|
||||||
|
for (index = 0 ; index < co->codec_count ; ++index)
|
||||||
{
|
{
|
||||||
best_index = best_pro_index;
|
#if defined(XRDP_H264)
|
||||||
self->egfx_flags = XRDP_EGFX_RFX_PRO;
|
if (co->codecs[index] == XTC_H264 && best_h264_index >= 0)
|
||||||
}
|
{
|
||||||
/* prefer h264, todo use setting in xrdp.ini for this */
|
LOG(LOG_LEVEL_INFO, "Matched H264 mode");
|
||||||
if (best_h264_index >= 0)
|
best_index = best_h264_index;
|
||||||
{
|
self->egfx_flags = XRDP_EGFX_H264;
|
||||||
#if defined(XRDP_X264) || defined(XRDP_NVENC)
|
break;
|
||||||
best_index = best_h264_index;
|
}
|
||||||
self->egfx_flags = XRDP_EGFX_H264;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (co->codecs[index] == XTC_RFX && best_pro_index >= 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_INFO, "Matched RFX mode");
|
||||||
|
best_index = best_pro_index;
|
||||||
|
self->egfx_flags = XRDP_EGFX_RFX_PRO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_index >= 0)
|
if (best_index >= 0)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x",
|
LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x",
|
||||||
@ -1362,14 +1387,14 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
|||||||
error = xrdp_egfx_send_reset_graphics(self->egfx,
|
error = xrdp_egfx_send_reset_graphics(self->egfx,
|
||||||
screen->width, screen->height,
|
screen->width, screen->height,
|
||||||
self->wm->client_info->display_sizes.monitorCount,
|
self->wm->client_info->display_sizes.monitorCount,
|
||||||
self->wm->client_info->display_sizes.minfo_wm);
|
self->wm->client_info->display_sizes.minfo);
|
||||||
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_reset_graphics "
|
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_reset_graphics "
|
||||||
"error %d monitorCount %d",
|
"error %d monitorCount %d",
|
||||||
error, self->wm->client_info->display_sizes.monitorCount);
|
error, self->wm->client_info->display_sizes.monitorCount);
|
||||||
self->egfx_up = 1;
|
self->egfx_up = 1;
|
||||||
xrdp_mm_egfx_create_surfaces(self);
|
xrdp_mm_egfx_create_surfaces(self);
|
||||||
self->encoder = xrdp_encoder_create(self);
|
self->encoder = xrdp_encoder_create(self);
|
||||||
xrdp_mm_egfx_invalidate_all(self);
|
xrdp_mm_egfx_invalidate_wm_screen(self);
|
||||||
|
|
||||||
if (self->resize_data != NULL
|
if (self->resize_data != NULL
|
||||||
&& self->resize_data->state == WMRZ_EGFX_INITALIZING)
|
&& self->resize_data->state == WMRZ_EGFX_INITALIZING)
|
||||||
@ -1635,6 +1660,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
|||||||
struct xrdp_rdp *rdp;
|
struct xrdp_rdp *rdp;
|
||||||
struct xrdp_sec *sec;
|
struct xrdp_sec *sec;
|
||||||
struct xrdp_channel *chan;
|
struct xrdp_channel *chan;
|
||||||
|
int in_progress;
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "process_display_control_monitor_layout_data:");
|
LOG_DEVEL(LOG_LEVEL_TRACE, "process_display_control_monitor_layout_data:");
|
||||||
|
|
||||||
@ -1697,6 +1723,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
|||||||
if (error == 0 && module != 0)
|
if (error == 0 && module != 0)
|
||||||
{
|
{
|
||||||
xrdp_egfx_shutdown_close_connection(wm->mm->egfx);
|
xrdp_egfx_shutdown_close_connection(wm->mm->egfx);
|
||||||
|
mm->egfx_up = 0;
|
||||||
}
|
}
|
||||||
advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSING);
|
advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSING);
|
||||||
break;
|
break;
|
||||||
@ -1725,13 +1752,15 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
|||||||
{
|
{
|
||||||
xrdp_egfx_shutdown_delete(wm->mm->egfx);
|
xrdp_egfx_shutdown_delete(wm->mm->egfx);
|
||||||
mm->egfx = NULL;
|
mm->egfx = NULL;
|
||||||
mm->egfx_up = 0;
|
|
||||||
}
|
}
|
||||||
advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE);
|
advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE);
|
||||||
break;
|
break;
|
||||||
case WMRZ_SERVER_MONITOR_RESIZE:
|
case WMRZ_SERVER_MONITOR_RESIZE:
|
||||||
error = module->mod_server_monitor_resize(
|
error = module->mod_server_monitor_resize(
|
||||||
module, desc_width, desc_height);
|
module, desc_width, desc_height,
|
||||||
|
description->description.monitorCount,
|
||||||
|
description->description.minfo,
|
||||||
|
&in_progress);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||||
@ -1739,30 +1768,27 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
|||||||
" mod_server_monitor_resize failed %d", error);
|
" mod_server_monitor_resize failed %d", error);
|
||||||
return advance_error(error, mm);
|
return advance_error(error, mm);
|
||||||
}
|
}
|
||||||
advance_resize_state_machine(
|
else if (in_progress)
|
||||||
mm, WMRZ_SERVER_VERSION_MESSAGE_START);
|
|
||||||
break;
|
|
||||||
case WMRZ_SERVER_VERSION_MESSAGE_START:
|
|
||||||
error = module->mod_server_version_message(module);
|
|
||||||
if (error != 0)
|
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
// Call is proceeding asynchronously
|
||||||
"process_display_control_monitor_layout_data:"
|
advance_resize_state_machine(
|
||||||
" mod_server_version_message failed %d", error);
|
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING);
|
||||||
return advance_error(error, mm);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Call is done
|
||||||
|
advance_resize_state_machine(
|
||||||
|
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED);
|
||||||
}
|
}
|
||||||
advance_resize_state_machine(
|
|
||||||
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING);
|
|
||||||
break;
|
break;
|
||||||
// Not processed here. Processed in server_reset
|
// Not processed here. Processed in client_monitor_resize
|
||||||
// case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING:
|
// case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING:
|
||||||
case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED:
|
case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED:
|
||||||
advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESET);
|
advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESET);
|
||||||
break;
|
break;
|
||||||
case WMRZ_XRDP_CORE_RESET:
|
case WMRZ_XRDP_CORE_RESET:
|
||||||
// TODO: Unify this logic with server_reset
|
sync_dynamic_monitor_data(wm, &(description->description));
|
||||||
error = libxrdp_reset(
|
error = libxrdp_reset(wm->session);
|
||||||
wm->session, desc_width, desc_height, wm->screen->bpp);
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||||
@ -1813,7 +1839,6 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
|||||||
" xrdp_bitmap_resize failed %d", error);
|
" xrdp_bitmap_resize failed %d", error);
|
||||||
return advance_error(error, mm);
|
return advance_error(error, mm);
|
||||||
}
|
}
|
||||||
sync_dynamic_monitor_data(wm, &(description->description));
|
|
||||||
advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE);
|
advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE);
|
||||||
break;
|
break;
|
||||||
case WMRZ_EGFX_INITIALIZE:
|
case WMRZ_EGFX_INITIALIZE:
|
||||||
@ -1845,20 +1870,13 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
|||||||
// Ack all frames to speed up resize.
|
// Ack all frames to speed up resize.
|
||||||
module->mod_frame_ack(module, 0, INT_MAX);
|
module->mod_frame_ack(module, 0, INT_MAX);
|
||||||
}
|
}
|
||||||
// Restart module output
|
// Restart module output after invalidating
|
||||||
|
// the screen. This causes an automatic redraw.
|
||||||
|
xrdp_bitmap_invalidate(wm->screen, 0);
|
||||||
rdp = (struct xrdp_rdp *) (wm->session->rdp);
|
rdp = (struct xrdp_rdp *) (wm->session->rdp);
|
||||||
xrdp_rdp_suppress_output(rdp,
|
xrdp_rdp_suppress_output(rdp,
|
||||||
0, XSO_REASON_DYNAMIC_RESIZE,
|
0, XSO_REASON_DYNAMIC_RESIZE,
|
||||||
0, 0, desc_width, desc_height);
|
0, 0, desc_width, desc_height);
|
||||||
/* redraw */
|
|
||||||
error = xrdp_bitmap_invalidate(wm->screen, 0);
|
|
||||||
if (error != 0)
|
|
||||||
{
|
|
||||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
|
||||||
"process_display_control_monitor_layout_data:"
|
|
||||||
" xrdp_bitmap_invalidate failed %d", error);
|
|
||||||
return advance_error(error, mm);
|
|
||||||
}
|
|
||||||
advance_resize_state_machine(mm, WMRZ_COMPLETE);
|
advance_resize_state_machine(mm, WMRZ_COMPLETE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2686,6 +2704,14 @@ xrdp_mm_process_login_response(struct xrdp_mm *self)
|
|||||||
self->wm->pamerrortxt);
|
self->wm->pamerrortxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->wm->client_info->require_credentials)
|
||||||
|
{
|
||||||
|
/* Credentials had to be specified, but were invalid */
|
||||||
|
g_set_wait_obj(self->wm->pro_layer->self_term_event);
|
||||||
|
LOG(LOG_LEVEL_ERROR, "require_credentials is set, "
|
||||||
|
"but the user could not be logged in");
|
||||||
|
}
|
||||||
|
|
||||||
if (server_closed)
|
if (server_closed)
|
||||||
{
|
{
|
||||||
if (login_result == E_SCP_LOGIN_NOT_AUTHENTICATED)
|
if (login_result == E_SCP_LOGIN_NOT_AUTHENTICATED)
|
||||||
@ -3476,7 +3502,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
|
|||||||
y = enc_done->y;
|
y = enc_done->y;
|
||||||
cx = enc_done->cx;
|
cx = enc_done->cx;
|
||||||
cy = enc_done->cy;
|
cy = enc_done->cy;
|
||||||
if (!enc_done->continuation)
|
if (client_ack && !enc_done->continuation)
|
||||||
{
|
{
|
||||||
libxrdp_fastpath_send_frame_marker(self->wm->session, 0,
|
libxrdp_fastpath_send_frame_marker(self->wm->session, 0,
|
||||||
enc_done->frame_id);
|
enc_done->frame_id);
|
||||||
@ -3488,7 +3514,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
|
|||||||
x, y, x + cx, y + cy,
|
x, y, x + cx, y + cy,
|
||||||
32, self->encoder->codec_id,
|
32, self->encoder->codec_id,
|
||||||
cx, cy);
|
cx, cy);
|
||||||
if (enc_done->last)
|
if (client_ack && enc_done->last)
|
||||||
{
|
{
|
||||||
libxrdp_fastpath_send_frame_marker(self->wm->session, 1,
|
libxrdp_fastpath_send_frame_marker(self->wm->session, 1,
|
||||||
enc_done->frame_id);
|
enc_done->frame_id);
|
||||||
@ -3534,6 +3560,39 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
void
|
||||||
|
xrdp_mm_efgx_add_dirty_region_to_planar_list(struct xrdp_mm *self,
|
||||||
|
struct xrdp_region *dirty_region)
|
||||||
|
{
|
||||||
|
int jndex = 0;
|
||||||
|
struct xrdp_rect rect;
|
||||||
|
|
||||||
|
int error = xrdp_region_get_rect(dirty_region, jndex, &rect);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
if (self->wm->screen_dirty_region == NULL)
|
||||||
|
{
|
||||||
|
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
xrdp_region_add_rect(self->wm->screen_dirty_region, &rect);
|
||||||
|
jndex++;
|
||||||
|
error = xrdp_region_get_rect(dirty_region, jndex, &rect);
|
||||||
|
}
|
||||||
|
while (error == 0);
|
||||||
|
|
||||||
|
if (self->mod_handle != 0)
|
||||||
|
{
|
||||||
|
// Module has been writing to WM screen using GFX
|
||||||
|
self->mod_uses_wm_screen_for_gfx = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
static int
|
static int
|
||||||
xrdp_mm_draw_dirty(struct xrdp_mm *self)
|
xrdp_mm_draw_dirty(struct xrdp_mm *self)
|
||||||
@ -4116,11 +4175,13 @@ server_egfx_cmd(struct xrdp_mod *mod,
|
|||||||
mm = wm->mm;
|
mm = wm->mm;
|
||||||
if (mm->encoder == NULL)
|
if (mm->encoder == NULL)
|
||||||
{
|
{
|
||||||
|
// This can happen when we are in the resize state machine, if
|
||||||
|
// there are messages queued up by the X server
|
||||||
if (data != NULL)
|
if (data != NULL)
|
||||||
{
|
{
|
||||||
g_munmap(data, data_bytes);
|
g_munmap(data, data_bytes);
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
enc = g_new0(struct xrdp_enc_data, 1);
|
enc = g_new0(struct xrdp_enc_data, 1);
|
||||||
if (enc == NULL)
|
if (enc == NULL)
|
||||||
@ -4432,17 +4493,70 @@ server_draw_text(struct xrdp_mod *mod, int font,
|
|||||||
x, y, data, data_len);
|
x, y, data, data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
int
|
||||||
|
client_monitor_resize(struct xrdp_mod *mod, int width, int height,
|
||||||
|
int num_monitors, const struct monitor_info *monitors)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
struct xrdp_wm *wm;
|
||||||
|
struct display_size_description *display_size_data;
|
||||||
|
|
||||||
|
LOG_DEVEL(LOG_LEVEL_TRACE, "client_monitor_resize:");
|
||||||
|
wm = (struct xrdp_wm *)(mod->wm);
|
||||||
|
if (wm == 0 || wm->mm == 0 || wm->client_info == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wm->client_info->client_resize_mode == CRMODE_NONE)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Server is not allowed to resize this client");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wm->client_info->client_resize_mode == CRMODE_SINGLE_SCREEN &&
|
||||||
|
num_monitors > 1)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING,
|
||||||
|
"Server cannot resize this client with multiple monitors");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_size_data = g_new0(struct display_size_description, 1);
|
||||||
|
if (display_size_data == NULL)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "client_monitor_resize: Out of memory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
error = libxrdp_init_display_size_description(num_monitors,
|
||||||
|
monitors,
|
||||||
|
display_size_data);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "client_monitor_resize:"
|
||||||
|
" libxrdp_init_display_size_description"
|
||||||
|
" failed with error %d.", error);
|
||||||
|
free(display_size_data);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
list_add_item(wm->mm->resize_queue, (tintptr)display_size_data);
|
||||||
|
g_set_wait_obj(wm->mm->resize_ready);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
/* Note : if this is called on a multimon setup, the client is resized
|
/* Note : if this is called on a multimon setup, the client is resized
|
||||||
* to a single monitor */
|
* to a single monitor */
|
||||||
int
|
int
|
||||||
server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
|
server_monitor_resize_done(struct xrdp_mod *mod)
|
||||||
{
|
{
|
||||||
struct xrdp_wm *wm;
|
struct xrdp_wm *wm;
|
||||||
struct xrdp_mm *mm;
|
struct xrdp_mm *mm;
|
||||||
|
|
||||||
LOG(LOG_LEVEL_TRACE, "server_reset:");
|
LOG(LOG_LEVEL_TRACE, "server_monitor_resize_done:");
|
||||||
|
|
||||||
wm = (struct xrdp_wm *)(mod->wm);
|
wm = (struct xrdp_wm *)(mod->wm);
|
||||||
if (wm == 0)
|
if (wm == 0)
|
||||||
@ -4450,78 +4564,25 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
mm = wm->mm;
|
mm = wm->mm;
|
||||||
|
if (mm == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (wm->client_info == 0)
|
if (wm->client_info == 0)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* older client can't resize */
|
if (mm->resize_data != NULL
|
||||||
if (wm->client_info->build <= 419)
|
&& mm->resize_data->state
|
||||||
|
== WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING)
|
||||||
{
|
{
|
||||||
return 0;
|
LOG(LOG_LEVEL_INFO,
|
||||||
|
"server_monitor_resize_done: Advancing server monitor resized.");
|
||||||
|
advance_resize_state_machine(
|
||||||
|
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bpp of zero is impossible.
|
|
||||||
// This is a signal from xup that
|
|
||||||
// It is finished resizing.
|
|
||||||
if (bpp == 0)
|
|
||||||
{
|
|
||||||
if (mm == 0)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!xrdp_wm_can_resize(wm))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (mm->resize_data == NULL)
|
|
||||||
{
|
|
||||||
mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (mm->resize_data != NULL
|
|
||||||
&& mm->resize_data->state
|
|
||||||
== WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_INFO,
|
|
||||||
"server_reset: Advancing server monitor resized.");
|
|
||||||
advance_resize_state_machine(
|
|
||||||
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED);
|
|
||||||
}
|
|
||||||
else if (mm->resize_data != NULL
|
|
||||||
&& mm->resize_data->description.session_height == 0
|
|
||||||
&& mm->resize_data->description.session_width == 0)
|
|
||||||
{
|
|
||||||
mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if same (and only one monitor on client) don't need to do anything */
|
|
||||||
if (wm->client_info->display_sizes.session_width == (uint32_t)width &&
|
|
||||||
wm->client_info->display_sizes.session_height == (uint32_t)height &&
|
|
||||||
wm->client_info->bpp == bpp &&
|
|
||||||
(wm->client_info->display_sizes.monitorCount == 0 ||
|
|
||||||
wm->client_info->multimon == 0))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset lib, client_info gets updated in libxrdp_reset */
|
|
||||||
if (libxrdp_reset(wm->session, width, height, bpp) != 0)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset cache */
|
|
||||||
xrdp_cache_reset(wm->cache, wm->client_info);
|
|
||||||
/* resize the main window */
|
|
||||||
xrdp_bitmap_resize(wm->screen, wm->client_info->display_sizes.session_width,
|
|
||||||
wm->client_info->display_sizes.session_height);
|
|
||||||
/* load some stuff */
|
|
||||||
xrdp_wm_load_static_colors_plus(wm, 0);
|
|
||||||
xrdp_wm_load_static_pointers(wm);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,18 +95,8 @@ xrdp_painter_send_dirty(struct xrdp_painter *self)
|
|||||||
|
|
||||||
if (self->session->client_info->gfx)
|
if (self->session->client_info->gfx)
|
||||||
{
|
{
|
||||||
if (self->wm->screen_dirty_region == NULL)
|
xrdp_mm_efgx_add_dirty_region_to_planar_list(self->wm->mm,
|
||||||
{
|
self->dirty_region);
|
||||||
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
|
|
||||||
}
|
|
||||||
jndex = 0;
|
|
||||||
error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
|
|
||||||
while (error == 0)
|
|
||||||
{
|
|
||||||
xrdp_region_add_rect(self->wm->screen_dirty_region, &rect);
|
|
||||||
jndex++;
|
|
||||||
error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
424
xrdp/xrdp_tconfig.c
Normal file
424
xrdp/xrdp_tconfig.c
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* Copyright (C) Koichiro Iwao
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @file xrdp_tconfig.c
|
||||||
|
* @brief TOML config loader
|
||||||
|
* @author Koichiro Iwao
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(HAVE_CONFIG_H)
|
||||||
|
#include <config_ac.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "arch.h"
|
||||||
|
#include "os_calls.h"
|
||||||
|
#include "parse.h"
|
||||||
|
#include "toml.h"
|
||||||
|
#include "ms-rdpbcgr.h"
|
||||||
|
#include "xrdp_tconfig.h"
|
||||||
|
#include "string_calls.h"
|
||||||
|
|
||||||
|
#define TCLOG(log_level, args...) LOG(log_level, "TConfig: " args)
|
||||||
|
|
||||||
|
#define X264_DEFAULT_PRESET "ultrafast"
|
||||||
|
#define X264_DEFAULT_TUNE "zerolatency"
|
||||||
|
#define X264_DEFAULT_PROFILE "main"
|
||||||
|
#define X264_DEFAULT_FPS_NUM 24
|
||||||
|
#define X264_DEFAULT_FPS_DEN 1
|
||||||
|
|
||||||
|
const char *
|
||||||
|
tconfig_codec_order_to_str(
|
||||||
|
const struct xrdp_tconfig_gfx_codec_order *codec_order,
|
||||||
|
char *buff,
|
||||||
|
unsigned int bufflen)
|
||||||
|
{
|
||||||
|
if (bufflen < (8 * codec_order->codec_count))
|
||||||
|
{
|
||||||
|
snprintf(buff, bufflen, "???");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int p = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0 ; i < codec_order->codec_count; ++i)
|
||||||
|
{
|
||||||
|
if (p > 0)
|
||||||
|
{
|
||||||
|
buff[p++] = ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (codec_order->codecs[i])
|
||||||
|
{
|
||||||
|
case XTC_H264:
|
||||||
|
buff[p++] = 'H';
|
||||||
|
buff[p++] = '2';
|
||||||
|
buff[p++] = '6';
|
||||||
|
buff[p++] = '4';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XTC_RFX:
|
||||||
|
buff[p++] = 'R';
|
||||||
|
buff[p++] = 'F';
|
||||||
|
buff[p++] = 'X';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buff[p++] = '?';
|
||||||
|
buff[p++] = '?';
|
||||||
|
buff[p++] = '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buff[p++] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type,
|
||||||
|
struct xrdp_tconfig_gfx_x264_param *param)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_TRACE, "[x264]");
|
||||||
|
|
||||||
|
if (connection_type > NUM_CONNECTION_TYPES)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_ERROR, "[x264] Invalid connection type is given");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
toml_table_t *x264 = toml_table_in(tfile, "x264");
|
||||||
|
if (!x264)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING, "[x264] x264 params are not defined");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
toml_table_t *x264_ct =
|
||||||
|
toml_table_in(x264, rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
toml_datum_t datum;
|
||||||
|
|
||||||
|
if (!x264_ct)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING, "x264 params for connection type [%s] is not defined",
|
||||||
|
rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* preset */
|
||||||
|
datum = toml_string_in(x264_ct, "preset");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
g_strncpy(param[connection_type].preset,
|
||||||
|
datum.u.s,
|
||||||
|
sizeof(param[connection_type].preset) - 1);
|
||||||
|
free(datum.u.s);
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] preset is not set, adopting the default value \""
|
||||||
|
X264_DEFAULT_PRESET "\"",
|
||||||
|
rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
g_strncpy(param[connection_type].preset,
|
||||||
|
X264_DEFAULT_PRESET,
|
||||||
|
sizeof(param[connection_type].preset) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tune */
|
||||||
|
datum = toml_string_in(x264_ct, "tune");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
g_strncpy(param[connection_type].tune,
|
||||||
|
datum.u.s,
|
||||||
|
sizeof(param[connection_type].tune) - 1);
|
||||||
|
free(datum.u.s);
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] tune is not set, adopting the default value \""
|
||||||
|
X264_DEFAULT_TUNE"\"",
|
||||||
|
rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
g_strncpy(param[connection_type].tune,
|
||||||
|
X264_DEFAULT_TUNE,
|
||||||
|
sizeof(param[connection_type].tune) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* profile */
|
||||||
|
datum = toml_string_in(x264_ct, "profile");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
g_strncpy(param[connection_type].profile,
|
||||||
|
datum.u.s,
|
||||||
|
sizeof(param[connection_type].profile) - 1);
|
||||||
|
free(datum.u.s);
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] profile is not set, adopting the default value \""
|
||||||
|
X264_DEFAULT_PROFILE"\"",
|
||||||
|
rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
g_strncpy(param[connection_type].profile,
|
||||||
|
X264_DEFAULT_PROFILE,
|
||||||
|
sizeof(param[connection_type].profile) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vbv_max_bitrate */
|
||||||
|
datum = toml_int_in(x264_ct, "vbv_max_bitrate");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
param[connection_type].vbv_max_bitrate = datum.u.i;
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] vbv_max_bitrate is not set, adopting the default value [0]",
|
||||||
|
rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
param[connection_type].vbv_max_bitrate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vbv_buffer_size */
|
||||||
|
datum = toml_int_in(x264_ct, "vbv_buffer_size");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
param[connection_type].vbv_buffer_size = datum.u.i;
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] vbv_buffer_size is not set, adopting the default value [0]",
|
||||||
|
rdpbcgr_connection_type_names[connection_type]);
|
||||||
|
param[connection_type].vbv_buffer_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fps_num */
|
||||||
|
datum = toml_int_in(x264_ct, "fps_num");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
param[connection_type].fps_num = datum.u.i;
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] fps_num is not set, adopting the default value [%d]",
|
||||||
|
rdpbcgr_connection_type_names[connection_type],
|
||||||
|
X264_DEFAULT_FPS_NUM);
|
||||||
|
param[connection_type].fps_num = X264_DEFAULT_FPS_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fps_den */
|
||||||
|
datum = toml_int_in(x264_ct, "fps_den");
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
param[connection_type].fps_den = datum.u.i;
|
||||||
|
}
|
||||||
|
else if (connection_type == 0)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_WARNING,
|
||||||
|
"[x264.%s] fps_den is not set, adopting the default value [%d]",
|
||||||
|
rdpbcgr_connection_type_names[connection_type],
|
||||||
|
X264_DEFAULT_FPS_DEN);
|
||||||
|
param[connection_type].fps_den = X264_DEFAULT_FPS_DEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tconfig_load_gfx_order(toml_table_t *tfile, struct xrdp_tconfig_gfx *config)
|
||||||
|
{
|
||||||
|
char buff[64];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This config loader is not responsible to check if xrdp is built with
|
||||||
|
* H264/RFX support. Just loads configurations as-is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TCLOG(LOG_LEVEL_TRACE, "[codec]");
|
||||||
|
|
||||||
|
int h264_found = 0;
|
||||||
|
int rfx_found = 0;
|
||||||
|
|
||||||
|
config->codec.codec_count = 0;
|
||||||
|
|
||||||
|
toml_table_t *codec;
|
||||||
|
toml_array_t *order;
|
||||||
|
|
||||||
|
if ((codec = toml_table_in(tfile, "codec")) != NULL &&
|
||||||
|
(order = toml_array_in(codec, "order")) != NULL)
|
||||||
|
{
|
||||||
|
for (int i = 0; ; i++)
|
||||||
|
{
|
||||||
|
toml_datum_t datum = toml_string_at(order, i);
|
||||||
|
|
||||||
|
if (datum.ok)
|
||||||
|
{
|
||||||
|
if (h264_found == 0 &&
|
||||||
|
(g_strcasecmp(datum.u.s, "h264") == 0 ||
|
||||||
|
g_strcasecmp(datum.u.s, "h.264") == 0))
|
||||||
|
{
|
||||||
|
h264_found = 1;
|
||||||
|
config->codec.codecs[config->codec.codec_count] = XTC_H264;
|
||||||
|
++config->codec.codec_count;
|
||||||
|
}
|
||||||
|
if (rfx_found == 0 &&
|
||||||
|
g_strcasecmp(datum.u.s, "rfx") == 0)
|
||||||
|
{
|
||||||
|
rfx_found = 1;
|
||||||
|
config->codec.codecs[config->codec.codec_count] = XTC_RFX;
|
||||||
|
++config->codec.codec_count;
|
||||||
|
}
|
||||||
|
free(datum.u.s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h264_found == 0 && rfx_found == 0)
|
||||||
|
{
|
||||||
|
/* prefer H264 if no priority found */
|
||||||
|
config->codec.codecs[0] = XTC_H264;
|
||||||
|
config->codec.codecs[1] = XTC_RFX;
|
||||||
|
config->codec.codec_count = 2;
|
||||||
|
|
||||||
|
TCLOG(LOG_LEVEL_WARNING, "[codec] could not get GFX codec order, "
|
||||||
|
"using default order %s",
|
||||||
|
tconfig_codec_order_to_str(&config->codec, buff, sizeof(buff)));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCLOG(LOG_LEVEL_DEBUG, "[codec] %s",
|
||||||
|
tconfig_codec_order_to_str(&config->codec, buff, sizeof(buff)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a codec is enabled
|
||||||
|
* @param co Ordered codec list
|
||||||
|
* @param code Code of codec to look for
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
codec_enabled(const struct xrdp_tconfig_gfx_codec_order *co,
|
||||||
|
enum xrdp_tconfig_codecs code)
|
||||||
|
{
|
||||||
|
for (unsigned short i = 0; i < co->codec_count; ++i)
|
||||||
|
{
|
||||||
|
if (co->codecs[i] == code)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables a Codec by removing it from the codec list
|
||||||
|
* @param co Ordered codec list
|
||||||
|
* @param code Code of codec to remove from list
|
||||||
|
*
|
||||||
|
* The order of the passed-in codec list is preserved.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
disable_codec(struct xrdp_tconfig_gfx_codec_order *co,
|
||||||
|
enum xrdp_tconfig_codecs code)
|
||||||
|
{
|
||||||
|
unsigned short j = 0;
|
||||||
|
for (unsigned short i = 0; i < co->codec_count; ++i)
|
||||||
|
{
|
||||||
|
if (co->codecs[i] != code)
|
||||||
|
{
|
||||||
|
co->codecs[j++] = co->codecs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
co->codec_count = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char errbuf[200];
|
||||||
|
toml_table_t *tfile;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
/* Default to just RFX support. in case we can't load anything */
|
||||||
|
config->codec.codec_count = 1;
|
||||||
|
config->codec.codecs[0] = XTC_RFX;
|
||||||
|
memset(config->x264_param, 0, sizeof(config->x264_param));
|
||||||
|
|
||||||
|
if ((fp = fopen(filename, "r")) == NULL)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_ERROR, "Error loading GFX config file %s (%s)",
|
||||||
|
filename, g_get_strerror());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tfile = toml_parse_file(fp, errbuf, sizeof(errbuf))) == NULL)
|
||||||
|
{
|
||||||
|
TCLOG(LOG_LEVEL_ERROR, "Error in GFX config file %s - %s", filename, errbuf);
|
||||||
|
fclose(fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCLOG(LOG_LEVEL_INFO, "Loading GFX config file %s", filename);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/* Load GFX codec order */
|
||||||
|
tconfig_load_gfx_order(tfile, config);
|
||||||
|
|
||||||
|
/* H.264 configuration */
|
||||||
|
if (codec_enabled(&config->codec, XTC_H264))
|
||||||
|
{
|
||||||
|
/* First of all, read the default params */
|
||||||
|
if (tconfig_load_gfx_x264_ct(tfile, 0, config->x264_param) != 0)
|
||||||
|
{
|
||||||
|
/* We can't read the H.264 defaults. Disable H.264 */
|
||||||
|
LOG(LOG_LEVEL_WARNING, "H.264 support will be disabled");
|
||||||
|
disable_codec(&config->codec, XTC_H264);
|
||||||
|
rv = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy default params to other connection types, and
|
||||||
|
* then override them */
|
||||||
|
for (int ct = CONNECTION_TYPE_MODEM; ct < NUM_CONNECTION_TYPES;
|
||||||
|
ct++)
|
||||||
|
{
|
||||||
|
config->x264_param[ct] = config->x264_param[0];
|
||||||
|
tconfig_load_gfx_x264_ct(tfile, ct, config->x264_param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toml_free(tfile);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
104
xrdp/xrdp_tconfig.h
Normal file
104
xrdp/xrdp_tconfig.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* Copyright (C) Koichiro Iwao
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @file xrdp_tconfig.c
|
||||||
|
* @brief TOML config loader and structures
|
||||||
|
* @author Koichiro Iwao
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef _XRDP_TCONFIG_H_
|
||||||
|
#define _XRDP_TCONFIG_H_
|
||||||
|
|
||||||
|
/* The number of connection types in MS-RDPBCGR 2.2.1.3.2 */
|
||||||
|
#define NUM_CONNECTION_TYPES 7
|
||||||
|
#define GFX_CONF XRDP_CFG_PATH "/gfx.toml"
|
||||||
|
|
||||||
|
/* nc stands for new config */
|
||||||
|
struct xrdp_tconfig_gfx_x264_param
|
||||||
|
{
|
||||||
|
char preset[16];
|
||||||
|
char tune[16];
|
||||||
|
char profile[16];
|
||||||
|
int vbv_max_bitrate;
|
||||||
|
int vbv_buffer_size;
|
||||||
|
int fps_num;
|
||||||
|
int fps_den;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum xrdp_tconfig_codecs
|
||||||
|
{
|
||||||
|
XTC_H264,
|
||||||
|
XTC_RFX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xrdp_tconfig_gfx_codec_order
|
||||||
|
{
|
||||||
|
enum xrdp_tconfig_codecs codecs[2];
|
||||||
|
unsigned short codec_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xrdp_tconfig_gfx
|
||||||
|
{
|
||||||
|
struct xrdp_tconfig_gfx_codec_order codec;
|
||||||
|
/* store x264 parameters for each connection type */
|
||||||
|
struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rdpbcgr_connection_type_names[] =
|
||||||
|
{
|
||||||
|
"default", /* for xrdp internal use */
|
||||||
|
"modem",
|
||||||
|
"broadband_low",
|
||||||
|
"satellite",
|
||||||
|
"broadband_high",
|
||||||
|
"wan",
|
||||||
|
"lan",
|
||||||
|
"autodetect",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a string representation of a codec order
|
||||||
|
*
|
||||||
|
* @param codec_order Codec order struct
|
||||||
|
* @param buff Buffer for result
|
||||||
|
* @param bufflen Length of above
|
||||||
|
* @return Convenience copy of buff
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
tconfig_codec_order_to_str(
|
||||||
|
const struct xrdp_tconfig_gfx_codec_order *codec_order,
|
||||||
|
char *buff,
|
||||||
|
unsigned int bufflen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the GFX config from the specified file
|
||||||
|
*
|
||||||
|
* @param filename Name of file to load
|
||||||
|
* @param config Struct to receive result
|
||||||
|
* @return 0 for success
|
||||||
|
*
|
||||||
|
* In the event of failure, an error is logged. A minimal
|
||||||
|
* useable configuration is always returned
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config);
|
||||||
|
|
||||||
|
#endif
|
@ -29,6 +29,7 @@
|
|||||||
#include "fifo.h"
|
#include "fifo.h"
|
||||||
#include "guid.h"
|
#include "guid.h"
|
||||||
#include "xrdp_client_info.h"
|
#include "xrdp_client_info.h"
|
||||||
|
#include "xrdp_tconfig.h"
|
||||||
|
|
||||||
#define MAX_NR_CHANNELS 16
|
#define MAX_NR_CHANNELS 16
|
||||||
#define MAX_CHANNEL_NAME 16
|
#define MAX_CHANNEL_NAME 16
|
||||||
@ -64,7 +65,10 @@ struct xrdp_mod
|
|||||||
int (*mod_suppress_output)(struct xrdp_mod *v, int suppress,
|
int (*mod_suppress_output)(struct xrdp_mod *v, int suppress,
|
||||||
int left, int top, int right, int bottom);
|
int left, int top, int right, int bottom);
|
||||||
int (*mod_server_monitor_resize)(struct xrdp_mod *v,
|
int (*mod_server_monitor_resize)(struct xrdp_mod *v,
|
||||||
int width, int height);
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress);
|
||||||
int (*mod_server_monitor_full_invalidate)(struct xrdp_mod *v,
|
int (*mod_server_monitor_full_invalidate)(struct xrdp_mod *v,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
int (*mod_server_version_message)(struct xrdp_mod *v);
|
int (*mod_server_version_message)(struct xrdp_mod *v);
|
||||||
@ -106,7 +110,10 @@ struct xrdp_mod
|
|||||||
int box_left, int box_top,
|
int box_left, int box_top,
|
||||||
int box_right, int box_bottom,
|
int box_right, int box_bottom,
|
||||||
int x, int y, char *data, int data_len);
|
int x, int y, char *data, int data_len);
|
||||||
int (*server_reset)(struct xrdp_mod *v, int width, int height, int bpp);
|
int (*client_monitor_resize)(struct xrdp_mod *v, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors);
|
||||||
|
int (*server_monitor_resize_done)(struct xrdp_mod *v);
|
||||||
int (*server_get_channel_count)(struct xrdp_mod *v);
|
int (*server_get_channel_count)(struct xrdp_mod *v);
|
||||||
int (*server_query_channel)(struct xrdp_mod *v, int index,
|
int (*server_query_channel)(struct xrdp_mod *v, int index,
|
||||||
char *channel_name,
|
char *channel_name,
|
||||||
@ -185,7 +192,7 @@ struct xrdp_mod
|
|||||||
int (*server_egfx_cmd)(struct xrdp_mod *v,
|
int (*server_egfx_cmd)(struct xrdp_mod *v,
|
||||||
char *cmd, int cmd_bytes,
|
char *cmd, int cmd_bytes,
|
||||||
char *data, int data_bytes);
|
char *data, int data_bytes);
|
||||||
tintptr server_dumby[100 - 49]; /* align, 100 minus the number of server
|
tintptr server_dumby[100 - 50]; /* align, 100 minus the number of server
|
||||||
functions above */
|
functions above */
|
||||||
/* common */
|
/* common */
|
||||||
tintptr handle; /* pointer to self as int */
|
tintptr handle; /* pointer to self as int */
|
||||||
@ -347,7 +354,6 @@ enum display_resize_state
|
|||||||
WMRZ_EGFX_CONN_CLOSED,
|
WMRZ_EGFX_CONN_CLOSED,
|
||||||
WRMZ_EGFX_DELETE,
|
WRMZ_EGFX_DELETE,
|
||||||
WMRZ_SERVER_MONITOR_RESIZE,
|
WMRZ_SERVER_MONITOR_RESIZE,
|
||||||
WMRZ_SERVER_VERSION_MESSAGE_START,
|
|
||||||
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING,
|
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING,
|
||||||
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED,
|
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED,
|
||||||
WMRZ_XRDP_CORE_RESET,
|
WMRZ_XRDP_CORE_RESET,
|
||||||
@ -370,8 +376,6 @@ enum display_resize_state
|
|||||||
(status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \
|
(status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \
|
||||||
(status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \
|
(status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \
|
||||||
(status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \
|
(status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \
|
||||||
(status) == WMRZ_SERVER_VERSION_MESSAGE_START ? \
|
|
||||||
"WMRZ_SERVER_VERSION_MESSAGE_START" : \
|
|
||||||
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING ? \
|
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING ? \
|
||||||
"WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \
|
"WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \
|
||||||
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \
|
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \
|
||||||
@ -436,6 +440,7 @@ struct xrdp_mm
|
|||||||
int egfx_up;
|
int egfx_up;
|
||||||
enum xrdp_egfx_flags egfx_flags;
|
enum xrdp_egfx_flags egfx_flags;
|
||||||
int gfx_delay_autologin;
|
int gfx_delay_autologin;
|
||||||
|
int mod_uses_wm_screen_for_gfx;
|
||||||
/* Resize on-the-fly control */
|
/* Resize on-the-fly control */
|
||||||
struct display_control_monitor_layout_data *resize_data;
|
struct display_control_monitor_layout_data *resize_data;
|
||||||
struct list *resize_queue;
|
struct list *resize_queue;
|
||||||
@ -562,6 +567,8 @@ struct xrdp_wm
|
|||||||
|
|
||||||
/* configuration derived from xrdp.ini */
|
/* configuration derived from xrdp.ini */
|
||||||
struct xrdp_config *xrdp_config;
|
struct xrdp_config *xrdp_config;
|
||||||
|
/* configuration derived from gfx.toml */
|
||||||
|
struct xrdp_tconfig_gfx *gfx_config;
|
||||||
|
|
||||||
struct xrdp_region *screen_dirty_region;
|
struct xrdp_region *screen_dirty_region;
|
||||||
int last_screen_draw_time;
|
int last_screen_draw_time;
|
||||||
|
131
xrdp/xrdp_wm.c
131
xrdp/xrdp_wm.c
@ -29,6 +29,54 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "string_calls.h"
|
#include "string_calls.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static void
|
||||||
|
xrdp_wm_load_channel_config(struct xrdp_wm *self)
|
||||||
|
{
|
||||||
|
struct list *names = list_create();
|
||||||
|
names->auto_free = 1;
|
||||||
|
struct list *values = list_create();
|
||||||
|
values->auto_free = 1;
|
||||||
|
|
||||||
|
if (file_by_name_read_section(self->session->xrdp_ini,
|
||||||
|
"Channels", names, values) == 0)
|
||||||
|
{
|
||||||
|
int chan_id;
|
||||||
|
int chan_count = libxrdp_get_channel_count(self->session);
|
||||||
|
const char *disabled_str = NULL;
|
||||||
|
|
||||||
|
for (chan_id = 0 ; chan_id < chan_count ; ++chan_id)
|
||||||
|
{
|
||||||
|
char chan_name[16];
|
||||||
|
if (libxrdp_query_channel(self->session, chan_id, chan_name,
|
||||||
|
NULL) == 0)
|
||||||
|
{
|
||||||
|
int disabled = 1; /* Channels disabled if not found */
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for (index = 0; index < names->count; index++)
|
||||||
|
{
|
||||||
|
const char *q = (const char *)list_get_item(names, index);
|
||||||
|
const char *r = (const char *)list_get_item(values, index);
|
||||||
|
if (g_strcasecmp(q, chan_name) == 0)
|
||||||
|
{
|
||||||
|
disabled = !g_text2bool(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disabled_str = (disabled) ? "disabled" : "enabled";
|
||||||
|
LOG(LOG_LEVEL_DEBUG, "xrdp_wm_load_channel_config: "
|
||||||
|
"channel %s channel id %d is %s",
|
||||||
|
chan_name, chan_id, disabled_str);
|
||||||
|
|
||||||
|
libxrdp_disable_channel(self->session, chan_id, disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_delete(names);
|
||||||
|
list_delete(values);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
struct xrdp_wm *
|
struct xrdp_wm *
|
||||||
xrdp_wm_create(struct xrdp_process *owner,
|
xrdp_wm_create(struct xrdp_process *owner,
|
||||||
@ -66,8 +114,26 @@ xrdp_wm_create(struct xrdp_process *owner,
|
|||||||
self->target_surface = self->screen;
|
self->target_surface = self->screen;
|
||||||
self->current_surface_index = 0xffff; /* screen */
|
self->current_surface_index = 0xffff; /* screen */
|
||||||
|
|
||||||
/* to store configuration from xrdp.ini */
|
/* to store configuration from xrdp.ini, gfx.toml */
|
||||||
self->xrdp_config = g_new0(struct xrdp_config, 1);
|
self->xrdp_config = g_new0(struct xrdp_config, 1);
|
||||||
|
self->gfx_config = g_new0(struct xrdp_tconfig_gfx, 1);
|
||||||
|
|
||||||
|
/* Load the channel config so libxrdp can check whether
|
||||||
|
drdynvc is enabled or not */
|
||||||
|
xrdp_wm_load_channel_config(self);
|
||||||
|
|
||||||
|
// Start drdynvc if available.
|
||||||
|
if (libxrdp_drdynvc_start(self->session) == 0)
|
||||||
|
{
|
||||||
|
// drdynvc is started. callback() will
|
||||||
|
// be notified when capabilities are received.
|
||||||
|
}
|
||||||
|
else if (self->client_info->gfx)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Disabling GFX as '"
|
||||||
|
DRDYNVC_SVC_CHANNEL_NAME "' isn't available");
|
||||||
|
self->client_info->gfx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -97,6 +163,11 @@ xrdp_wm_delete(struct xrdp_wm *self)
|
|||||||
g_free(self->xrdp_config);
|
g_free(self->xrdp_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->gfx_config)
|
||||||
|
{
|
||||||
|
g_free(self->gfx_config);
|
||||||
|
}
|
||||||
|
|
||||||
/* free self */
|
/* free self */
|
||||||
g_free(self);
|
g_free(self);
|
||||||
}
|
}
|
||||||
@ -564,9 +635,7 @@ xrdp_wm_init(struct xrdp_wm *self)
|
|||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int index;
|
int index;
|
||||||
struct list *names;
|
const char *q;
|
||||||
struct list *values;
|
|
||||||
char *q;
|
|
||||||
const char *r;
|
const char *r;
|
||||||
char param[256];
|
char param[256];
|
||||||
char default_section_name[256];
|
char default_section_name[256];
|
||||||
@ -579,6 +648,8 @@ xrdp_wm_init(struct xrdp_wm *self)
|
|||||||
load_xrdp_config(self->xrdp_config, self->session->xrdp_ini,
|
load_xrdp_config(self->xrdp_config, self->session->xrdp_ini,
|
||||||
self->screen->bpp);
|
self->screen->bpp);
|
||||||
|
|
||||||
|
tconfig_load_gfx(XRDP_CFG_PATH "/gfx.toml", self->gfx_config);
|
||||||
|
|
||||||
/* Remove a font loaded on the previous config */
|
/* Remove a font loaded on the previous config */
|
||||||
xrdp_font_delete(self->default_font);
|
xrdp_font_delete(self->default_font);
|
||||||
self->painter->font = NULL; /* May be set to the default_font */
|
self->painter->font = NULL; /* May be set to the default_font */
|
||||||
@ -590,48 +661,6 @@ xrdp_wm_init(struct xrdp_wm *self)
|
|||||||
/* Scale the login screen values */
|
/* Scale the login screen values */
|
||||||
xrdp_login_wnd_scale_config_values(self);
|
xrdp_login_wnd_scale_config_values(self);
|
||||||
|
|
||||||
/* global channels allow */
|
|
||||||
names = list_create();
|
|
||||||
names->auto_free = 1;
|
|
||||||
values = list_create();
|
|
||||||
values->auto_free = 1;
|
|
||||||
if (file_by_name_read_section(self->session->xrdp_ini,
|
|
||||||
"Channels", names, values) == 0)
|
|
||||||
{
|
|
||||||
int chan_id;
|
|
||||||
int chan_count = libxrdp_get_channel_count(self->session);
|
|
||||||
const char *disabled_str = NULL;
|
|
||||||
|
|
||||||
for (chan_id = 0 ; chan_id < chan_count ; ++chan_id)
|
|
||||||
{
|
|
||||||
char chan_name[16];
|
|
||||||
if (libxrdp_query_channel(self->session, chan_id, chan_name,
|
|
||||||
NULL) == 0)
|
|
||||||
{
|
|
||||||
int disabled = 1; /* Channels disabled if not found */
|
|
||||||
|
|
||||||
for (index = 0; index < names->count; index++)
|
|
||||||
{
|
|
||||||
q = (char *) list_get_item(names, index);
|
|
||||||
if (g_strcasecmp(q, chan_name) == 0)
|
|
||||||
{
|
|
||||||
r = (const char *) list_get_item(values, index);
|
|
||||||
disabled = !g_text2bool(r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
disabled_str = (disabled) ? "disabled" : "enabled";
|
|
||||||
LOG(LOG_LEVEL_DEBUG, "xrdp_wm_init: "
|
|
||||||
"channel %s channel id %d is %s",
|
|
||||||
chan_name, chan_id, disabled_str);
|
|
||||||
|
|
||||||
libxrdp_disable_channel(self->session, chan_id, disabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_delete(names);
|
|
||||||
list_delete(values);
|
|
||||||
|
|
||||||
xrdp_wm_load_static_colors_plus(self, autorun_name);
|
xrdp_wm_load_static_colors_plus(self, autorun_name);
|
||||||
xrdp_wm_load_static_pointers(self);
|
xrdp_wm_load_static_pointers(self);
|
||||||
self->screen->bg_color = self->xrdp_config->cfg_globals.ls_top_window_bg_color;
|
self->screen->bg_color = self->xrdp_config->cfg_globals.ls_top_window_bg_color;
|
||||||
@ -645,9 +674,9 @@ xrdp_wm_init(struct xrdp_wm *self)
|
|||||||
fd = g_file_open_ro(self->session->xrdp_ini);
|
fd = g_file_open_ro(self->session->xrdp_ini);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
{
|
{
|
||||||
names = list_create();
|
struct list *names = list_create();
|
||||||
names->auto_free = 1;
|
names->auto_free = 1;
|
||||||
values = list_create();
|
struct list *values = list_create();
|
||||||
values->auto_free = 1;
|
values->auto_free = 1;
|
||||||
|
|
||||||
/* pick up the first section name except for 'globals', 'Logging', 'channels'
|
/* pick up the first section name except for 'globals', 'Logging', 'channels'
|
||||||
@ -656,7 +685,7 @@ xrdp_wm_init(struct xrdp_wm *self)
|
|||||||
default_section_name[0] = '\0';
|
default_section_name[0] = '\0';
|
||||||
for (index = 0; index < names->count; index++)
|
for (index = 0; index < names->count; index++)
|
||||||
{
|
{
|
||||||
q = (char *)list_get_item(names, index);
|
q = (const char *)list_get_item(names, index);
|
||||||
if ((g_strncasecmp("globals", q, 8) != 0) &&
|
if ((g_strncasecmp("globals", q, 8) != 0) &&
|
||||||
(g_strncasecmp("Logging", q, 8) != 0) &&
|
(g_strncasecmp("Logging", q, 8) != 0) &&
|
||||||
(g_strncasecmp("LoggingPerLogger", q, 17) != 0) &&
|
(g_strncasecmp("LoggingPerLogger", q, 17) != 0) &&
|
||||||
@ -714,8 +743,8 @@ xrdp_wm_init(struct xrdp_wm *self)
|
|||||||
{
|
{
|
||||||
for (index = 0; index < names->count; index++)
|
for (index = 0; index < names->count; index++)
|
||||||
{
|
{
|
||||||
q = (char *)list_get_item(names, index);
|
q = (const char *)list_get_item(names, index);
|
||||||
r = (char *)list_get_item(values, index);
|
r = (const char *)list_get_item(values, index);
|
||||||
|
|
||||||
if (g_strncasecmp("password", q, 255) == 0)
|
if (g_strncasecmp("password", q, 255) == 0)
|
||||||
{
|
{
|
||||||
|
56
xup/xup.c
56
xup/xup.c
@ -28,8 +28,10 @@
|
|||||||
#include "string_calls.h"
|
#include "string_calls.h"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
send_server_monitor_resize(
|
send_server_monitor_update(struct mod *v, struct stream *s,
|
||||||
struct mod *mod, struct stream *s, int width, int height, int bpp);
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
send_server_monitor_full_invalidate(
|
send_server_monitor_full_invalidate(
|
||||||
@ -224,13 +226,6 @@ lib_mod_connect(struct mod *mod)
|
|||||||
error = send_server_version_message(mod, s);
|
error = send_server_version_message(mod, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error == 0)
|
|
||||||
{
|
|
||||||
/* send screen size message */
|
|
||||||
error = send_server_monitor_resize(
|
|
||||||
mod, s, mod->width, mod->height, mod->bpp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
error = send_server_monitor_full_invalidate(
|
error = send_server_monitor_full_invalidate(
|
||||||
@ -1466,33 +1461,30 @@ send_server_version_message(struct mod *mod, struct stream *s)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* return error */
|
/* return error */
|
||||||
static int
|
static int
|
||||||
send_server_monitor_resize(
|
send_server_monitor_update(struct mod *mod, struct stream *s,
|
||||||
struct mod *mod, struct stream *s, int width, int height, int bpp)
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors)
|
||||||
{
|
{
|
||||||
/* send screen size message */
|
/* send monitor update message */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
s_push_layer(s, iso_hdr, 4);
|
s_push_layer(s, iso_hdr, 4);
|
||||||
out_uint16_le(s, 103);
|
out_uint16_le(s, 103);
|
||||||
out_uint32_le(s, 300);
|
out_uint32_le(s, 302);
|
||||||
out_uint32_le(s, width);
|
out_uint32_le(s, width);
|
||||||
out_uint32_le(s, height);
|
out_uint32_le(s, height);
|
||||||
/*
|
out_uint32_le(s, num_monitors);
|
||||||
TODO: The bpp here is only necessary for initial creation. We should
|
|
||||||
modify XUP to require this only on server initialization, but not on
|
|
||||||
resize. Microsoft's RDP protocol does not support changing
|
|
||||||
the bpp on resize.
|
|
||||||
*/
|
|
||||||
out_uint32_le(s, bpp);
|
|
||||||
out_uint32_le(s, 0);
|
out_uint32_le(s, 0);
|
||||||
|
out_uint8a(s, monitors, sizeof(monitors[0]) * num_monitors);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
int len = (int)(s->end - s->data);
|
int len = (int)(s->end - s->data);
|
||||||
s_pop_layer(s, iso_hdr);
|
s_pop_layer(s, iso_hdr);
|
||||||
out_uint32_le(s, len);
|
out_uint32_le(s, len);
|
||||||
int rv = lib_send_copy(mod, s);
|
int rv = lib_send_copy(mod, s);
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize:"
|
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_update:"
|
||||||
" sent resize message with following properties to"
|
" sent monitor updsate message with following properties to"
|
||||||
" xorgxrdp backend width=%d, height=%d, bpp=%d, return value=%d",
|
" xorgxrdp backend width=%d, height=%d, num=%d, return value=%d",
|
||||||
width, height, bpp, rv);
|
width, height, num_monitors, rv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1542,12 +1534,16 @@ lib_send_server_version_message(struct mod *mod)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* return error */
|
/* return error */
|
||||||
static int
|
static int
|
||||||
lib_send_server_monitor_resize(struct mod *mod, int width, int height)
|
lib_send_server_monitor_resize(struct mod *mod, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress)
|
||||||
{
|
{
|
||||||
/* send screen size message */
|
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
make_stream(s);
|
make_stream(s);
|
||||||
int rv = send_server_monitor_resize(mod, s, width, height, mod->bpp);
|
int rv = send_server_monitor_update(mod, s, width, height,
|
||||||
|
num_monitors, monitors);
|
||||||
|
*in_progress = (rv == 0);
|
||||||
free_stream(s);
|
free_stream(s);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1802,7 +1798,7 @@ lib_mod_process_message(struct mod *mod, struct stream *s)
|
|||||||
LOG(LOG_LEVEL_INFO, "Received memory_allocation_complete"
|
LOG(LOG_LEVEL_INFO, "Received memory_allocation_complete"
|
||||||
" command. width: %d, height: %d",
|
" command. width: %d, height: %d",
|
||||||
width, height);
|
width, height);
|
||||||
rv = mod->server_reset(mod, width, height, 0);
|
rv = mod->server_monitor_resize_done(mod);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
s->p = phold + len;
|
s->p = phold + len;
|
||||||
@ -1897,6 +1893,10 @@ lib_mod_check_wait_objs(struct mod *mod)
|
|||||||
if (mod->trans != 0)
|
if (mod->trans != 0)
|
||||||
{
|
{
|
||||||
rv = trans_check_wait_objs(mod->trans);
|
rv = trans_check_wait_objs(mod->trans);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
LOG(LOG_LEVEL_ERROR, "Xorg server closed connection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
xup/xup.h
12
xup/xup.h
@ -55,7 +55,10 @@ struct mod
|
|||||||
int (*mod_suppress_output)(struct mod *v, int suppress,
|
int (*mod_suppress_output)(struct mod *v, int suppress,
|
||||||
int left, int top, int right, int bottom);
|
int left, int top, int right, int bottom);
|
||||||
int (*mod_server_monitor_resize)(struct mod *v,
|
int (*mod_server_monitor_resize)(struct mod *v,
|
||||||
int width, int height);
|
int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors,
|
||||||
|
int *in_progress);
|
||||||
int (*mod_server_monitor_full_invalidate)(struct mod *v,
|
int (*mod_server_monitor_full_invalidate)(struct mod *v,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
int (*mod_server_version_message)(struct mod *v);
|
int (*mod_server_version_message)(struct mod *v);
|
||||||
@ -94,7 +97,10 @@ struct mod
|
|||||||
int box_left, int box_top,
|
int box_left, int box_top,
|
||||||
int box_right, int box_bottom,
|
int box_right, int box_bottom,
|
||||||
int x, int y, char *data, int data_len);
|
int x, int y, char *data, int data_len);
|
||||||
int (*server_reset)(struct mod *v, int width, int height, int bpp);
|
int (*client_monitor_resize)(struct mod *v, int width, int height,
|
||||||
|
int num_monitors,
|
||||||
|
const struct monitor_info *monitors);
|
||||||
|
int (*server_monitor_resize_done)(struct mod *v);
|
||||||
int (*server_get_channel_count)(struct mod *v);
|
int (*server_get_channel_count)(struct mod *v);
|
||||||
int (*server_query_channel)(struct mod *v, int index,
|
int (*server_query_channel)(struct mod *v, int index,
|
||||||
char *channel_name,
|
char *channel_name,
|
||||||
@ -170,7 +176,7 @@ struct mod
|
|||||||
int (*server_egfx_cmd)(struct mod *v,
|
int (*server_egfx_cmd)(struct mod *v,
|
||||||
char *cmd, int cmd_bytes,
|
char *cmd, int cmd_bytes,
|
||||||
char *data, int data_bytes);
|
char *data, int data_bytes);
|
||||||
tintptr server_dumby[100 - 49]; /* align, 100 minus the number of server
|
tintptr server_dumby[100 - 50]; /* align, 100 minus the number of server
|
||||||
functions above */
|
functions above */
|
||||||
/* common */
|
/* common */
|
||||||
tintptr handle; /* pointer to self as long */
|
tintptr handle; /* pointer to self as long */
|
||||||
|
Loading…
Reference in New Issue
Block a user