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
|
||||
matrix:
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-2
|
||||
image_family: freebsd-13-3
|
||||
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
|
||||
- git submodule update --init --recursive
|
||||
|
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@ -113,7 +113,8 @@ jobs:
|
||||
--disable-pixman"
|
||||
CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
|
||||
--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
|
||||
--enable-opus --enable-rfxcodec --enable-painter
|
||||
--disable-pixman --with-imlib2 --with-freetype2
|
||||
@ -132,7 +133,7 @@ jobs:
|
||||
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||
echo "CFLAGS=$CFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||
echo "LDFLAGS=$LDFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: "Install Dependencies"
|
||||
# See https://github.com/actions/runner-images/issues/7192
|
||||
run: |
|
||||
@ -173,9 +174,9 @@ jobs:
|
||||
id: os
|
||||
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Cache cppcheck
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-cppcheck
|
||||
with:
|
||||
@ -202,9 +203,9 @@ jobs:
|
||||
id: os
|
||||
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Cache astyle
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-astyle
|
||||
with:
|
||||
@ -213,6 +214,6 @@ jobs:
|
||||
- run: sudo scripts/install_astyle_dependencies_with_apt.sh
|
||||
- run: scripts/install_astyle.sh $ASTYLE_REPO $ASTYLE_VER
|
||||
- name: Format code with astyle
|
||||
run: scripts/run_astyle.sh
|
||||
run: scripts/run_astyle.sh -v $ASTYLE_VER
|
||||
- name: Check code formatting
|
||||
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
|
||||
* 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
|
||||
* Both inbound and outbound clipboards can now be restricted for text, files or images [Sponsored by @CyberTrust @clear-code and @kenhys] (#2087)
|
||||
A clipboard bugfix included in this release is sponsored by Krämer Pferdesport GmbH & Co KG. We very much appreciate the sponsorship.
|
||||
|
||||
## Bug fixes
|
||||
* [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)
|
||||
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.
|
||||
|
||||
## 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
|
||||
* Add a new log level TRACE more verbose than DEBUG #835 #944
|
||||
* SSH agent forwarding via RDP #867 #868 FreeRDP/FreeRDP#4122
|
||||
* Support horizontal wheel properly #928
|
||||
* GFX-RFX lossy compression levels are now selectable depending on connection type on the client (#3183, backport of #2973)
|
||||
|
||||
## 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
|
||||
* Workaround for corrupted display with Windows Server 2008 using NeutrinoRDP #869
|
||||
* Fix glitch in audio redirection by AAC #910 #936
|
||||
* Implement vsock support #930 #935 #948
|
||||
* Avoid 100% CPU usage on SSL accept #956
|
||||
## Internal changes
|
||||
* FreeBSD CI bumped to 13.3 (#3088, backport of #3104)
|
||||
|
||||
## Other changes
|
||||
* Add US Dvorak keyboard #929
|
||||
* Suppress some misleading logs #964
|
||||
* Add Finnish keyboard #972
|
||||
* Add more user-friendlier description about Xorg config #974
|
||||
* Renew pulseaudio document #984 #985
|
||||
* Lots of cleanups and refactoring
|
||||
## Changes for users
|
||||
* None since v0.10.0.
|
||||
* If moving from v0.9.x, read the v0.10.0 release note.
|
||||
|
||||
## Known issues
|
||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
||||
## Changes for packagers or developers
|
||||
* 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
|
||||
* Accept prefill credentials in base64 form #153 #811
|
||||
* Indroduce AAC encoder to audio redirection (requires Windows 10 client)
|
||||
This section notes changes since the [v0.10 branch](#branch-v010) was created.
|
||||
|
||||
## Bugfixes
|
||||
* Fix ocasional SEGV in drive redirection #838
|
||||
* 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
|
||||
## General announcements
|
||||
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.
|
||||
|
||||
## Other changes
|
||||
* Add Belgian keyboard #858
|
||||
* Add a PAM file for FreeBSD #824
|
||||
* Several refactorings and cosmetic 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!
|
||||
|
||||
## Known issues
|
||||
* Windows 10 (1703) shows black blank screen in RemoteFX mode
|
||||
* This issue is already fixed at Insider Preview build 16273
|
||||
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.
|
||||
|
||||
-----------------------
|
||||
## 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)
|
||||
|
||||
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.
|
||||
|
||||
Users who running xrdp on these systems don't need to upgrade from v0.9.3 to v0.9.3.1.
|
||||
|
||||
* Linux systems without systemd
|
||||
* non-Linux systems such as BSD operating systems
|
||||
|
||||
-----------------------
|
||||
|
||||
# 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
|
||||
* 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
|
||||
* New look of login screen (#2366)
|
||||
* 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.
|
||||
* The format of the date and time in the log file has been changed to ISO 8601 with milliseconds (#2386 #2541)
|
||||
* xrdp-sesman now supports a `--reload` switch to allow for the configuration to be changed when sessions are active (#2416)
|
||||
|
||||
## Security fixes
|
||||
* User's password could be recovered from the Xvnc password file
|
||||
* X11 authentication was not used
|
||||
None
|
||||
|
||||
## 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)
|
||||
|
||||
libcommon_la_LIBADD = \
|
||||
-lpthread -lrt \
|
||||
-lpthread \
|
||||
$(OPENSSL_LIBS) \
|
||||
$(DLOPEN_LIBS)
|
||||
|
@ -58,6 +58,10 @@
|
||||
#define SEC_TAG_CLI_4 0xc004 /* CS_CLUSTER? */
|
||||
#define SEC_TAG_CLI_MONITOR 0xc005 /* CS_MONITOR */
|
||||
#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) */
|
||||
#define RNS_UD_COLOR_4BPP 0xCA00
|
||||
@ -74,6 +78,7 @@
|
||||
|
||||
/* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */
|
||||
#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
|
||||
|
||||
/* Client Core Data: connectionType (2.2.1.3.2) */
|
||||
@ -158,9 +163,16 @@
|
||||
#define RDP5_NO_CURSOR_SHADOW 0x20
|
||||
#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) */
|
||||
#define LICENCE_TAG_USER 0x000f /* BB_CLIENT_USER_NAME_BLOB */
|
||||
#define LICENCE_TAG_HOST 0x0010 /* BB_CLIENT_MACHINE_NAME_BLOB */
|
||||
#define BB_ERROR_BLOB 0x0004
|
||||
|
||||
/* 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 */
|
||||
|
||||
@ -448,17 +460,14 @@
|
||||
#define RDP_DATA_PDU_LOGON 38
|
||||
#define RDP_DATA_PDU_FONT2 39
|
||||
#define RDP_DATA_PDU_DISCONNECT 47
|
||||
#define PDUTYPE2_MONITOR_LAYOUT_PDU 55
|
||||
|
||||
/* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */
|
||||
/* TODO: to be renamed */
|
||||
#define SEC_CLIENT_RANDOM 0x0001 /* SEC_EXCHANGE_PKT? */
|
||||
#define SEC_EXCHANGE_PKT 0x0001
|
||||
#define SEC_ENCRYPT 0x0008
|
||||
#define SEC_LOGON_INFO 0x0040 /* SEC_INFO_PKT */
|
||||
#define SEC_LICENCE_NEG 0x0080 /* SEC_LICENSE_PKT */
|
||||
|
||||
#define SEC_TAG_SRV_INFO 0x0c01 /* SC_CORE */
|
||||
#define SEC_TAG_SRV_CRYPT 0x0c02 /* SC_SECURITY */
|
||||
#define SEC_TAG_SRV_CHANNELS 0x0c03 /* SC_NET? */
|
||||
#define SEC_INFO_PKT 0x0040
|
||||
#define SEC_LICENSE_PKT 0x0080
|
||||
#define SEC_LICENSE_ENCRYPT_CS 0x0280
|
||||
|
||||
/* Slow-Path Input Event: messageType (2.2.8.1.1.3.1.1) */
|
||||
/* TODO: to be renamed */
|
||||
|
@ -378,6 +378,7 @@ g_tcp_socket(void)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EPROTONOSUPPORT: /* if IPv6 is supported, but don't have an IPv6 address */
|
||||
case EAFNOSUPPORT: /* if IPv6 not supported, retry IPv4 */
|
||||
LOG(LOG_LEVEL_INFO, "IPv6 not supported, falling back to IPv4");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,23 @@ struct display_size_description
|
||||
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
|
||||
*
|
||||
@ -163,7 +180,7 @@ struct xrdp_client_info
|
||||
int mcs_early_capability_flags;
|
||||
|
||||
int max_fastpath_frag_bytes;
|
||||
int capture_code;
|
||||
int pad0; /* unused */
|
||||
int capture_format;
|
||||
|
||||
char certificate[1024];
|
||||
@ -218,6 +235,12 @@ struct xrdp_client_info
|
||||
|
||||
int large_pointer_support_flags;
|
||||
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
|
||||
@ -237,6 +260,6 @@ enum xrdp_encoder_flags
|
||||
|
||||
/* yyyymmdd of last incompatible change to xrdp_client_info */
|
||||
/* also used for changes to all the xrdp installed headers */
|
||||
#define CLIENT_INFO_CURRENT_VERSION 20230425
|
||||
#define CLIENT_INFO_CURRENT_VERSION 20240514
|
||||
|
||||
#endif
|
||||
|
11
configure.ac
11
configure.ac
@ -1,7 +1,8 @@
|
||||
# Process this file with autoconf to produce a configure script
|
||||
|
||||
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)
|
||||
AM_INIT_AUTOMAKE([1.7.2 foreign])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
@ -166,7 +167,10 @@ AC_ARG_ENABLE(pixman, AS_HELP_STRING([--enable-pixman],
|
||||
[Use pixman library (default: no)]),
|
||||
[], [enable_pixman=no])
|
||||
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],
|
||||
[Do not use included painter library (default: no)]),
|
||||
[], [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_x264" = "xyes"] , [PKG_CHECK_MODULES(XRDP_X264, x264 >= 0.3.0)] )
|
||||
|
||||
# checking for TurboJPEG
|
||||
if test "x$enable_tjpeg" = "xyes"
|
||||
then
|
||||
@ -623,6 +629,7 @@ echo " fdkaac $enable_fdkaac"
|
||||
echo " jpeg $enable_jpeg"
|
||||
echo " turbo jpeg $enable_tjpeg"
|
||||
echo " rfxcodec $enable_rfxcodec"
|
||||
echo " x264 $enable_x264"
|
||||
echo " painter $enable_painter"
|
||||
echo " pixman $enable_pixman"
|
||||
echo " fuse $enable_fuse"
|
||||
|
@ -1,9 +1,3 @@
|
||||
if USE_FREETYPE2
|
||||
MKFV1_MAN = xrdp-mkfv1.8
|
||||
else
|
||||
MKFV1_MAN =
|
||||
endif
|
||||
|
||||
man_MANS = \
|
||||
xrdp-dis.1 \
|
||||
sesman.ini.5 \
|
||||
@ -15,10 +9,13 @@ man_MANS = \
|
||||
xrdp-sesadmin.8 \
|
||||
xrdp-sesman.8 \
|
||||
xrdp-sesrun.8 \
|
||||
xrdp-dumpfv1.8 \
|
||||
$(MKFV1_MAN)
|
||||
xrdp-dumpfv1.8
|
||||
|
||||
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 \
|
||||
-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
|
||||
|
@ -133,9 +133,12 @@ by \fBseparator\fP.
|
||||
|
||||
.TP
|
||||
\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
|
||||
password initial connection phase. In other words, xrdp doesn't allow clients to show login
|
||||
screen if set to true. If not specified, defaults to \fBfalse\fP.
|
||||
If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients
|
||||
to include username and password initial connection phase. In other
|
||||
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
|
||||
\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
|
||||
.TP
|
||||
\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
|
||||
\fBtls_ciphers\fP=\fIcipher_suite\fP
|
||||
|
@ -2,7 +2,7 @@
|
||||
Description=xrdp daemon
|
||||
Documentation=man:xrdp(8) man:xrdp.ini(5)
|
||||
Requires=xrdp-sesman.service
|
||||
After=network.target xrdp-sesman.service
|
||||
After=network-online.target xrdp-sesman.service
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
@ -10,9 +10,7 @@ EnvironmentFile=-@sysconfdir@/sysconfig/xrdp
|
||||
EnvironmentFile=-@sysconfdir@/default/xrdp
|
||||
ExecStart=@sbindir@/xrdp $XRDP_OPTIONS --nodaemon
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@basic-io @file-system @io-event @ipc @network-io @process
|
||||
SystemCallFilter=@signal @system-service ioctl madvise sysinfo uname
|
||||
SystemCallErrorNumber=EPERM
|
||||
SystemCallFilter=@system-service
|
||||
|
||||
[Install]
|
||||
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
|
||||
libxrdp_reset(struct xrdp_session *session,
|
||||
unsigned int width, unsigned int height, int bpp)
|
||||
libxrdp_reset(struct xrdp_session *session)
|
||||
{
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
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
|
||||
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
|
||||
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
|
||||
* out of range, BOTH must be ignored.
|
||||
*/
|
||||
@ -1891,16 +1888,16 @@ libxrdp_process_monitor_stream(struct stream *s,
|
||||
{
|
||||
uint32_t num_monitor;
|
||||
uint32_t monitor_index;
|
||||
struct monitor_info monitors[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS];
|
||||
struct monitor_info *monitor_layout;
|
||||
struct xrdp_rect all_monitors_encompassing_bounds = {0};
|
||||
int got_primary = 0;
|
||||
int monitor_struct_stream_check_bytes;
|
||||
const char *monitor_struct_stream_check_message;
|
||||
|
||||
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:");
|
||||
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.");
|
||||
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.";
|
||||
}
|
||||
|
||||
description->monitorCount = num_monitor;
|
||||
memset(monitors, 0, sizeof(monitors[0]) * num_monitor);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
monitor_layout = description->minfo + monitor_index;
|
||||
monitor_layout = &monitors[monitor_index];
|
||||
|
||||
if (full_parameters != 0)
|
||||
{
|
||||
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->device_scale_factor);
|
||||
|
||||
sanitise_extended_monitor_attributes(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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
return libxrdp_init_display_size_description(
|
||||
num_monitor, monitors, description);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -2283,6 +2159,163 @@ libxrdp_process_monitor_ex_stream(struct stream *s,
|
||||
|
||||
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
|
||||
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,
|
||||
int data_pdu_type);
|
||||
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,
|
||||
int data_pdu_type);
|
||||
int
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "xrdp_rail.h"
|
||||
|
||||
struct list;
|
||||
struct monitor_info;
|
||||
|
||||
/* 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,
|
||||
int font_index, int char_index);
|
||||
int
|
||||
libxrdp_reset(struct xrdp_session *session,
|
||||
unsigned int width, unsigned int height, int bpp);
|
||||
libxrdp_reset(struct xrdp_session *session);
|
||||
int
|
||||
libxrdp_orders_send_raw_bitmap2(struct xrdp_session *session,
|
||||
int width, int height, int bpp, char *data,
|
||||
@ -241,6 +241,8 @@ int
|
||||
libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
|
||||
int is_disabled);
|
||||
int
|
||||
libxrdp_drdynvc_start(struct xrdp_session *session);
|
||||
int
|
||||
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
||||
int flags, struct xrdp_drdynvc_procs *procs,
|
||||
int *chan_id);
|
||||
@ -346,4 +348,21 @@ int EXPORT_CC
|
||||
libxrdp_process_monitor_ex_stream(struct stream *s,
|
||||
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
|
||||
|
@ -48,6 +48,7 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
|
||||
struct stream *s;
|
||||
uint32_t i;
|
||||
struct display_size_description *description;
|
||||
int rv = 0;
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
@ -74,14 +75,13 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
|
||||
|
||||
s_mark_end(s);
|
||||
|
||||
if (xrdp_rdp_send_data(self, s, 0x37) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// [MS-RDPBCGR]
|
||||
// - 2.2.12.1 - ...the pduSource field MUST be set to zero.
|
||||
// - 3.3.5.12.1 - The contents of this PDU SHOULD NOT be compressed
|
||||
rv = xrdp_rdp_send_data_from_channel(self, s,
|
||||
PDUTYPE2_MONITOR_LAYOUT_PDU, 0, 0);
|
||||
free_stream(s);
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -120,6 +120,45 @@ xrdp_caps_process_general(struct xrdp_rdp *self, struct stream *s,
|
||||
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.
|
||||
@ -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);
|
||||
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
|
||||
{
|
||||
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;
|
||||
case CAPSTYPE_BITMAP:
|
||||
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;
|
||||
case CAPSTYPE_ORDER:
|
||||
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;
|
||||
}
|
||||
|
||||
/* send Monitor Layout PDU for dual monitor */
|
||||
if (self->client_info.display_sizes.monitorCount > 0 &&
|
||||
/* send Monitor Layout PDU for multi-monitor */
|
||||
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)
|
||||
{
|
||||
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
|
||||
xrdp_channel_drdynvc_start(struct xrdp_channel *self)
|
||||
{
|
||||
int index;
|
||||
int count;
|
||||
struct mcs_channel_item *ci;
|
||||
struct mcs_channel_item *dci;
|
||||
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: drdynvc_channel_id %d", self->drdynvc_channel_id);
|
||||
int rv = 0;
|
||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||
"xrdp_channel_drdynvc_start: drdynvc_channel_id %d",
|
||||
self->drdynvc_channel_id);
|
||||
if (self->drdynvc_channel_id != -1)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: already started");
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||
"xrdp_channel_drdynvc_start: already started");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Dynamic Virtual Channel named 'drdynvc' not found, "
|
||||
"channel not initialized");
|
||||
int index;
|
||||
int count;
|
||||
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 */
|
||||
int
|
||||
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
||||
int data_pdu_type)
|
||||
xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s,
|
||||
int data_pdu_type, int channel_id,
|
||||
int compress)
|
||||
{
|
||||
int len;
|
||||
int ctype;
|
||||
@ -614,7 +616,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
||||
clen = len;
|
||||
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;
|
||||
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
|
||||
{
|
||||
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",
|
||||
mppc_enc->protocol_type, mppc_enc->flags);
|
||||
}
|
||||
@ -652,11 +656,11 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
|
||||
/* TS_SHARECONTROLHEADER */
|
||||
out_uint16_le(s, pdulen); /* totalLength */
|
||||
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 "
|
||||
"totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, "
|
||||
"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 */
|
||||
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)
|
||||
{
|
||||
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 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 */
|
||||
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,
|
||||
0, 0);
|
||||
}
|
||||
xrdp_channel_drdynvc_start(self->sec_layer->chan_layer);
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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] =
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 (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
|
||||
{
|
||||
// Skip the password
|
||||
if (!s_check_rem_and_log(s, len_password + 2, "Parsing [MS-RDPBCGR] TS_INFO_PACKET Password"))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
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'
|
||||
&& 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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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
|
||||
* See also: [MS-RDPELE] 1.3.3 Licensing PDU Flows
|
||||
* Send a [MS-RDPBCGR] Server License Error PDU (2.2.1.12) with
|
||||
* STATUS_VALID_CLIENT
|
||||
*/
|
||||
/* returns error */
|
||||
static int
|
||||
@ -1213,45 +992,34 @@ xrdp_sec_send_lic_response(struct xrdp_sec *self)
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE 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");
|
||||
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPBCGR] Server License Error PDU with STATUS_VALID_CLIENT failed");
|
||||
free_stream(s);
|
||||
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"))
|
||||
{
|
||||
@ -1659,7 +1427,7 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
|
||||
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)
|
||||
{
|
||||
@ -1667,31 +1435,6 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
|
||||
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)
|
||||
{
|
||||
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,
|
||||
"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
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "client supports gfx protocol");
|
||||
|
10
mc/mc.h
10
mc/mc.h
@ -31,6 +31,9 @@
|
||||
|
||||
struct source_info;
|
||||
|
||||
/* Defined in xrdp_client_info.h */
|
||||
struct monitor_info;
|
||||
|
||||
struct mod
|
||||
{
|
||||
int size; /* size of this struct */
|
||||
@ -81,7 +84,10 @@ struct mod
|
||||
int box_left, int box_top,
|
||||
int box_right, int box_bottom,
|
||||
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_query_channel)(struct mod *v, int index,
|
||||
char *channel_name,
|
||||
@ -92,7 +98,7 @@ struct mod
|
||||
int total_data_len, int flags);
|
||||
int (*server_bell_trigger)(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 */
|
||||
/* common */
|
||||
tintptr handle; /* pointer to self as long */
|
||||
|
@ -877,8 +877,12 @@ lxrdp_server_version_message(struct mod *mod)
|
||||
|
||||
/******************************************************************************/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,10 @@ struct mod
|
||||
int (*mod_suppress_output)(struct mod *mod, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
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 width, int height);
|
||||
int (*mod_server_version_message)(struct mod *mod);
|
||||
@ -126,7 +129,10 @@ struct mod
|
||||
int box_left, int box_top,
|
||||
int box_right, int box_bottom,
|
||||
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_query_channel)(struct mod *v, int index,
|
||||
char *channel_name,
|
||||
@ -191,7 +197,7 @@ struct mod
|
||||
int flags, int frame_id);
|
||||
int (*server_session_info)(struct mod *v, const char *data,
|
||||
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 */
|
||||
/* common */
|
||||
tintptr handle; /* pointer to self as long */
|
||||
|
@ -95,7 +95,8 @@ in
|
||||
libfdk-aac-dev \
|
||||
libimlib2-dev \
|
||||
libopus-dev \
|
||||
libpixman-1-dev"
|
||||
libpixman-1-dev \
|
||||
libx264-dev"
|
||||
;;
|
||||
*)
|
||||
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
|
||||
#
|
||||
# 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
|
||||
|
||||
INSTALL_ROOT=~/astyle.local
|
||||
ASTYLE_FROM_XRDP=$INSTALL_ROOT/3.4.12/usr/bin/astyle
|
||||
MIN_ASTYLE_VER="3.1"
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@ -15,53 +18,66 @@ MIN_ASTYLE_VER="3.1"
|
||||
# ----------------------------------------------------------------------------
|
||||
usage()
|
||||
{
|
||||
echo "** Usage: $0"
|
||||
echo " e.g. $0"
|
||||
echo "** Usage: $0 [ -v version]"
|
||||
echo " e.g. $0 -v 3.4.12"
|
||||
} >&2
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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
|
||||
usage
|
||||
exit 1
|
||||
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=""
|
||||
ERROR_MESSAGE=""
|
||||
if [ ! -z "$ASTYLE_FROM_OS_VER_OUTPUT" ]; then
|
||||
# astyle is installed, so check if it's version meets the minimum requirements
|
||||
LOWEST_VERSION=`echo -e "$MIN_ASTYLE_VER\n$ASTYLE_FROM_OS_VER_OUTPUT" | sort -V | head -n1`
|
||||
if [ "$MIN_ASTYLE_VER" = "$LOWEST_VERSION" ]; then
|
||||
ASTYLE=astyle
|
||||
else
|
||||
# check if the selected astyle meets the minimum requrements
|
||||
ASTYLE_VER_OUTPUT=`$ASTYLE --version 2>/dev/null | grep "Artistic Style Version" | cut -d' ' -f4`
|
||||
|
||||
if [ ! -z "$ASTYLE_VER_OUTPUT" ]; then
|
||||
# Check the version meets the minimum requirements
|
||||
LOWEST_VERSION=`{ echo "$MIN_ASTYLE_VER" ; echo "$ASTYLE_VER_OUTPUT"; } | sort -V | head -n1`
|
||||
if [ "$MIN_ASTYLE_VER" != "$LOWEST_VERSION" ]; then
|
||||
ERROR_MESSAGE="The version of astyle installed does not meet the minimum version requirement: >= $MIN_ASTYLE_VER "
|
||||
fi
|
||||
else
|
||||
elif [ "$ASTYLE" = astyle ]; then
|
||||
ERROR_MESSAGE="astyle is not installed on the system path"
|
||||
fi
|
||||
|
||||
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
|
||||
else
|
||||
ERROR_MESSAGE="Can't find $ASTYLE"
|
||||
fi
|
||||
|
||||
if [ ! -z "$ERROR_MESSAGE" ]; then
|
||||
echo "$ERROR_MESSAGE"
|
||||
echo "$ERROR_MESSAGE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "astyle_config.as" ]; then
|
||||
echo "$0 must be run from the root xrdp repository directory which "
|
||||
echo "contains the 'astyle_config.as' file."
|
||||
echo "$0 must be run from the root xrdp repository directory which " >&2
|
||||
echo "contains the 'astyle_config.as' file." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@ -72,3 +88,5 @@ ASTYLE_FLAGS="--options=astyle_config.as --exclude=third_party ./\*.c ./\*.h"
|
||||
echo "Command: $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 \
|
||||
sesman.c \
|
||||
sesman.h \
|
||||
sesman.ini.in \
|
||||
sesexec_control.c \
|
||||
sesexec_control.h \
|
||||
session_list.c \
|
||||
@ -52,7 +53,7 @@ SUFFIXES = .in
|
||||
.in:
|
||||
$(subst_verbose)$(SUBST_VARS) $< > $@
|
||||
|
||||
dist_sesmansysconf_DATA = \
|
||||
nodist_sesmansysconf_DATA = \
|
||||
sesman.ini
|
||||
|
||||
dist_sesmansysconf_SCRIPTS = \
|
||||
@ -64,3 +65,5 @@ SUBDIRS = \
|
||||
sesexec \
|
||||
tools \
|
||||
chansrv
|
||||
|
||||
CLEANFILES = $(nodist_sesmansysconf_DATA)
|
||||
|
@ -202,7 +202,7 @@ struct state_lookup
|
||||
{
|
||||
fuse_req_t req; /* Original FUSE request from lookup */
|
||||
fuse_ino_t pinum; /* inum of parent directory */
|
||||
char name[XFS_MAXFILENAMELEN];
|
||||
char name[XFS_MAXFILENAMELEN + 1];
|
||||
/* Name to look up */
|
||||
fuse_ino_t existing_inum;
|
||||
/* inum of an existing entry */
|
||||
@ -241,7 +241,7 @@ struct state_create
|
||||
fuse_req_t req; /* Original FUSE request from lookup */
|
||||
struct fuse_file_info fi; /* File info struct passed to open */
|
||||
fuse_ino_t pinum; /* inum of parent directory */
|
||||
char name[XFS_MAXFILENAMELEN];
|
||||
char name[XFS_MAXFILENAMELEN + 1];
|
||||
/* Name of file in parent directory */
|
||||
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_ino_t pinum; /* inum of 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 */
|
||||
};
|
||||
|
||||
@ -540,10 +540,25 @@ xfuse_init(void)
|
||||
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
|
||||
* 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, '/');
|
||||
if (p != NULL)
|
||||
{
|
||||
@ -554,11 +569,6 @@ xfuse_init(void)
|
||||
g_fuse_root_parent_ino = g_file_get_inode_num(g_fuse_root_path);
|
||||
*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)
|
||||
{
|
||||
@ -568,18 +578,6 @@ xfuse_init(void)
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_parse_cmdline() failed");
|
||||
LOG(LOG_LEVEL_ERROR, "fuse_parse_cmdline() failed");
|
||||
fuse_opt_free_args(args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
g_ch = 0;
|
||||
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);
|
||||
XFS_INODE_ALL *xino1 = NULL;
|
||||
XFS_INODE_ALL *xino2 = NULL;
|
||||
char *xino1_name = NULL;
|
||||
char *xino2_name = 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) ||
|
||||
xfs->inode_table == 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(xino2);
|
||||
free(xino1_name);
|
||||
free(xino2_name);
|
||||
xfs_delete_xfs_fs(xfs);
|
||||
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.mtime = 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.is_redirected = 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.mtime = 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.is_redirected = 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;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
static void
|
||||
xfs_free_inode(XFS_INODE_ALL *xino)
|
||||
{
|
||||
if (xino != NULL)
|
||||
{
|
||||
free(xino->pub.name);
|
||||
free(xino);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
void
|
||||
xfs_delete_xfs_fs(struct xfs_fs *xfs)
|
||||
@ -363,7 +380,7 @@ xfs_delete_xfs_fs(struct xfs_fs *xfs)
|
||||
size_t 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);
|
||||
@ -407,9 +424,14 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
|
||||
if (xfs->free_count > 0 ||
|
||||
grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY))
|
||||
{
|
||||
XFS_INODE_ALL *xino = NULL;
|
||||
|
||||
if ((xino = g_new0(XFS_INODE_ALL, 1)) != NULL)
|
||||
XFS_INODE_ALL *xino = g_new0(XFS_INODE_ALL, 1);
|
||||
char *cpyname = strdup(name);
|
||||
if (xino == NULL || cpyname == NULL)
|
||||
{
|
||||
free(xino);
|
||||
free(cpyname);
|
||||
}
|
||||
else
|
||||
{
|
||||
fuse_ino_t inum = xfs->free_list[--xfs->free_count];
|
||||
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.mtime = 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.is_redirected = parent->pub.is_redirected;
|
||||
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.
|
||||
*/
|
||||
++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 *parent;
|
||||
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];
|
||||
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);
|
||||
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)
|
||||
{
|
||||
/* Same directory, but name has changed */
|
||||
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
|
||||
{
|
||||
/* Name collision - remove destination entry */
|
||||
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;
|
||||
}
|
||||
free (cpyname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -29,7 +29,11 @@
|
||||
|
||||
#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
|
||||
@ -37,6 +41,9 @@
|
||||
struct xfs_fs;
|
||||
struct xfs_dir_handle;
|
||||
|
||||
/**
|
||||
* Describe an inode in the XFS filesystem
|
||||
*/
|
||||
typedef struct xfs_inode
|
||||
{
|
||||
fuse_ino_t inum; /* File serial number. */
|
||||
@ -47,7 +54,7 @@ typedef struct xfs_inode
|
||||
time_t atime; /* Time of last access. */
|
||||
time_t mtime; /* Time of last modification. */
|
||||
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 */
|
||||
char is_redirected; /* file is on redirected device */
|
||||
tui32 device_id; /* device ID of redirected device */
|
||||
|
@ -181,14 +181,8 @@ x-special/gnome-copied-files
|
||||
#include "ms-rdpeclip.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
static char g_bmp_image_header[] =
|
||||
{
|
||||
/* 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
|
||||
};
|
||||
#define BMPFILEHEADER_LEN 14
|
||||
#define BMPINFOHEADER_LEN 40
|
||||
|
||||
extern int g_cliprdr_chan_id; /* in chansrv.c */
|
||||
|
||||
@ -1135,6 +1129,7 @@ clipboard_process_data_response_for_image(struct stream *s,
|
||||
{
|
||||
XSelectionRequestEvent *lxev;
|
||||
int len;
|
||||
struct stream *bmp_hs;
|
||||
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: "
|
||||
"CLIPRDR_DATA_RESPONSE_FOR_IMAGE");
|
||||
@ -1148,20 +1143,45 @@ clipboard_process_data_response_for_image(struct stream *s,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
g_clip_c2s.total_bytes = 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_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 "
|
||||
"clipboard_provide_selection_c2s");
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
@ -52,8 +53,8 @@ extern char g_fuse_clipboard_path[];
|
||||
|
||||
struct cb_file_info
|
||||
{
|
||||
char pathname[256];
|
||||
char filename[256];
|
||||
char *pathname;
|
||||
char *filename;
|
||||
int flags;
|
||||
int size;
|
||||
tui64 time;
|
||||
@ -82,6 +83,103 @@ timeval2wintime(struct timeval *tv)
|
||||
}
|
||||
#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
|
||||
*
|
||||
@ -113,54 +211,13 @@ clipboard_send_filecontents_response_fail(int streamId)
|
||||
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
|
||||
clipboard_get_file(const char *file, int bytes)
|
||||
{
|
||||
int sindex;
|
||||
int pindex;
|
||||
int flags;
|
||||
char full_fn[256]; /* /etc/xrdp/xrdp.ini */
|
||||
char filename[256]; /* xrdp.ini */
|
||||
char pathname[256]; /* /etc/xrdp */
|
||||
char *full_fn;
|
||||
struct cb_file_info *cfi;
|
||||
int result = 1;
|
||||
|
||||
/* x-special/gnome-copied-files */
|
||||
if ((g_strncmp(file, "copy", 4) == 0) && (bytes == 4))
|
||||
@ -171,35 +228,23 @@ clipboard_get_file(const char *file, int bytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
sindex = 0;
|
||||
flags = CB_FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
/* text/uri-list */
|
||||
/* 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;
|
||||
while (pindex > sindex)
|
||||
else
|
||||
{
|
||||
if (file[pindex] == '/')
|
||||
{
|
||||
break;
|
||||
}
|
||||
pindex--;
|
||||
full_fn = decode_rfc3986(file, bytes);
|
||||
}
|
||||
g_memset(pathname, 0, 256);
|
||||
g_memset(filename, 0, 256);
|
||||
g_memcpy(pathname, file + sindex, pindex - sindex);
|
||||
if (pathname[0] == 0)
|
||||
|
||||
if (full_fn == NULL)
|
||||
{
|
||||
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,
|
||||
@ -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 "
|
||||
"%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, "
|
||||
"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",
|
||||
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
|
||||
{
|
||||
cfi = (struct cb_file_info *)g_malloc(sizeof(struct cb_file_info), 1);
|
||||
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->flags = flags;
|
||||
cfi->flags = CB_FILE_ATTRIBUTE_ARCHIVE;
|
||||
cfi->time = (g_time1() + CB_EPOCH_DIFF) * 10000000LL;
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "ok filename [%s] pathname [%s] size [%d]",
|
||||
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
|
||||
clipboard_get_files(const char *files, int bytes)
|
||||
{
|
||||
int index;
|
||||
int file_index;
|
||||
char file[512];
|
||||
const char *start = files;
|
||||
const char *end = files + bytes;
|
||||
const char *p;
|
||||
|
||||
file_index = 0;
|
||||
for (index = 0; index < bytes; index++)
|
||||
for (p = start ; p < end ; ++p)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
file_index = 0;
|
||||
/* Get file. Errors are logged */
|
||||
(void)clipboard_get_file(start, p - start);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file[file_index] = files[index];
|
||||
file_index++;
|
||||
|
||||
/* Move the start of filename pointer to either 'end', or
|
||||
* the next character which will either be a filename or
|
||||
* another terminator */
|
||||
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)
|
||||
{
|
||||
@ -492,10 +538,12 @@ clipboard_send_file_data(int streamId, int lindex,
|
||||
make_stream(s);
|
||||
init_stream(s, cbRequested + 64);
|
||||
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",
|
||||
cbRequested, size);
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR,
|
||||
"clipboard_send_file_data: read error, want %d got [%s]",
|
||||
cbRequested, g_get_strerror());
|
||||
free_stream(s);
|
||||
g_file_close(fd);
|
||||
clipboard_send_filecontents_response_fail(streamId);
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "log.h"
|
||||
#include "chansrv.h"
|
||||
#include "chansrv_fuse.h"
|
||||
#include "chansrv_xfs.h"
|
||||
#include "devredir.h"
|
||||
#include "smartcard.h"
|
||||
#include "ms-rdpefs.h"
|
||||
@ -1249,7 +1250,13 @@ devredir_proc_query_dir_response(IRP *irp,
|
||||
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];
|
||||
#endif
|
||||
tui64 LastAccessTime;
|
||||
tui64 LastWriteTime;
|
||||
tui64 EndOfFile;
|
||||
|
@ -102,6 +102,14 @@ process_sys_login_request(struct pre_session_item *psi)
|
||||
}
|
||||
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
|
||||
*
|
||||
* 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
|
||||
create_xrdp_socket_path(uid_t uid)
|
||||
{
|
||||
// Owner all permissions, group read+execute
|
||||
#define RWX_PERMS 0x750
|
||||
|
||||
int rv = 1;
|
||||
const char *sockdir_group = g_cfg->sec.session_sockdir_group;
|
||||
int gid = 0; // Default if no group specified
|
||||
@ -330,14 +341,21 @@ create_xrdp_socket_path(uid_t uid)
|
||||
char sockdir[XRDP_SOCKETS_MAXPATH];
|
||||
g_snprintf(sockdir, sizeof(sockdir), XRDP_SOCKET_PATH, (int)uid);
|
||||
|
||||
// Create directory permissions 0x750, if it doesn't exist already.
|
||||
int old_umask = g_umask_hex(0x750 ^ 0x777);
|
||||
// Create directory permissions RWX_PERMS, if it doesn't exist already
|
||||
// (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))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"create_xrdp_socket_path: Can't create %s [%s]",
|
||||
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' &&
|
||||
g_getgroup_info(sockdir_group, &gid) != 0)
|
||||
{
|
||||
@ -358,6 +376,7 @@ create_xrdp_socket_path(uid_t uid)
|
||||
(void)g_umask_hex(old_umask);
|
||||
|
||||
return rv;
|
||||
#undef RWX_PERMS
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -579,8 +579,9 @@ print_version(void)
|
||||
{
|
||||
g_writeln("xrdp-sesman %s", PACKAGE_VERSION);
|
||||
g_writeln(" The xrdp session manager");
|
||||
g_writeln(" Copyright (C) 2004-2023 Jay Sorg, "
|
||||
"Neutrino Labs, and all contributors.");
|
||||
g_writeln(" Copyright (C) 2004-%d Jay Sorg, "
|
||||
"Neutrino Labs, and all contributors.",
|
||||
VERSION_YEAR);
|
||||
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
||||
g_writeln("%s", "");
|
||||
|
||||
|
@ -209,9 +209,12 @@ x_server_running_check_ports(int display)
|
||||
/******************************************************************************/
|
||||
/* Helper function for get_sorted_display_list():qsort() */
|
||||
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();
|
||||
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);
|
||||
}
|
||||
ck_assert_int_ne(pid, 0);
|
||||
|
@ -1,4 +1,5 @@
|
||||
AM_CPPFLAGS = \
|
||||
-DXRDP_TOP_SRCDIR=\"$(top_srcdir)\" \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir)/xrdp \
|
||||
-I$(top_srcdir)/libxrdp \
|
||||
@ -18,7 +19,14 @@ EXTRA_DIST = \
|
||||
test_not4_8bit.bmp \
|
||||
test_not4_24bit.bmp \
|
||||
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
|
||||
check_PROGRAMS = test_xrdp
|
||||
@ -28,6 +36,7 @@ test_xrdp_SOURCES = \
|
||||
test_xrdp_main.c \
|
||||
test_xrdp_egfx.c \
|
||||
test_xrdp_region.c \
|
||||
test_tconfig.c \
|
||||
test_bitmap_load.c
|
||||
|
||||
test_xrdp_CFLAGS = \
|
||||
@ -47,6 +56,7 @@ test_xrdp_LDADD = \
|
||||
$(top_builddir)/libxrdp/libxrdp.la \
|
||||
$(top_builddir)/libpainter/src/libpainter.la \
|
||||
$(top_builddir)/librfxcodec/src/librfxencode.la \
|
||||
$(top_builddir)/third_party/tomlc99/libtoml.la \
|
||||
$(top_builddir)/xrdp/lang.o \
|
||||
$(top_builddir)/xrdp/xrdp_mm.o \
|
||||
$(top_builddir)/xrdp/xrdp_wm.o \
|
||||
@ -60,8 +70,16 @@ test_xrdp_LDADD = \
|
||||
$(top_builddir)/xrdp/xrdp_encoder.o \
|
||||
$(top_builddir)/xrdp/xrdp_process.o \
|
||||
$(top_builddir)/xrdp/xrdp_login_wnd.o \
|
||||
$(top_builddir)/xrdp/xrdp_tconfig.o \
|
||||
$(top_builddir)/xrdp/xrdp_main_utils.o \
|
||||
$(PIXMAN_LIBS) \
|
||||
$(IMLIB2_LIBS) \
|
||||
@CHECK_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_egfx_base_functions(void);
|
||||
Suite *make_suite_region(void);
|
||||
Suite *make_suite_tconfig_load_gfx(void);
|
||||
|
||||
#endif /* TEST_XRDP_H */
|
||||
|
@ -57,6 +57,7 @@ int main (void)
|
||||
sr = srunner_create (make_suite_test_bitmap_load());
|
||||
srunner_add_suite(sr, make_suite_egfx_base_functions());
|
||||
srunner_add_suite(sr, make_suite_region());
|
||||
srunner_add_suite(sr, make_suite_tconfig_load_gfx());
|
||||
|
||||
srunner_set_tap(sr, "-");
|
||||
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 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,
|
||||
const struct vnc_screen *b)
|
||||
{
|
||||
int result = 0;
|
||||
if (a->id != b->id)
|
||||
{
|
||||
result = a->id - b->id;
|
||||
}
|
||||
else if (a->x != b->x)
|
||||
if (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
|
||||
*
|
||||
* @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 layout->total_width is untouched
|
||||
* @post layout->total_height is untouched
|
||||
@ -225,10 +219,8 @@ read_extended_desktop_size_rect(struct vnc *v,
|
||||
struct stream *s;
|
||||
int error;
|
||||
unsigned int count;
|
||||
struct vnc_screen *screens;
|
||||
|
||||
layout->count = 0;
|
||||
layout->s = NULL;
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
@ -239,46 +231,41 @@ read_extended_desktop_size_rect(struct vnc *v,
|
||||
{
|
||||
/* Get the number of screens */
|
||||
in_uint8(s, count);
|
||||
in_uint8s(s, 3);
|
||||
|
||||
error = trans_force_read_s(v->trans, s, 16 * count);
|
||||
if (error == 0)
|
||||
if (count <= 0 || count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
|
||||
{
|
||||
screens = g_new(struct vnc_screen, count);
|
||||
if (screens == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"VNC : Can't alloc for %d screens", count);
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Bad monitor count %d in ExtendedDesktopSize rectangle",
|
||||
count);
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_uint8s(s, 3);
|
||||
|
||||
error = trans_force_read_s(v->trans, s, 16 * count);
|
||||
if (error == 0)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0 ; i < count ; ++i)
|
||||
{
|
||||
in_uint32_be(s, screens[i].id);
|
||||
in_uint16_be(s, screens[i].x);
|
||||
in_uint16_be(s, screens[i].y);
|
||||
in_uint16_be(s, screens[i].width);
|
||||
in_uint16_be(s, screens[i].height);
|
||||
in_uint32_be(s, screens[i].flags);
|
||||
in_uint32_be(s, layout->s[i].id);
|
||||
in_uint16_be(s, layout->s[i].x);
|
||||
in_uint16_be(s, layout->s[i].y);
|
||||
in_uint16_be(s, layout->s[i].width);
|
||||
in_uint16_be(s, layout->s[i].height);
|
||||
in_uint32_be(s, layout->s[i].flags);
|
||||
}
|
||||
|
||||
/* sort monitors in increasing ID order */
|
||||
qsort(screens, count, sizeof(screens[0]),
|
||||
/* sort monitors in increasing (x,y) order */
|
||||
qsort(layout->s, count, sizeof(layout->s[0]),
|
||||
(int (*)(const void *, const void *))cmp_vnc_screen);
|
||||
layout->count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_stream(s);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
layout->count = count;
|
||||
layout->s = screens;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* @param layout Structure to set up
|
||||
* @param width New client width
|
||||
* @param height New client height
|
||||
*
|
||||
* @pre layout->count must be valid
|
||||
* @pre layout->s must be valid
|
||||
* Initialises a vnc_screen_layout as a single screen
|
||||
* @param[in] width Screen Width
|
||||
* @param[in] height Screen Height
|
||||
* @param[out] layout Layout to initialise
|
||||
*/
|
||||
static void
|
||||
set_single_screen_layout(struct vnc_screen_layout *layout,
|
||||
int width, int height)
|
||||
init_single_screen_layout(int width, int height,
|
||||
struct vnc_screen_layout *layout)
|
||||
{
|
||||
int id = 0;
|
||||
int flags = 0;
|
||||
|
||||
layout->total_width = width;
|
||||
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->s[0].id = id;
|
||||
layout->s[0].id = 0;
|
||||
layout->s[0].x = 0;
|
||||
layout->s[0].y = 0;
|
||||
layout->s[0].width = width;
|
||||
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 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
|
||||
*
|
||||
* The new client layout is recorded in v->client_layout. If the client was
|
||||
* multi-screen before this call, it won't be afterwards.
|
||||
* The new client layout is recorded in v->client_layout.
|
||||
*/
|
||||
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;
|
||||
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 ||
|
||||
v->client_layout.total_width != width ||
|
||||
v->client_layout.total_height != height)
|
||||
if (sl->count <= 0 ||
|
||||
sl->count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
|
||||
{
|
||||
if (update_in_progress)
|
||||
{
|
||||
error = v->server_end_update(v);
|
||||
}
|
||||
LOG(LOG_LEVEL_ERROR, "%s: Programming error. Bad monitors %d",
|
||||
__func__, sl->count);
|
||||
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)
|
||||
{
|
||||
error = v->server_reset(v, width, height, v->server_bpp);
|
||||
if (error == 0)
|
||||
{
|
||||
set_single_screen_layout(&v->client_layout, width, height);
|
||||
if (update_in_progress)
|
||||
{
|
||||
error = v->server_begin_update(v);
|
||||
}
|
||||
}
|
||||
v->client_layout = *sl;
|
||||
}
|
||||
|
||||
if (update_in_progress && v->server_begin_update(v) != 0)
|
||||
{
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 update_in_progress True if there's a painter update in progress
|
||||
* @param layout Desired layout from server
|
||||
* @return != 0 for error
|
||||
*
|
||||
* This has some limitations. We have no way to move multiple screens about
|
||||
* on a connected client, and so we are not able to change the client unless
|
||||
* we're changing to a single screen layout.
|
||||
* The new client layout is recorded in v->client_layout.
|
||||
*/
|
||||
static int
|
||||
resize_client_from_layout(struct vnc *v,
|
||||
int update_in_progress,
|
||||
const struct vnc_screen_layout *layout)
|
||||
resize_server_to_client_layout(struct vnc *v)
|
||||
{
|
||||
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
|
||||
* than a single screen.
|
||||
* If we've only got one screen, and the other side has
|
||||
* 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,
|
||||
"VNC Resize to %d screen(s) from %d screen(s) "
|
||||
"not implemented",
|
||||
v->client_layout.count, layout->count);
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC "
|
||||
"setting screen id to %d from server",
|
||||
v->server_layout.s[0].id);
|
||||
|
||||
/* Dump some useful info, in case we get here when we don't
|
||||
* need to */
|
||||
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);
|
||||
v->client_layout.s[0].id = v->server_layout.s[0].id;
|
||||
v->client_layout.s[0].flags = v->server_layout.s[0].flags;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -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, y, cx, cy);
|
||||
error = read_extended_desktop_size_rect(v, &layout);
|
||||
g_free(layout.s);
|
||||
}
|
||||
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
|
||||
* 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 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_layout Returned layout for the encoding
|
||||
* @return != 0 for error
|
||||
*
|
||||
* @post After a successful call, match_layout.s must be free'd
|
||||
*/
|
||||
static int
|
||||
find_matching_extended_rect(struct vnc *v,
|
||||
@ -971,8 +946,7 @@ find_matching_extended_rect(struct vnc *v,
|
||||
int cx;
|
||||
int cy;
|
||||
encoding_type encoding;
|
||||
|
||||
match_layout->s = NULL;
|
||||
int found = 0;
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
@ -1002,14 +976,14 @@ find_matching_extended_rect(struct vnc *v,
|
||||
in_uint32_be(s, encoding);
|
||||
|
||||
if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE &&
|
||||
match_layout->s == NULL &&
|
||||
!found &&
|
||||
match(x, y, cx, cy))
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"VNC matched ExtendedDesktopSize rectangle "
|
||||
"x=%d, y=%d geom=%dx%d",
|
||||
x, y, cx, cy);
|
||||
|
||||
found = 1;
|
||||
error = read_extended_desktop_size_rect(v, match_layout);
|
||||
if (match_x)
|
||||
{
|
||||
@ -1065,6 +1039,7 @@ send_update_request_for_resize_status(struct vnc *v)
|
||||
switch (v->resize_status)
|
||||
{
|
||||
case VRS_WAITING_FOR_FIRST_UPDATE:
|
||||
case VRS_WAITING_FOR_RESIZE_CONFIRM:
|
||||
/*
|
||||
* 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);
|
||||
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:
|
||||
/*
|
||||
* 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_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->server_width);
|
||||
out_uint16_be(s, v->server_height);
|
||||
out_uint16_be(s, v->server_layout.total_width);
|
||||
out_uint16_be(s, v->server_layout.total_height);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
}
|
||||
@ -1159,12 +1120,15 @@ lib_framebuffer_first_update(struct vnc *v)
|
||||
&layout);
|
||||
if (error == 0)
|
||||
{
|
||||
if (layout.s != NULL)
|
||||
if (layout.count > 0)
|
||||
{
|
||||
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 */
|
||||
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
|
||||
@ -1184,32 +1148,19 @@ lib_framebuffer_first_update(struct vnc *v)
|
||||
v->client_layout.s[0].flags = layout.s[0].flags;
|
||||
}
|
||||
|
||||
if (vnc_screen_layouts_equal(&layout, &v->client_layout))
|
||||
{
|
||||
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;
|
||||
}
|
||||
resize_server_to_client_layout(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC server does not support resizing");
|
||||
v->resize_supported = VRSS_NOT_SUPPORTED;
|
||||
|
||||
/* Force client to same size as server */
|
||||
LOG(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d",
|
||||
v->server_width, v->server_height);
|
||||
error = resize_client(v, 0, v->server_width, v->server_height);
|
||||
v->server_layout.total_width, v->server_layout.total_height);
|
||||
error = resize_client_to_server(v, 0);
|
||||
v->resize_status = VRS_DONE;
|
||||
}
|
||||
|
||||
g_free(layout.s);
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
@ -1224,7 +1175,7 @@ lib_framebuffer_first_update(struct vnc *v)
|
||||
* Looks for a resize confirm in a framebuffer update request
|
||||
*
|
||||
* 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
|
||||
* @return != 0 for error
|
||||
@ -1243,18 +1194,17 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
|
||||
&layout);
|
||||
if (error == 0)
|
||||
{
|
||||
if (layout.s != NULL)
|
||||
if (layout.count > 0)
|
||||
{
|
||||
if (response_code == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized");
|
||||
log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout);
|
||||
v->server_layout = layout;
|
||||
// If this resize was requested by the client mid-session
|
||||
// (dynamic resize), we need to tell xrdp_mm that
|
||||
// it's OK to continue with the resize state machine.
|
||||
// We do this by sending a reset with bpp == 0
|
||||
error = v->server_reset(v, v->server_width,
|
||||
v->server_height, 0);
|
||||
error = v->server_monitor_resize_done(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1263,14 +1213,11 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
|
||||
response_code,
|
||||
rfb_get_eds_status_msg(response_code));
|
||||
/* Force client to same size as server */
|
||||
LOG(LOG_LEVEL_WARNING, "Resizing client to server %dx%d",
|
||||
v->server_width, v->server_height);
|
||||
error = resize_client(v, 0, v->server_width, v->server_height);
|
||||
LOG(LOG_LEVEL_WARNING, "Resizing client to server");
|
||||
error = resize_client_to_server(v, 0);
|
||||
}
|
||||
v->resize_status = VRS_DONE;
|
||||
}
|
||||
|
||||
g_free(layout.s);
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
@ -1415,9 +1362,8 @@ lib_framebuffer_update(struct vnc *v)
|
||||
else if (encoding == RFB_ENC_DESKTOP_SIZE)
|
||||
{
|
||||
/* Server end has resized */
|
||||
v->server_width = cx;
|
||||
v->server_height = cy;
|
||||
error = resize_client(v, 1, cx, cy);
|
||||
init_single_screen_layout(cx, cy, &v->server_layout);
|
||||
error = resize_client_to_server(v, 1);
|
||||
}
|
||||
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 (error == 0 && x != 1)
|
||||
{
|
||||
v->server_width = layout.total_width;
|
||||
v->server_height = layout.total_height;
|
||||
error = resize_client_from_layout(v, 1, &layout);
|
||||
if (!vnc_screen_layouts_equal(&v->server_layout, &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
|
||||
{
|
||||
@ -1456,8 +1405,8 @@ lib_framebuffer_update(struct vnc *v)
|
||||
out_uint8(s, 1); /* incremental == 1 : Changes only */
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->server_width);
|
||||
out_uint16_be(s, v->server_height);
|
||||
out_uint16_be(s, v->server_layout.total_width);
|
||||
out_uint16_be(s, v->server_layout.total_height);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
}
|
||||
@ -1831,8 +1780,11 @@ lib_mod_connect(struct vnc *v)
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
in_uint16_be(s, v->server_width);
|
||||
in_uint16_be(s, v->server_height);
|
||||
int width;
|
||||
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);
|
||||
v->server_msg(v, "VNC receiving pixel format", 0);
|
||||
@ -2000,6 +1952,7 @@ lib_mod_connect(struct vnc *v)
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
v->resize_supported = VRSS_UNKNOWN;
|
||||
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
|
||||
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.
|
||||
*
|
||||
* @param [out] layout Our layout
|
||||
* @param [in] client_info WM info
|
||||
* @param v VNC module
|
||||
* @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
|
||||
init_client_layout(struct vnc_screen_layout *layout,
|
||||
const struct xrdp_client_info *client_info)
|
||||
init_client_layout(struct vnc *v,
|
||||
int width, int height,
|
||||
int num_monitors,
|
||||
const struct monitor_info *monitors)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
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)
|
||||
struct vnc_screen_layout *layout = &v->client_layout;
|
||||
if (!v->multimon_configured || num_monitors < 1)
|
||||
{
|
||||
/* Use minfo_wm, as this is normalised for a top-left of (0,0)
|
||||
* as required by RFC6143 */
|
||||
layout->s[i].id = i;
|
||||
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->s[i].width = client_info->display_sizes.minfo_wm[i].right -
|
||||
client_info->display_sizes.minfo_wm[i].left + 1;
|
||||
layout->s[i].height = client_info->display_sizes.minfo_wm[i].bottom -
|
||||
client_info->display_sizes.minfo_wm[i].top + 1;
|
||||
layout->s[i].flags = 0;
|
||||
init_single_screen_layout(width, height, layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
layout->total_width = width;
|
||||
layout->total_height = height;
|
||||
layout->count = num_monitors;
|
||||
|
||||
unsigned int i;
|
||||
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 *) value;
|
||||
|
||||
g_free(v->client_layout.s);
|
||||
v->multimon_configured = client_info->multimon;
|
||||
|
||||
/* Save monitor information from the client */
|
||||
if (!client_info->multimon || client_info->display_sizes.monitorCount < 1)
|
||||
{
|
||||
set_single_screen_layout(&v->client_layout,
|
||||
client_info->display_sizes.session_width,
|
||||
client_info->display_sizes.session_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
init_client_layout(&v->client_layout, client_info);
|
||||
}
|
||||
/* Save monitor information from the client
|
||||
* Use minfo_wm, as this is normalised for a top-left of (0,0)
|
||||
* as required by RFC6143 */
|
||||
init_client_layout(v,
|
||||
client_info->display_sizes.session_width,
|
||||
client_info->display_sizes.session_height,
|
||||
client_info->display_sizes.monitorCount,
|
||||
client_info->display_sizes.minfo_wm);
|
||||
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)
|
||||
{
|
||||
rv = trans_check_wait_objs(v->trans);
|
||||
if (rv != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "VNC server closed connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
@ -2217,8 +2178,8 @@ lib_mod_suppress_output(struct vnc *v, int suppress,
|
||||
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->server_width);
|
||||
out_uint16_be(s, v->server_height);
|
||||
out_uint16_be(s, v->server_layout.total_width);
|
||||
out_uint16_be(s, v->server_layout.total_height);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
free_stream(s);
|
||||
@ -2237,12 +2198,29 @@ lib_mod_server_version_message(struct vnc *v)
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
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;
|
||||
set_single_screen_layout(&v->client_layout, width, height);
|
||||
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
|
||||
error = send_update_request_for_resize_status(v);
|
||||
int error;
|
||||
*in_progress = 0;
|
||||
init_client_layout(v, width, height, num_monitors, monitors);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2298,7 +2276,6 @@ mod_exit(tintptr handle)
|
||||
return 0;
|
||||
}
|
||||
trans_delete(v->trans);
|
||||
g_free(v->client_layout.s);
|
||||
vnc_clip_exit(v);
|
||||
g_free(v);
|
||||
return 0;
|
||||
|
32
vnc/vnc.h
32
vnc/vnc.h
@ -27,6 +27,7 @@
|
||||
#include "os_calls.h"
|
||||
#include "defines.h"
|
||||
#include "guid.h"
|
||||
#include "ms-rdpbcgr.h"
|
||||
|
||||
#define CURRENT_MOD_VER 4
|
||||
|
||||
@ -46,8 +47,8 @@ struct vnc_screen_layout
|
||||
int total_width;
|
||||
int total_height;
|
||||
unsigned int count;
|
||||
/* For comparison, screens are sorted in increasing order of ID */
|
||||
struct vnc_screen *s;
|
||||
/* For comparison, screens are sorted in x, y, width, height) order */
|
||||
struct vnc_screen s[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -60,11 +61,21 @@ enum vnc_resize_status
|
||||
VRS_DONE
|
||||
};
|
||||
|
||||
enum vnc_resize_support_status
|
||||
{
|
||||
VRSS_NOT_SUPPORTED,
|
||||
VRSS_SUPPORTED,
|
||||
VRSS_UNKNOWN
|
||||
};
|
||||
|
||||
struct source_info;
|
||||
|
||||
/* Defined in vnc_clip.c */
|
||||
struct vnc_clipboard_data;
|
||||
|
||||
/* Defined in xrdp_client_info.h */
|
||||
struct monitor_info;
|
||||
|
||||
struct vnc
|
||||
{
|
||||
int size; /* size of this struct */
|
||||
@ -85,7 +96,10 @@ struct vnc
|
||||
int (*mod_suppress_output)(struct vnc *v, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
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 width, int height);
|
||||
int (*mod_server_version_message)(struct vnc *v);
|
||||
@ -123,7 +137,10 @@ struct vnc
|
||||
int box_left, int box_top,
|
||||
int box_right, int box_bottom,
|
||||
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_query_channel)(struct vnc *v, int index,
|
||||
char *channel_name,
|
||||
@ -134,7 +151,7 @@ struct vnc
|
||||
int total_data_len, int flags);
|
||||
int (*server_bell_trigger)(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 */
|
||||
/* common */
|
||||
tintptr handle; /* pointer to self as long */
|
||||
@ -142,8 +159,6 @@ struct vnc
|
||||
tintptr painter;
|
||||
struct source_info *si;
|
||||
/* mod data */
|
||||
int server_width;
|
||||
int server_height;
|
||||
int server_bpp;
|
||||
char mod_name[256];
|
||||
int mod_mouse_state;
|
||||
@ -164,8 +179,11 @@ struct vnc
|
||||
int suppress_output;
|
||||
unsigned int enabled_encodings_mask;
|
||||
/* Resizeable support */
|
||||
int multimon_configured;
|
||||
struct vnc_screen_layout client_layout;
|
||||
struct vnc_screen_layout server_layout;
|
||||
enum vnc_resize_status resize_status;
|
||||
enum vnc_resize_support_status resize_supported;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -19,6 +19,7 @@ AM_CPPFLAGS = \
|
||||
$(IMLIB2_CFLAGS)
|
||||
|
||||
XRDP_EXTRA_LIBS =
|
||||
XRDP_EXTRA_SOURCES =
|
||||
|
||||
if XRDP_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
|
||||
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
|
||||
AM_CPPFLAGS += -DXRDP_PIXMAN
|
||||
AM_CPPFLAGS += $(PIXMAN_CFLAGS)
|
||||
@ -46,6 +54,7 @@ xrdp_SOURCES = \
|
||||
lang.c \
|
||||
xrdp.c \
|
||||
xrdp.h \
|
||||
xrdp.ini.in \
|
||||
xrdp_bitmap.c \
|
||||
xrdp_bitmap_load.c \
|
||||
xrdp_bitmap_common.c \
|
||||
@ -63,7 +72,10 @@ xrdp_SOURCES = \
|
||||
xrdp_egfx.c \
|
||||
xrdp_egfx.h \
|
||||
xrdp_wm.c \
|
||||
xrdp_main_utils.c
|
||||
xrdp_main_utils.c \
|
||||
xrdp_tconfig.c \
|
||||
xrdp_tconfig.h \
|
||||
$(XRDP_EXTRA_SOURCES)
|
||||
|
||||
xrdp_LDADD = \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
@ -93,9 +105,12 @@ SUFFIXES = .in
|
||||
$(subst_verbose)$(SUBST_VARS) $< > $@
|
||||
|
||||
dist_xrdpsysconf_DATA = \
|
||||
xrdp.ini \
|
||||
gfx.toml \
|
||||
xrdp_keyboard.ini
|
||||
|
||||
nodist_xrdpsysconf_DATA = \
|
||||
xrdp.ini
|
||||
|
||||
xrdppkgdatadir=$(datadir)/xrdp
|
||||
|
||||
dist_xrdppkgdata_DATA = \
|
||||
@ -110,3 +125,5 @@ dist_xrdppkgdata_DATA = \
|
||||
sans-18.fv1 \
|
||||
cursor0.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(" A Remote Desktop Protocol Server.");
|
||||
g_writeln(" Copyright (C) 2004-2020 Jay Sorg, "
|
||||
"Neutrino Labs, and all contributors.");
|
||||
g_writeln(" Copyright (C) 2004-%d Jay Sorg, "
|
||||
"Neutrino Labs, and all contributors.",
|
||||
VERSION_YEAR);
|
||||
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
||||
g_writeln("%s", "");
|
||||
|
||||
|
16
xrdp/xrdp.h
16
xrdp/xrdp.h
@ -38,6 +38,14 @@
|
||||
#include "xrdp_client_info.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 */
|
||||
long
|
||||
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);
|
||||
int
|
||||
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
|
||||
xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,
|
||||
struct xrdp_bitmap *bitmap,
|
||||
@ -591,7 +602,10 @@ server_draw_text(struct xrdp_mod *mod, int font,
|
||||
int box_right, int box_bottom,
|
||||
int x, int y, char *data, int data_len);
|
||||
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
|
||||
is_channel_allowed(struct xrdp_wm *wm, int channel_id);
|
||||
int
|
||||
|
@ -35,7 +35,10 @@ tcp_nodelay=true
|
||||
; if the network connection disappear without close messages the connection will be closed
|
||||
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_recv_buffer_bytes=32768
|
||||
|
||||
@ -85,7 +88,8 @@ max_bpp=32
|
||||
new_cursors=true
|
||||
; fastpath - can be 'input', 'output', 'both', 'none'
|
||||
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
|
||||
; when true, the userid will be used to try to authenticate
|
||||
#enable_token_login=true
|
||||
@ -219,7 +223,6 @@ drdynvc=true
|
||||
cliprdr=true
|
||||
rail=true
|
||||
xrdpvr=true
|
||||
tcutils=true
|
||||
|
||||
; for debugging xrdp, in section xrdp1, change port=-1 to this:
|
||||
#port=/tmp/.xrdp/xrdp_display_10
|
||||
|
@ -301,8 +301,6 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
|
||||
return 1;
|
||||
}
|
||||
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
Bpp = 4;
|
||||
|
||||
switch (self->bpp)
|
||||
@ -318,8 +316,28 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(self->data);
|
||||
self->data = (char *)g_malloc(width * height * Bpp, 0);
|
||||
/* To prevent valgrind errors (particularly on a screen resize),
|
||||
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;
|
||||
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:");
|
||||
s = xrdp_egfx_frame_start(egfx->bulk, frame_id, timestamp);
|
||||
error = xrdp_egfx_send_s(egfx, s);
|
||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s "
|
||||
"error %d", error);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s "
|
||||
"error %d", error);
|
||||
}
|
||||
free_stream(s);
|
||||
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:");
|
||||
s = xrdp_egfx_frame_end(egfx->bulk, frame_id);
|
||||
error = xrdp_egfx_send_s(egfx, s);
|
||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s "
|
||||
"error %d", error);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s "
|
||||
"error %d", error);
|
||||
}
|
||||
free_stream(s);
|
||||
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, intframeId);
|
||||
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",
|
||||
queueDepth, intframeId, totalFramesDecoded);
|
||||
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_uint32_le(s, 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);
|
||||
if (pduLength < 8)
|
||||
{
|
||||
@ -1121,6 +1127,10 @@ xrdp_egfx_shutdown_close_connection(struct xrdp_egfx *egfx)
|
||||
return error;
|
||||
}
|
||||
|
||||
// Ignore any messages we haven't processed yet
|
||||
egfx->caps_advertise = NULL;
|
||||
egfx->frame_ack = NULL;
|
||||
|
||||
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 pixel_format,
|
||||
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 *
|
||||
xrdp_egfx_reset_graphics(struct xrdp_egfx_bulk *bulk, int width, int height,
|
||||
int monitor_count, struct monitor_info *mi);
|
||||
|
@ -28,21 +28,55 @@
|
||||
#include "thread_calls.h"
|
||||
#include "fifo.h"
|
||||
#include "xrdp_egfx.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
#ifdef XRDP_RFXCODEC
|
||||
#include "rfxcodec_encode.h"
|
||||
#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 OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024)
|
||||
|
||||
#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,
|
||||
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
|
||||
|
||||
struct enc_rect
|
||||
@ -59,11 +93,13 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
|
||||
#ifdef XRDP_RFXCODEC
|
||||
static int
|
||||
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
|
||||
#ifdef XRDP_X264
|
||||
static int
|
||||
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 */
|
||||
@ -71,8 +107,15 @@ static void
|
||||
xrdp_enc_data_destructor(void *item, void *closure)
|
||||
{
|
||||
XRDP_ENC_DATA *enc = (XRDP_ENC_DATA *)item;
|
||||
g_free(enc->u.sc.drects);
|
||||
g_free(enc->u.sc.crects);
|
||||
if (ENC_IS_BIT_SET(enc->flags, ENC_FLAGS_GFX_BIT))
|
||||
{
|
||||
g_free(enc->u.gfx.cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free(enc->u.sc.drects);
|
||||
g_free(enc->u.sc.crects);
|
||||
}
|
||||
g_free(enc);
|
||||
}
|
||||
|
||||
@ -117,53 +160,80 @@ xrdp_encoder_create(struct xrdp_mm *mm)
|
||||
return NULL;
|
||||
}
|
||||
self->mm = mm;
|
||||
|
||||
self->process_enc = process_enc_egfx;
|
||||
if (client_info->jpeg_codec_id != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session");
|
||||
self->codec_id = client_info->jpeg_codec_id;
|
||||
self->in_codec_mode = 1;
|
||||
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;
|
||||
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
|
||||
else if (mm->egfx_flags & XRDP_EGFX_RFX_PRO)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"xrdp_encoder_create: starting gfx rfx pro codec session");
|
||||
self->in_codec_mode = 1;
|
||||
client_info->capture_code = 4;
|
||||
self->process_enc = process_enc_egfx;
|
||||
client_info->capture_code = CC_GFX_PRO;
|
||||
self->gfx = 1;
|
||||
self->quants = (const char *) g_rfx_quantization_values;
|
||||
self->num_quants = 2;
|
||||
self->quant_idx_y = 0;
|
||||
self->quant_idx_u = 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)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session");
|
||||
self->codec_id = client_info->rfx_codec_id;
|
||||
self->in_codec_mode = 1;
|
||||
client_info->capture_code = 2;
|
||||
client_info->capture_code = CC_SUF_RFX;
|
||||
self->process_enc = process_enc_rfx;
|
||||
self->codec_handle_rfx = rfxcodec_encode_create(mm->wm->screen->width,
|
||||
mm->wm->screen->height,
|
||||
RFX_FORMAT_YUV, 0);
|
||||
}
|
||||
#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
|
||||
{
|
||||
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);
|
||||
self->xrdp_encoder_event_processed = g_create_wait_obj(buf);
|
||||
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)
|
||||
{
|
||||
// Magic numbers... Why?
|
||||
self->frames_in_flight = 2;
|
||||
self->max_compressed_bytes = 3145728;
|
||||
const char *env_var = g_getenv("XRDP_GFX_FRAMES_IN_FLIGHT");
|
||||
self->frames_in_flight = DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT;
|
||||
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
|
||||
{
|
||||
@ -225,8 +333,12 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
|
||||
return;
|
||||
}
|
||||
/* tell worker thread to shut down */
|
||||
g_set_wait_obj(self->xrdp_encoder_term);
|
||||
g_sleep(1000);
|
||||
g_set_wait_obj(self->xrdp_encoder_term_request);
|
||||
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
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -259,7 +371,8 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
|
||||
/* destroy wait objects used for signalling */
|
||||
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_term);
|
||||
g_delete_wait_obj(self->xrdp_encoder_term_request);
|
||||
g_delete_wait_obj(self->xrdp_encoder_term_done);
|
||||
|
||||
/* cleanup fifos */
|
||||
fifo_delete(self->fifo_to_proc, NULL);
|
||||
@ -515,6 +628,61 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
||||
}
|
||||
#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 */
|
||||
static int
|
||||
@ -524,27 +692,267 @@ process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
||||
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 *
|
||||
gfx_wiretosurface1(struct xrdp_encoder *self,
|
||||
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)bulk;
|
||||
(void)in_s;
|
||||
(void)enc_gfx_cmd;
|
||||
(void)enc;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct stream *
|
||||
gfx_wiretosurface2(struct xrdp_encoder *self,
|
||||
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 surface_id;
|
||||
int codec_id;
|
||||
@ -561,10 +969,10 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
||||
int bitmap_data_length;
|
||||
struct rfx_tile *tiles;
|
||||
struct rfx_rect *rfxrects;
|
||||
int tiles_compressed;
|
||||
int flags;
|
||||
int total_tiles;
|
||||
int tiles_written;
|
||||
int do_free;
|
||||
int do_send;
|
||||
int mon_index;
|
||||
|
||||
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, width);
|
||||
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)
|
||||
{
|
||||
self->codec_handle_prfx_gfx[mon_index] = rfxcodec_encode_create(
|
||||
@ -649,60 +1060,80 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
|
||||
RFX_FORMAT_YUV,
|
||||
RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1);
|
||||
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(rfxrects);
|
||||
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);
|
||||
g_free(rfxrects);
|
||||
rv = NULL;
|
||||
if (do_send)
|
||||
bitmap_data_length = self->max_compressed_bytes;
|
||||
bitmap_data = g_new(char, bitmap_data_length);
|
||||
if (bitmap_data == NULL)
|
||||
{
|
||||
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,
|
||||
codec_id, codec_context_id,
|
||||
pixel_format,
|
||||
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(bitmap_data);
|
||||
}
|
||||
g_free(tiles);
|
||||
g_free(rfxrects);
|
||||
g_free(bitmap_data);
|
||||
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 in_s;
|
||||
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_bytes;
|
||||
int frame_id;
|
||||
int got_frame_id;
|
||||
int error;
|
||||
char *holdp;
|
||||
char *holdend;
|
||||
|
||||
fifo_processed = self->fifo_processed;
|
||||
mutex = self->mutex;
|
||||
event_processed = self->xrdp_encoder_event_processed;
|
||||
bulk = self->mm->egfx->bulk;
|
||||
g_memset(&in_s, 0, sizeof(in_s));
|
||||
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;
|
||||
in_s.end = holdp + cmd_bytes;
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_egfx: cmd_id %d", cmd_id);
|
||||
switch (cmd_id)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
case XR_RDPGFX_CMDID_SOLIDFILL: /* 0x0004 */
|
||||
s = gfx_solidfill(self, bulk, &in_s);
|
||||
@ -973,44 +1399,32 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (s == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: cmd_id %d s = nil", cmd_id);
|
||||
return 1;
|
||||
}
|
||||
/* setup for next cmd */
|
||||
in_s.p = holdp + cmd_bytes;
|
||||
in_s.end = holdend;
|
||||
/* setup enc_done struct */
|
||||
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
|
||||
if (enc_done == NULL)
|
||||
if (s != NULL)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
/* send message to main thread */
|
||||
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);
|
||||
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)
|
||||
else
|
||||
{
|
||||
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
|
||||
enc_done->frame_id = frame_id;
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_egfx: nil");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Encoder thread main loop
|
||||
*****************************************************************************/
|
||||
@ -1045,7 +1459,7 @@ proc_enc_msg(void *arg)
|
||||
event_to_proc = self->xrdp_encoder_event_to_proc;
|
||||
|
||||
term_obj = g_get_term();
|
||||
lterm_obj = self->xrdp_encoder_term;
|
||||
lterm_obj = self->xrdp_encoder_term_request;
|
||||
|
||||
cont = 1;
|
||||
while (cont)
|
||||
@ -1096,6 +1510,7 @@ proc_enc_msg(void *arg)
|
||||
}
|
||||
|
||||
} /* end while (cont) */
|
||||
g_set_wait_obj(self->xrdp_encoder_term_done);
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "proc_enc_msg: thread exit");
|
||||
return 0;
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ struct xrdp_encoder
|
||||
int max_compressed_bytes;
|
||||
tbus xrdp_encoder_event_to_proc;
|
||||
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_processed;
|
||||
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>
|
||||
[default_layouts_map]
|
||||
rdp_layout_us=us
|
||||
rdp_layout_us_dvorak=dvorak
|
||||
rdp_layout_us_dvorak=us(dvorak)
|
||||
rdp_layout_us_dvp=us(dvp)
|
||||
rdp_layout_dk=dk
|
||||
rdp_layout_de=de
|
||||
@ -125,7 +125,7 @@ layouts_map=default_layouts_map
|
||||
|
||||
[rdp_layouts_map_mac]
|
||||
rdp_layout_us=us
|
||||
rdp_layout_us_dvorak=dvorak
|
||||
rdp_layout_us_dvorak=us(dvorak)
|
||||
rdp_layout_us_dvp=us(dvp)
|
||||
rdp_layout_dk=dk
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error getting send "
|
||||
"buffer");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "send buffer set to %d "
|
||||
"bytes", bytes);
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "send buffer set to %d bytes", bytes);
|
||||
}
|
||||
}
|
||||
if (startup_params->tcp_recv_buffer_bytes > 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "error getting recv "
|
||||
"buffer");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "recv buffer set to %d "
|
||||
"bytes", bytes);
|
||||
}
|
||||
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_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, "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, "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_add_char = server_add_char;
|
||||
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_query_channel = server_query_channel;
|
||||
self->mod->server_get_channel_id = server_get_channel_id;
|
||||
@ -1094,25 +1095,32 @@ cleanup:
|
||||
|
||||
/******************************************************************************/
|
||||
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;
|
||||
struct xrdp_bitmap *screen;
|
||||
int error;
|
||||
int error = 0;
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:");
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_wm_screen:");
|
||||
|
||||
screen = self->wm->screen;
|
||||
|
||||
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)
|
||||
// Only invalidate the WM screen if the module is using the WM screen,
|
||||
// or we haven't loaded the module yet.
|
||||
//
|
||||
// Otherwise we may send client updates which conflict with the
|
||||
// updates sent directly from the module via the encoder.
|
||||
if (self->mod_uses_wm_screen_for_gfx || self->mod_handle == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1262,7 +1270,6 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
||||
struct xrdp_mm *self;
|
||||
struct xrdp_bitmap *screen;
|
||||
int index;
|
||||
int best_index;
|
||||
int best_h264_index;
|
||||
int best_pro_index;
|
||||
int error;
|
||||
@ -1270,6 +1277,10 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
||||
int 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:");
|
||||
self = (struct xrdp_mm *) user;
|
||||
screen = self->wm->screen;
|
||||
@ -1290,7 +1301,6 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
||||
}
|
||||
/* sort by version */
|
||||
g_qsort(ver_flags, caps_count, sizeof(struct ver_flags_t), cmpverfunc);
|
||||
best_index = -1;
|
||||
best_h264_index = -1;
|
||||
best_pro_index = -1;
|
||||
for (index = 0; index < caps_count; index++)
|
||||
@ -1337,19 +1347,34 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
|
||||
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;
|
||||
self->egfx_flags = XRDP_EGFX_RFX_PRO;
|
||||
}
|
||||
/* prefer h264, todo use setting in xrdp.ini for this */
|
||||
if (best_h264_index >= 0)
|
||||
{
|
||||
#if defined(XRDP_X264) || defined(XRDP_NVENC)
|
||||
best_index = best_h264_index;
|
||||
self->egfx_flags = XRDP_EGFX_H264;
|
||||
#if defined(XRDP_H264)
|
||||
if (co->codecs[index] == XTC_H264 && best_h264_index >= 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Matched H264 mode");
|
||||
best_index = best_h264_index;
|
||||
self->egfx_flags = XRDP_EGFX_H264;
|
||||
break;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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,
|
||||
screen->width, screen->height,
|
||||
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 "
|
||||
"error %d monitorCount %d",
|
||||
error, self->wm->client_info->display_sizes.monitorCount);
|
||||
self->egfx_up = 1;
|
||||
xrdp_mm_egfx_create_surfaces(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
|
||||
&& 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_sec *sec;
|
||||
struct xrdp_channel *chan;
|
||||
int in_progress;
|
||||
|
||||
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)
|
||||
{
|
||||
xrdp_egfx_shutdown_close_connection(wm->mm->egfx);
|
||||
mm->egfx_up = 0;
|
||||
}
|
||||
advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSING);
|
||||
break;
|
||||
@ -1725,13 +1752,15 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
|
||||
{
|
||||
xrdp_egfx_shutdown_delete(wm->mm->egfx);
|
||||
mm->egfx = NULL;
|
||||
mm->egfx_up = 0;
|
||||
}
|
||||
advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE);
|
||||
break;
|
||||
case WMRZ_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)
|
||||
{
|
||||
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);
|
||||
return advance_error(error, mm);
|
||||
}
|
||||
advance_resize_state_machine(
|
||||
mm, WMRZ_SERVER_VERSION_MESSAGE_START);
|
||||
break;
|
||||
case WMRZ_SERVER_VERSION_MESSAGE_START:
|
||||
error = module->mod_server_version_message(module);
|
||||
if (error != 0)
|
||||
else if (in_progress)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_INFO,
|
||||
"process_display_control_monitor_layout_data:"
|
||||
" mod_server_version_message failed %d", error);
|
||||
return advance_error(error, mm);
|
||||
// Call is proceeding asynchronously
|
||||
advance_resize_state_machine(
|
||||
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING);
|
||||
}
|
||||
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;
|
||||
// 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_PROCESSED:
|
||||
advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESET);
|
||||
break;
|
||||
case WMRZ_XRDP_CORE_RESET:
|
||||
// TODO: Unify this logic with server_reset
|
||||
error = libxrdp_reset(
|
||||
wm->session, desc_width, desc_height, wm->screen->bpp);
|
||||
sync_dynamic_monitor_data(wm, &(description->description));
|
||||
error = libxrdp_reset(wm->session);
|
||||
if (error != 0)
|
||||
{
|
||||
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);
|
||||
return advance_error(error, mm);
|
||||
}
|
||||
sync_dynamic_monitor_data(wm, &(description->description));
|
||||
advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE);
|
||||
break;
|
||||
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.
|
||||
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);
|
||||
xrdp_rdp_suppress_output(rdp,
|
||||
0, XSO_REASON_DYNAMIC_RESIZE,
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
@ -2686,6 +2704,14 @@ xrdp_mm_process_login_response(struct xrdp_mm *self)
|
||||
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 (login_result == E_SCP_LOGIN_NOT_AUTHENTICATED)
|
||||
@ -3476,7 +3502,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
|
||||
y = enc_done->y;
|
||||
cx = enc_done->cx;
|
||||
cy = enc_done->cy;
|
||||
if (!enc_done->continuation)
|
||||
if (client_ack && !enc_done->continuation)
|
||||
{
|
||||
libxrdp_fastpath_send_frame_marker(self->wm->session, 0,
|
||||
enc_done->frame_id);
|
||||
@ -3488,7 +3514,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
|
||||
x, y, x + cx, y + cy,
|
||||
32, self->encoder->codec_id,
|
||||
cx, cy);
|
||||
if (enc_done->last)
|
||||
if (client_ack && enc_done->last)
|
||||
{
|
||||
libxrdp_fastpath_send_frame_marker(self->wm->session, 1,
|
||||
enc_done->frame_id);
|
||||
@ -3534,6 +3560,39 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
|
||||
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
|
||||
xrdp_mm_draw_dirty(struct xrdp_mm *self)
|
||||
@ -4116,11 +4175,13 @@ server_egfx_cmd(struct xrdp_mod *mod,
|
||||
mm = wm->mm;
|
||||
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)
|
||||
{
|
||||
g_munmap(data, data_bytes);
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
enc = g_new0(struct xrdp_enc_data, 1);
|
||||
if (enc == NULL)
|
||||
@ -4432,17 +4493,70 @@ server_draw_text(struct xrdp_mod *mod, int font,
|
||||
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
|
||||
* to a single monitor */
|
||||
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_mm *mm;
|
||||
|
||||
LOG(LOG_LEVEL_TRACE, "server_reset:");
|
||||
LOG(LOG_LEVEL_TRACE, "server_monitor_resize_done:");
|
||||
|
||||
wm = (struct xrdp_wm *)(mod->wm);
|
||||
if (wm == 0)
|
||||
@ -4450,78 +4564,25 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
|
||||
return 1;
|
||||
}
|
||||
mm = wm->mm;
|
||||
if (mm == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (wm->client_info == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* older client can't resize */
|
||||
if (wm->client_info->build <= 419)
|
||||
if (mm->resize_data != NULL
|
||||
&& 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;
|
||||
}
|
||||
|
||||
|
@ -95,18 +95,8 @@ xrdp_painter_send_dirty(struct xrdp_painter *self)
|
||||
|
||||
if (self->session->client_info->gfx)
|
||||
{
|
||||
if (self->wm->screen_dirty_region == NULL)
|
||||
{
|
||||
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);
|
||||
}
|
||||
xrdp_mm_efgx_add_dirty_region_to_planar_list(self->wm->mm,
|
||||
self->dirty_region);
|
||||
}
|
||||
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 "guid.h"
|
||||
#include "xrdp_client_info.h"
|
||||
#include "xrdp_tconfig.h"
|
||||
|
||||
#define MAX_NR_CHANNELS 16
|
||||
#define MAX_CHANNEL_NAME 16
|
||||
@ -64,7 +65,10 @@ struct xrdp_mod
|
||||
int (*mod_suppress_output)(struct xrdp_mod *v, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
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 width, int height);
|
||||
int (*mod_server_version_message)(struct xrdp_mod *v);
|
||||
@ -106,7 +110,10 @@ struct xrdp_mod
|
||||
int box_left, int box_top,
|
||||
int box_right, int box_bottom,
|
||||
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_query_channel)(struct xrdp_mod *v, int index,
|
||||
char *channel_name,
|
||||
@ -185,7 +192,7 @@ struct xrdp_mod
|
||||
int (*server_egfx_cmd)(struct xrdp_mod *v,
|
||||
char *cmd, int cmd_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 */
|
||||
/* common */
|
||||
tintptr handle; /* pointer to self as int */
|
||||
@ -347,7 +354,6 @@ enum display_resize_state
|
||||
WMRZ_EGFX_CONN_CLOSED,
|
||||
WRMZ_EGFX_DELETE,
|
||||
WMRZ_SERVER_MONITOR_RESIZE,
|
||||
WMRZ_SERVER_VERSION_MESSAGE_START,
|
||||
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING,
|
||||
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED,
|
||||
WMRZ_XRDP_CORE_RESET,
|
||||
@ -370,8 +376,6 @@ enum display_resize_state
|
||||
(status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \
|
||||
(status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \
|
||||
(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 ? \
|
||||
"WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \
|
||||
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \
|
||||
@ -436,6 +440,7 @@ struct xrdp_mm
|
||||
int egfx_up;
|
||||
enum xrdp_egfx_flags egfx_flags;
|
||||
int gfx_delay_autologin;
|
||||
int mod_uses_wm_screen_for_gfx;
|
||||
/* Resize on-the-fly control */
|
||||
struct display_control_monitor_layout_data *resize_data;
|
||||
struct list *resize_queue;
|
||||
@ -562,6 +567,8 @@ struct xrdp_wm
|
||||
|
||||
/* configuration derived from xrdp.ini */
|
||||
struct xrdp_config *xrdp_config;
|
||||
/* configuration derived from gfx.toml */
|
||||
struct xrdp_tconfig_gfx *gfx_config;
|
||||
|
||||
struct xrdp_region *screen_dirty_region;
|
||||
int last_screen_draw_time;
|
||||
|
131
xrdp/xrdp_wm.c
131
xrdp/xrdp_wm.c
@ -29,6 +29,54 @@
|
||||
#include "log.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 *
|
||||
xrdp_wm_create(struct xrdp_process *owner,
|
||||
@ -66,8 +114,26 @@ xrdp_wm_create(struct xrdp_process *owner,
|
||||
self->target_surface = self->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->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;
|
||||
}
|
||||
@ -97,6 +163,11 @@ xrdp_wm_delete(struct xrdp_wm *self)
|
||||
g_free(self->xrdp_config);
|
||||
}
|
||||
|
||||
if (self->gfx_config)
|
||||
{
|
||||
g_free(self->gfx_config);
|
||||
}
|
||||
|
||||
/* free self */
|
||||
g_free(self);
|
||||
}
|
||||
@ -564,9 +635,7 @@ xrdp_wm_init(struct xrdp_wm *self)
|
||||
{
|
||||
int fd;
|
||||
int index;
|
||||
struct list *names;
|
||||
struct list *values;
|
||||
char *q;
|
||||
const char *q;
|
||||
const char *r;
|
||||
char param[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,
|
||||
self->screen->bpp);
|
||||
|
||||
tconfig_load_gfx(XRDP_CFG_PATH "/gfx.toml", self->gfx_config);
|
||||
|
||||
/* Remove a font loaded on the previous config */
|
||||
xrdp_font_delete(self->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 */
|
||||
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_pointers(self);
|
||||
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);
|
||||
if (fd != -1)
|
||||
{
|
||||
names = list_create();
|
||||
struct list *names = list_create();
|
||||
names->auto_free = 1;
|
||||
values = list_create();
|
||||
struct list *values = list_create();
|
||||
values->auto_free = 1;
|
||||
|
||||
/* 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';
|
||||
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) &&
|
||||
(g_strncasecmp("Logging", q, 8) != 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++)
|
||||
{
|
||||
q = (char *)list_get_item(names, index);
|
||||
r = (char *)list_get_item(values, index);
|
||||
q = (const char *)list_get_item(names, index);
|
||||
r = (const char *)list_get_item(values, index);
|
||||
|
||||
if (g_strncasecmp("password", q, 255) == 0)
|
||||
{
|
||||
|
56
xup/xup.c
56
xup/xup.c
@ -28,8 +28,10 @@
|
||||
#include "string_calls.h"
|
||||
|
||||
static int
|
||||
send_server_monitor_resize(
|
||||
struct mod *mod, struct stream *s, int width, int height, int bpp);
|
||||
send_server_monitor_update(struct mod *v, struct stream *s,
|
||||
int width, int height,
|
||||
int num_monitors,
|
||||
const struct monitor_info *monitors);
|
||||
|
||||
static int
|
||||
send_server_monitor_full_invalidate(
|
||||
@ -224,13 +226,6 @@ lib_mod_connect(struct mod *mod)
|
||||
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)
|
||||
{
|
||||
error = send_server_monitor_full_invalidate(
|
||||
@ -1466,33 +1461,30 @@ send_server_version_message(struct mod *mod, struct stream *s)
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
static int
|
||||
send_server_monitor_resize(
|
||||
struct mod *mod, struct stream *s, int width, int height, int bpp)
|
||||
send_server_monitor_update(struct mod *mod, struct stream *s,
|
||||
int width, int height,
|
||||
int num_monitors,
|
||||
const struct monitor_info *monitors)
|
||||
{
|
||||
/* send screen size message */
|
||||
/* send monitor update message */
|
||||
init_stream(s, 8192);
|
||||
s_push_layer(s, iso_hdr, 4);
|
||||
out_uint16_le(s, 103);
|
||||
out_uint32_le(s, 300);
|
||||
out_uint32_le(s, 302);
|
||||
out_uint32_le(s, width);
|
||||
out_uint32_le(s, height);
|
||||
/*
|
||||
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, num_monitors);
|
||||
out_uint32_le(s, 0);
|
||||
out_uint8a(s, monitors, sizeof(monitors[0]) * num_monitors);
|
||||
s_mark_end(s);
|
||||
int len = (int)(s->end - s->data);
|
||||
s_pop_layer(s, iso_hdr);
|
||||
out_uint32_le(s, len);
|
||||
int rv = lib_send_copy(mod, s);
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize:"
|
||||
" sent resize message with following properties to"
|
||||
" xorgxrdp backend width=%d, height=%d, bpp=%d, return value=%d",
|
||||
width, height, bpp, rv);
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_update:"
|
||||
" sent monitor updsate message with following properties to"
|
||||
" xorgxrdp backend width=%d, height=%d, num=%d, return value=%d",
|
||||
width, height, num_monitors, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1542,12 +1534,16 @@ lib_send_server_version_message(struct mod *mod)
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
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;
|
||||
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);
|
||||
return rv;
|
||||
}
|
||||
@ -1802,7 +1798,7 @@ lib_mod_process_message(struct mod *mod, struct stream *s)
|
||||
LOG(LOG_LEVEL_INFO, "Received memory_allocation_complete"
|
||||
" command. width: %d, height: %d",
|
||||
width, height);
|
||||
rv = mod->server_reset(mod, width, height, 0);
|
||||
rv = mod->server_monitor_resize_done(mod);
|
||||
break;
|
||||
}
|
||||
s->p = phold + len;
|
||||
@ -1897,6 +1893,10 @@ lib_mod_check_wait_objs(struct mod *mod)
|
||||
if (mod->trans != 0)
|
||||
{
|
||||
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 left, int top, int right, int bottom);
|
||||
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 width, int height);
|
||||
int (*mod_server_version_message)(struct mod *v);
|
||||
@ -94,7 +97,10 @@ struct mod
|
||||
int box_left, int box_top,
|
||||
int box_right, int box_bottom,
|
||||
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_query_channel)(struct mod *v, int index,
|
||||
char *channel_name,
|
||||
@ -170,7 +176,7 @@ struct mod
|
||||
int (*server_egfx_cmd)(struct mod *v,
|
||||
char *cmd, int cmd_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 */
|
||||
/* common */
|
||||
tintptr handle; /* pointer to self as long */
|
||||
|
Loading…
Reference in New Issue
Block a user